LAL  7.5.0.1-ec27e42
Eigen.c
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2007 Teviet Creighton
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with with program; see the file COPYING. If not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301 USA
18 */
19 
20 
21 #include <math.h>
22 #include <lal/LALConstants.h>
23 #include <lal/LALStdlib.h>
24 #include <lal/AVFactories.h>
25 #include <lal/MatrixUtils.h>
26 
27 #define EIGENINTERNALC_MAXITER 30 /* max. number of iterations in
28  diagonalizing */
29 
30 /* A quick macro to take the square root of the sum of squares,
31  without overflowing or underflowing. */
32 #define RSS( a, b ) ( fabs( a ) > fabs( b ) ? \
33 fabs( a )*sqrt( 1.0 + ((b)/(a))*((b)/(a)) ) : \
34 ( (b) == 0.0 ? 0.0 : fabs( b )*sqrt( 1.0 + ((a)/(b))*((a)/(b)) ) ) )
35 
36 
37 /*
38  * \defgroup EigenInternal_c Module EigenInternal.c
39  * \ingroup MatrixUtils_h
40  * \author Creighton, T. D.
41  *
42  * \brief Internal routines used to compute eigenvalues and eigenvectors.
43  *
44  * ### Description ###
45  *
46  * These functions are called by the routines in \ref Eigen_c to
47  * compute eigenvalues and eigenvectors of a symmetric square matrix
48  * <tt>*matrix</tt>. They are provided because, in some circumstances,
49  * users may find it useful to work with the partially-reduced results.
50  *
51  * <tt>LALSSymmetricToTriDiagonal()</tt> and
52  * <tt>LALDSymmetricToTriDiagonal()</tt> reduce the symmetric square matrix
53  * <tt>*matrix</tt> to tridiagonal form. The vectors <tt>*diag</tt> and
54  * <tt>*offDiag</tt> must be allocated to the same length as each matrix
55  * dimension; on return, <tt>*diag</tt> stores the diagonal elements and
56  * <tt>*offDiag</tt> the off-diagonal elements (<tt>offDiag->data[0]</tt> is
57  * meaningless and will be set to zero). The tri-diagonalization is done
58  * in-place, so that on return <tt>*matrix</tt> will store the
59  * transformation matrix that brings the original input matrix into
60  * tridiagonal form. If you don't want the input matrix to be changed,
61  * make a copy of it first.
62  *
63  * <tt>LALSTriDiagonalToDiagonal()</tt> and
64  * <tt>LALDTriDiagonalToDiagonal()</tt> take a symmetric tridiagonal matrix
65  * and compute its eigenvalues and eigenvectors. On input, <tt>*diag</tt>
66  * stores the diagonal elements of the matrix, and <tt>*offDiag</tt> the
67  * off-diagonal elements, with <tt>offDiag->data[0]</tt> arbitrary; on
68  * return, <tt>*diag</tt> will store the eigenvalues and <tt>*offDiag</tt>
69  * will store zeroes. The matrix <tt>*matrix</tt> should store the
70  * orthogonal transformation matrix that brought the original symmetric
71  * matrix into tri-diagonal form (as returned by the above routines), or
72  * the identity matrix if the tri-diagonal matrix \e is the original
73  * matrix of interest; on return, <tt>*matrix</tt> will store the
74  * orthogonal transformation matrix that diagonalizes the original
75  * matrix: its columns are the eigenvectors of the original matrix.
76  *
77  * ### Algorithm ###
78  *
79  * The tri-diagonalizing routines follow the Householder reduction method
80  * described in Sec. 11.2 of \cite ptvf1992; they are essentially
81  * re-implementations of the Numerical Recipes routine <tt>tred2()</tt>.
82  * For large \f$N\f$, their operation count is approximately \f$4N^3/3\f$, or
83  * \f$2N^3/3\f$ for the routines that ignore eigenvectors. These routines
84  * explicitly enforce symmetry, by only using the lower-left triangle of
85  * the matrix as input.
86  *
87  * The diagonalizing routines follow the QL algorithm with implicit
88  * shifts described in Sec. 11.3 of \cite ptvf1992; they are
89  * essentially re-implementations of the Numerical Recipes routine
90  * <tt>tqli()</tt>. Depending on the number of iterations required, their
91  * operation count is roughly \f$\sim30N^2\f$, plus \f$\sim3N^3\f$ if
92  * eigenvectors are also being computed.
93  *
94  * The diagonalizing routines can fail if they fail to converge rapidly
95  * enough. The discussion in \cite ptvf1992 does not go into much
96  * detail about when this is likely to occur, except to note that
97  * degenerate eigenvalues converge more slowly. If the routines fail in
98  * this way, \c diag, \c matrix, and \c offDiag will all be
99  * left in indeterminate states.
100  *
101  */
102 
103 static void
105  REAL4Vector *diag,
106  REAL4Array *matrix,
107  REAL4Vector *offDiag )
108 {
109  UINT4 n, in; /* matrix dimension (times i) */
110  UINT4 i, k, l; /* dimension indecies */
111  UINT4 ij, ik, ki, il, li, kl, lk, ii; /* matrix array indecies */
112  REAL4 *m, *d, *o; /* pointers to data arrays */
113  REAL4 H, K; /* scalars defined in Eqs. (11.2.4) and (11.2.11) of NR */
114  REAL4 x, y, scale; /* temporary variables */
115 
116  INITSTATUS(stat);
117 
118  /* Check input fields. */
121  ASSERT( offDiag, stat, MATRIXUTILSH_ENUL, MATRIXUTILSH_MSGENUL );
126  ASSERT( matrix->dimLength->data, stat, MATRIXUTILSH_ENUL,
128  ASSERT( matrix->dimLength->length == 2, stat, MATRIXUTILSH_EDIM,
130  n = diag->length;
132  ASSERT( n == offDiag->length, stat, MATRIXUTILSH_EDIM,
134  ASSERT( n == matrix->dimLength->data[0], stat, MATRIXUTILSH_EDIM,
136  ASSERT( n == matrix->dimLength->data[1], stat, MATRIXUTILSH_EDIM,
138 
139  /* Set up pointers. */
140  m = matrix->data;
141  d = diag->data;
142  o = offDiag->data;
143 
144  /* Start tri-diagonalizing from the bottom-right corner i = n-1. */
145  for ( i = n - 1; i; i-- ) {
146  /* j = i - 1; */
147  in = i*n;
148  ij = in + i - 1;
149  H = scale = 0.0;
150  if ( i > 1 ) {
151 
152  /* Compute typical magnitude of off-tri-diagonal components, and
153  skip transformation if they are zero. */
154  for ( k = 0, ik = in; k < i; k++, ik++ )
155  scale += fabs( m[ik] );
156  if ( scale == 0.0 )
157  o[i] = m[ij];
158 
159  /* Otherwise, apply transformation to row i. */
160  else {
161 
162  /* Renormalize off-tri-diagonal components and compute H. */
163  for ( k = 0, ik = in; k < i; k++, ik++ ) {
164  m[ik] /= scale;
165  H += m[ik]*m[ik];
166  }
167  x = m[ij];
168  y = ( x >= 0 ? -sqrt( H ) : sqrt( H ) );
169  o[i] = scale*y;
170  H -= x*y;
171 
172  /* Now compute K. To start, store u in ith row of matrix. */
173  m[ij] = x - y;
174  x = 0.0;
175  for ( k = 0, ik = in, ki = i; k < i; k++, ik++, ki += n ) {
176  /* Store u/H in ith column of matrix. */
177  m[ki] = m[ik] / H;
178  /* Compute component of matrix * u, stored in y. */
179  y = 0.0;
180  for ( l = 0, kl = k*n, il = in; l <= k; l++, kl++, il++ )
181  y += m[kl]*m[il];
182  for ( l = k + 1, lk = k*( n + 1 ) + n, il = in + k + 1;
183  l < i; l++, lk += n, il++ )
184  y += m[lk]*m[il];
185  /* Compute p, stored in unfilled part of o. */
186  o[k] = y/H;
187  x += o[k]*m[ik];
188  }
189  K = 0.5*x/H;
190 
191  /* Now reduce submatrix to tri-diagonal form. Start by
192  forming vector q and storing in o, overwriting p. */
193  for ( k = 0, ik = in; k < i; k++, ik++ ) {
194  x = m[ik];
195  o[k] = y = o[k] - K*x;
196  /* Now apply submatrix reduction. */
197  for ( l = 0, kl = n*k, il = in; l <= k; l++, kl++, il++ )
198  m[kl] -= x*o[l] + y*m[il];
199  }
200  }
201  }
202 
203  /* Last (top-right) 1x1 submatrix is trivial. */
204  else
205  o[i] = m[ij];
206 
207  /* Indicate whether this iteration was trivial or not. */
208  d[i] = H;
209  }
210 
211  /* Now compute transformation matrix (eigenvectors). */
212  d[0] = 0.0;
213  o[0] = 0.0;
214  /* Loop over the n sub-tranformations. */
215  for ( i = 0; i < n; i++ ) {
216  in = i*n;
217  ii = in + i;
218  /* Skip first block and any other trivial transformations. */
219  if ( d[i] ) {
220  for ( k = 0; k < i; k++ ) {
221  y = 0.0;
222  /* Use u and u/H, stored in ith row and column of matrix, to
223  compute P*Q. */
224  for ( l = 0, il = in, lk = k; l < i; l++, il++, lk += n )
225  y += m[il]*m[lk];
226  for ( l = 0, li = i, lk = k; l < i; l++, li += n, lk += n )
227  m[lk] -= y*m[li];
228  }
229  }
230 
231  /* Store diagonal element. */
232  d[i] = m[ii];
233 
234  /* Reset row and column to identity for next iteration. */
235  m[ii] = 1.0;
236  for ( k = 0, ik = in, ki = i; k < i; k++, ik++, ki += n )
237  m[ki] = m[ik] = 0.0;
238  }
239 
240  /* Finished. */
241  RETURN( stat );
242 }
243 
244 
245 static void
247  REAL4Vector *diag,
248  REAL4Array *matrix,
249  REAL4Vector *offDiag )
250 {
251  INT4 n, i, j, k, l; /* matrix dimension and indecies */
252  INT4 lk; /* matrix array index */
253  UINT4 iteration; /* number of iterated transforms */
254  REAL4 *m, *d, *o; /* pointers to data arrays */
255  REAL4 x, y, xx, yy, s, c, r, d2; /* temporary variables */
256 
257  INITSTATUS(stat);
258 
259  /* Check input fields. */
262  ASSERT( offDiag, stat, MATRIXUTILSH_ENUL, MATRIXUTILSH_MSGENUL );
267  ASSERT( matrix->dimLength->data, stat, MATRIXUTILSH_ENUL,
269  ASSERT( matrix->dimLength->length == 2, stat, MATRIXUTILSH_EDIM,
271  n = (INT4)( diag->length );
273  ASSERT( n == (INT4)( offDiag->length ), stat, MATRIXUTILSH_EDIM,
275  ASSERT( n == (INT4)( matrix->dimLength->data[0] ), stat,
277  ASSERT( n == (INT4)( matrix->dimLength->data[1] ), stat,
279 
280  /* Set up pointers. */
281  m = matrix->data;
282  d = diag->data;
283  o = offDiag->data;
284 
285  /* As in Numerical Recipes, we start by shifting the indexing of the
286  off-diagonal vector. */
287  for ( i = 1; i < n; i++ )
288  o[i-1] = o[i];
289  o[n-1] = 0.0;
290 
291  /* Loop over the i eigenvalues. */
292  for ( i = 0; i < n; i++ ) {
293 
294  /* For each eigenvalue, loop until we've diagonalized that part of
295  the matrix. */
296  iteration = 0;
297  do {
298 
299  /* Look for a small (effectively zero) off-diagonal element. */
300  for ( j = i; j < n - 1; j++ ) {
301  d2 = fabs( d[j] ) + fabs( d[j+1] );
302  if ( fabs( o[j]/d2 ) < LAL_REAL4_EPS )
303  break;
304  }
305 
306  if ( j != i ) {
307  if ( iteration++ == EIGENINTERNALC_MAXITER ) {
309  }
310  x = 0.5*( d[i+1] - d[i] )/o[i];
311  r = RSS( x, 1.0 );
312  if ( x > 0 )
313  x = d[j] - d[i] + o[i]/( x + r );
314  else
315  x = d[j] - d[i] + o[i]/( x - r );
316  s = c = 1.0;
317  yy = 0.0;
318 
319  /* Perform a plane rotation to diagonalize the submatrix, and
320  Givens rotations to restore it to tridiagonal form. */
321  for ( k = j - 1; k >= i; k-- ) {
322  xx = c*o[k];
323  y = s*o[k];
324  o[k+1] = ( r = RSS( x, y ) );
325 
326  /* Check for underflow. */
327  if ( r <= LAL_REAL4_MIN ) {
328  d[k+1] -= yy;
329  o[j] = 0.0;
330  break;
331  }
332 
333  /* Compute diagonal element. */
334  s = y/r;
335  c = x/r;
336  x = d[k+1] - yy;
337  r = ( d[k] - x )*s + 2.0*c*xx;
338  d[k+1] = x + ( yy = s*r );
339  x = c*r - xx;
340 
341  /* Accumulate transformation matrix. */
342  for ( l = 0, lk = k; l < n; l++, lk += n ) {
343  y = m[lk+1];
344  m[lk+1] = s*m[lk] + c*y;
345  m[lk] = c*m[lk] - s*y;
346  }
347  }
348 
349  /* Check for underflow. */
350  if ( r <= LAL_REAL4_MIN && k >= i )
351  continue;
352 
353  /* Adjust diagonal and off-diagonal elements, and continue
354  loop. */
355  d[i] -= yy;
356  o[i] = x;
357  o[j] = 0.0;
358  }
359  } while ( j != i );
360  }
361 
362  /* Done. */
363  RETURN( stat );
364 }
365 
366 
367 static void
369  REAL8Vector *diag,
370  REAL8Array *matrix,
371  REAL8Vector *offDiag )
372 {
373  UINT4 n, in; /* matrix dimension (times i) */
374  UINT4 i, k, l; /* dimension indecies */
375  UINT4 ij, ik, ki, il, li, kl, lk, ii; /* matrix array indecies */
376  REAL8 *m, *d, *o; /* pointers to data arrays */
377  REAL8 H, K; /* scalars defined in Eqs. (11.2.4) and (11.2.11) of NR */
378  REAL8 x, y, scale; /* temporary variables */
379 
380  INITSTATUS(stat);
381 
382  /* Check input fields. */
385  ASSERT( offDiag, stat, MATRIXUTILSH_ENUL, MATRIXUTILSH_MSGENUL );
390  ASSERT( matrix->dimLength->data, stat, MATRIXUTILSH_ENUL,
392  ASSERT( matrix->dimLength->length == 2, stat, MATRIXUTILSH_EDIM,
394  n = diag->length;
396  ASSERT( n == offDiag->length, stat, MATRIXUTILSH_EDIM,
398  ASSERT( n == matrix->dimLength->data[0], stat, MATRIXUTILSH_EDIM,
400  ASSERT( n == matrix->dimLength->data[1], stat, MATRIXUTILSH_EDIM,
402 
403  /* Set up pointers. */
404  m = matrix->data;
405  d = diag->data;
406  o = offDiag->data;
407 
408  /* Start tri-diagonalizing from the bottom-right corner i = n-1. */
409  for ( i = n - 1; i; i-- ) {
410  /* j = i - 1; */
411  in = i*n;
412  ij = in + i - 1;
413  H = scale = 0.0;
414  if ( i > 1 ) {
415 
416  /* Compute typical magnitude of off-tri-diagonal components, and
417  skip transformation if they are zero. */
418  for ( k = 0, ik = in; k < i; k++, ik++ )
419  scale += fabs( m[ik] );
420  if ( scale == 0.0 )
421  o[i] = m[ij];
422 
423  /* Otherwise, apply transformation to row i. */
424  else {
425 
426  /* Renormalize off-tri-diagonal components and compute H. */
427  for ( k = 0, ik = in; k < i; k++, ik++ ) {
428  m[ik] /= scale;
429  H += m[ik]*m[ik];
430  }
431  x = m[ij];
432  y = ( x >= 0 ? -sqrt( H ) : sqrt( H ) );
433  o[i] = scale*y;
434  H -= x*y;
435 
436  /* Now compute K. To start, store u in ith row of matrix. */
437  m[ij] = x - y;
438  x = 0.0;
439  for ( k = 0, ik = in, ki = i; k < i; k++, ik++, ki += n ) {
440  /* Store u/H in ith column of matrix. */
441  m[ki] = m[ik] / H;
442  /* Compute component of matrix * u, stored in y. */
443  y = 0.0;
444  for ( l = 0, kl = k*n, il = in; l <= k; l++, kl++, il++ )
445  y += m[kl]*m[il];
446  for ( l = k + 1, lk = k*( n + 1 ) + n, il = in + k + 1;
447  l < i; l++, lk += n, il++ )
448  y += m[lk]*m[il];
449  /* Compute p, stored in unfilled part of o. */
450  o[k] = y/H;
451  x += o[k]*m[ik];
452  }
453  K = 0.5*x/H;
454 
455  /* Now reduce submatrix to tri-diagonal form. Start by
456  forming vector q and storing in o, overwriting p. */
457  for ( k = 0, ik = in; k < i; k++, ik++ ) {
458  x = m[ik];
459  o[k] = y = o[k] - K*x;
460  /* Now apply submatrix reduction. */
461  for ( l = 0, kl = n*k, il = in; l <= k; l++, kl++, il++ )
462  m[kl] -= x*o[l] + y*m[il];
463  }
464  }
465  }
466 
467  /* Last (top-right) 1x1 submatrix is trivial. */
468  else
469  o[i] = m[ij];
470 
471  /* Indicate whether this iteration was trivial or not. */
472  d[i] = H;
473  }
474 
475  /* Now compute transformation matrix (eigenvectors). */
476  d[0] = 0.0;
477  o[0] = 0.0;
478  /* Loop over the n sub-tranformations. */
479  for ( i = 0; i < n; i++ ) {
480  in = i*n;
481  ii = in + i;
482  /* Skip first block and any other trivial transformations. */
483  if ( d[i] ) {
484  for ( k = 0; k < i; k++ ) {
485  y = 0.0;
486  /* Use u and u/H, stored in ith row and column of matrix, to
487  compute P*Q. */
488  for ( l = 0, il = in, lk = k; l < i; l++, il++, lk += n )
489  y += m[il]*m[lk];
490  for ( l = 0, li = i, lk = k; l < i; l++, li += n, lk += n )
491  m[lk] -= y*m[li];
492  }
493  }
494 
495  /* Store diagonal element. */
496  d[i] = m[ii];
497 
498  /* Reset row and column to identity for next iteration. */
499  m[ii] = 1.0;
500  for ( k = 0, ik = in, ki = i; k < i; k++, ik++, ki += n )
501  m[ki] = m[ik] = 0.0;
502  }
503 
504  /* Finished. */
505  RETURN( stat );
506 }
507 
508 
509 static void
511  REAL8Vector *diag,
512  REAL8Array *matrix,
513  REAL8Vector *offDiag )
514 {
515  INT4 n, i, j, k, l; /* matrix dimension and indecies */
516  INT4 lk; /* matrix array index */
517  UINT4 iteration; /* number of iterated transforms */
518  REAL8 *m, *d, *o; /* pointers to data arrays */
519  REAL8 x, y, xx, yy, s, c, r, d2; /* temporary variables */
520 
521  INITSTATUS(stat);
522 
523  /* Check input fields. */
526  ASSERT( offDiag, stat, MATRIXUTILSH_ENUL, MATRIXUTILSH_MSGENUL );
531  ASSERT( matrix->dimLength->data, stat, MATRIXUTILSH_ENUL,
533  ASSERT( matrix->dimLength->length == 2, stat, MATRIXUTILSH_EDIM,
535  n = (INT4)( diag->length );
537  ASSERT( n == (INT4)( offDiag->length ), stat, MATRIXUTILSH_EDIM,
539  ASSERT( n == (INT4)( matrix->dimLength->data[0] ), stat,
541  ASSERT( n == (INT4)( matrix->dimLength->data[1] ), stat,
543 
544  /* Set up pointers. */
545  m = matrix->data;
546  d = diag->data;
547  o = offDiag->data;
548 
549  /* As in Numerical Recipes, we start by shifting the indexing of the
550  off-diagonal vector. */
551  for ( i = 1; i < n; i++ )
552  o[i-1] = o[i];
553  o[n-1] = 0.0;
554 
555  /* Loop over the i eigenvalues. */
556  for ( i = 0; i < n; i++ ) {
557 
558  /* For each eigenvalue, loop until we've diagonalized that part of
559  the matrix. */
560  iteration = 0;
561  do {
562 
563  /* Look for a small (effectively zero) off-diagonal element. */
564  for ( j = i; j < n - 1; j++ ) {
565  d2 = fabs( d[j] ) + fabs( d[j+1] );
566  if ( fabs( o[j]/d2 ) < LAL_REAL8_EPS )
567  break;
568  }
569 
570  if ( j != i ) {
571  if ( iteration++ == EIGENINTERNALC_MAXITER ) {
573  }
574  x = 0.5*( d[i+1] - d[i] )/o[i];
575  r = RSS( x, 1.0 );
576  if ( x > 0 )
577  x = d[j] - d[i] + o[i]/( x + r );
578  else
579  x = d[j] - d[i] + o[i]/( x - r );
580  s = c = 1.0;
581  yy = 0.0;
582 
583  /* Perform a plane rotation to diagonalize the submatrix, and
584  Givens rotations to restore it to tridiagonal form. */
585  for ( k = j - 1; k >= i; k-- ) {
586  xx = c*o[k];
587  y = s*o[k];
588  o[k+1] = ( r = RSS( x, y ) );
589 
590  /* Check for underflow. */
591  if ( r <= LAL_REAL8_MIN ) {
592  d[k+1] -= yy;
593  o[j] = 0.0;
594  break;
595  }
596 
597  /* Compute diagonal element. */
598  s = y/r;
599  c = x/r;
600  x = d[k+1] - yy;
601  r = ( d[k] - x )*s + 2.0*c*xx;
602  d[k+1] = x + ( yy = s*r );
603  x = c*r - xx;
604 
605  /* Accumulate transformation matrix. */
606  for ( l = 0, lk = k; l < n; l++, lk += n ) {
607  y = m[lk+1];
608  m[lk+1] = s*m[lk] + c*y;
609  m[lk] = c*m[lk] - s*y;
610  }
611  }
612 
613  /* Check for underflow. */
614  if ( r <= LAL_REAL8_MIN && k >= i )
615  continue;
616 
617  /* Adjust diagonal and off-diagonal elements, and continue
618  loop. */
619  d[i] -= yy;
620  o[i] = x;
621  o[j] = 0.0;
622  }
623  } while ( j != i );
624  }
625 
626  /* Done. */
627  RETURN( stat );
628 }
629 
630 
631 /**
632  * \defgroup Eigen_c Module Eigen.c
633  * \ingroup MatrixUtils_h
634  * \author Creighton, T. D.
635  *
636  * \brief Routines to compute eigenvalues and eigenvectors.
637  *
638  * ### Description ###
639  *
640  * <tt>LALSSymmetricEigenVectors()</tt> and
641  * <tt>LALDSymmetricEigenVectors()</tt> compute the eigenvalues and
642  * eigenvectors of the square matrix <tt>*matrix</tt>. The
643  * eigen\e values are stored in <tt>*values</tt>, which must be
644  * pre-allocated to the same length as each of the dimensions of
645  * <tt>*matrix</tt>. The eigen\e vectors are computed in-place and
646  * returned in <tt>*matrix</tt>: on return, each column of <tt>*matrix</tt>
647  * stores the eigenvector of the corresponding eigenvalue as a column
648  * vector. If you don't want the input matrix to be changed, make a copy
649  * of it first.
650  *
651  * ### Algorithm ###
652  *
653  * A square matrix \f$\mathsf{M}^a{}_b\f$ is said to have an eigenvalue
654  * \f$\lambda\f$ and associated eigenvector \f$\mathsf{x}^a\f$ if the following
655  * equation holds:
656  * \f{equation}{
657  * \label{eq_eigenvalue}
658  * \mathsf{M}^a{}_b \mathsf{x}^b = \lambda\mathsf{x}^a
659  * \f}
660  * Generically an \f$N\times N\f$ matrix has \f$N\f$ distinct eigenvalues each
661  * with a unique (up to a multiplicative constant) associated
662  * eigenvector. In certain cases, though, the system is
663  * \e degenerate: that is, some of the \f$N\f$ eigenvalues may be the
664  * \e same, and the corresponding eigenvectors may not be unique.
665  *
666  * We are concerned with the particular case of real, symmetric matrices,
667  * which occur in a broad class of problems. These matrices have certain
668  * useful properties. First, for any Hermitian matrix (including real
669  * symmetric matrices) the eigenvalues are all real. Second, for any
670  * matrix that commutes with its Hermitian conjugate (including Hermitian
671  * and unitary matrices, or, for real matrices, symmetric and
672  * orthogonal), the eigenvectors \f${\mathsf{x}_{(i)}}^a\f$ of distinct
673  * eigenvalues \f$\lambda_{(i)}\f$ are \e orthogonal: that is,
674  * \f$(\mathsf{x}_{(i)}^T)_a \mathsf{x}_{(j)}{}^a=0\f$ if
675  * \f$\lambda_{(i)}\neq\lambda_{(j)}\f$. Furthermore, we note that if two or
676  * more linearly independent eigenvectors have the \e same
677  * eigenvalue, then any linear combination of them is also an eigenvector
678  * with that same eigenvalue: we are therefore free to choose a basis of
679  * eigenvectors that is orthonormal. Thirdly, for any matrix that
680  * commutes with its conjugate, the complete set of eigenvectors spans
681  * the entire \f$N\f$-dimensional vector space, so the orthonormal basis
682  * above is a \e complete orthonormal basis.
683  *
684  * If we construct a square matrix \f$\mathsf{X}^a{}_b\f$ whose columns are
685  * the orthonormal eigenvectors \f$X^i{}_j={x_{(j)}}^i\f$, then it is clear
686  * (from the orthonormality of \f${\mathsf{x}_{(j)}}^a\f$) that
687  * \f$\mathsf{X}^a{}_b\f$ is orthogonal. Furtthermore, the eigenvalue
688  * \eqref{eq_eigenvalue} gives:
689  * \f{equation}{
690  * {(\mathsf{X}^{-1}){}^a{}_b}\mathsf{M}^b{}_c\mathsf{X}^c{}_d =
691  * \left[\begin{array}{cccc}
692  * \lambda_{(1)} & 0 & \cdots & 0 \\
693  * 0 & \lambda_{(2)} & \cdots & 0 \\
694  * \vdots & \vdots & \ddots & \vdots \\
695  * 0 & 0 & \cdots & \lambda_{(N)}
696  * \end{array}\right] \;,
697  * \f}
698  * where \f$\lambda_{(i)}\f$ are the eigenvalues of the corresponding
699  * eigenvectors (with the possibility that some of these eigenvalues have
700  * the same value). That is, the matrix \f$\mathsf{M}^b{}_c\f$ can be
701  * \e diagonalized by an orthogonal similarity transformation, and
702  * the transformation matrix gives us the eigenvectors. The process of
703  * solving the eigenvalue equation is thus equivalent to the problem of
704  * diagonalizing the matrix.
705  *
706  * For a general \f$N\times N\f$ symmetric matrix, there is no finite
707  * algorithm that exactly diagonalizes the matrix. Most numerical
708  * eigenvalue solvers use a process of iterative orthogonal
709  * transformations, where each transformation is chosen to reduce the sum
710  * of the squares of the off-diagonal elements: the matrix uniformly
711  * converges to a diagonal form under successive transformations. This
712  * convergence can be speeded if one first transforms the matrix into a
713  * \e tridiagonal form (where the only nonzero elements are on the
714  * diagonal or immediately adjacent to it); this transformation
715  * \e can be accomplished deterministically in a finite number of
716  * steps. This is the approach advocated in Chapter 11
717  * of \cite ptvf1992 , and taken in this module.
718  *
719  * The routines in call the routines
720  * first to reduce the matrix to tridiagonal
721  * form, and then to reduce it to diagonal form iteratively. The
722  * routines <tt>LALSSymmetricEigenVectors()</tt> and
723  * <tt>LALDSymmetricEigenVectors()</tt> call the routines
724  * <tt>LALSSymmetricToTriDiagonal()</tt> and
725  * <tt>LALDSymmetricToTriDiagonal()</tt> to tri-diagonalize the matrix,
726  * then <tt>LALSTriDiagonalToDiagonal()</tt> and
727  * <tt>LALDTriDiagonalToDiagonal()</tt> to diagonalize it.
728  *
729  */
730 
731 /** @{ */
732 
733 /** \see See \ref Eigen_c for documentation */
734 void
736 {
737  REAL4Vector *offDiag = NULL; /* off-diagonal line of
738  tri-diagonalized matrix */
739 
740  INITSTATUS(stat);
741  ATTATCHSTATUSPTR( stat );
742 
743  /* Check dimension length. All other argument testing is done by
744  the subroutines. */
747 
748  /* Allocate an off-diagonal vector for the tri-diagonal matrix. */
749  TRY( LALSCreateVector( stat->statusPtr, &offDiag, values->length ),
750  stat );
751 
752  /* Call the subroutines. */
753  LALSSymmetricToTriDiagonal( stat->statusPtr, values, matrix,
754  offDiag );
755  BEGINFAIL( stat ) {
756  TRY( LALSDestroyVector( stat->statusPtr, &offDiag ), stat );
757  } ENDFAIL( stat );
758  LALSTriDiagonalToDiagonal( stat->statusPtr, values, matrix,
759  offDiag );
760  BEGINFAIL( stat ) {
761  TRY( LALSDestroyVector( stat->statusPtr, &offDiag ), stat );
762  } ENDFAIL( stat );
763 
764  /* Clean up. */
765  TRY( LALSDestroyVector( stat->statusPtr, &offDiag ), stat );
766  DETATCHSTATUSPTR( stat );
767  RETURN( stat );
768 }
769 
770 
771 /** \see See \ref Eigen_c for documentation */
772 void
774 {
775  REAL8Vector *offDiag = NULL; /* off-diagonal line of
776  tri-diagonalized matrix */
777 
778  INITSTATUS(stat);
779  ATTATCHSTATUSPTR( stat );
780 
781  /* Check dimension length. All other argument testing is done by
782  the subroutines. */
785 
786  /* Allocate an off-diagonal vector for the tri-diagonal matrix. */
787  TRY( LALDCreateVector( stat->statusPtr, &offDiag, values->length ),
788  stat );
789 
790  /* Call the subroutines. */
791  LALDSymmetricToTriDiagonal( stat->statusPtr, values, matrix,
792  offDiag );
793  BEGINFAIL( stat ) {
794  TRY( LALDDestroyVector( stat->statusPtr, &offDiag ), stat );
795  } ENDFAIL( stat );
796  LALDTriDiagonalToDiagonal( stat->statusPtr, values, matrix,
797  offDiag );
798  BEGINFAIL( stat ) {
799  TRY( LALDDestroyVector( stat->statusPtr, &offDiag ), stat );
800  } ENDFAIL( stat );
801 
802  /* Clean up. */
803  TRY( LALDDestroyVector( stat->statusPtr, &offDiag ), stat );
804  DETATCHSTATUSPTR( stat );
805  RETURN( stat );
806 }
807 
808 /** @} */
#define EIGENINTERNALC_MAXITER
Definition: Eigen.c:27
static void LALSSymmetricToTriDiagonal(LALStatus *stat, REAL4Vector *diag, REAL4Array *matrix, REAL4Vector *offDiag)
Definition: Eigen.c:103
#define RSS(a, b)
Definition: Eigen.c:31
static void LALSTriDiagonalToDiagonal(LALStatus *stat, REAL4Vector *diag, REAL4Array *matrix, REAL4Vector *offDiag)
Definition: Eigen.c:245
static void LALDSymmetricToTriDiagonal(LALStatus *stat, REAL8Vector *diag, REAL8Array *matrix, REAL8Vector *offDiag)
Definition: Eigen.c:367
static void LALDTriDiagonalToDiagonal(LALStatus *stat, REAL8Vector *diag, REAL8Array *matrix, REAL8Vector *offDiag)
Definition: Eigen.c:509
#define ABORT(statusptr, code, mesg)
#define ENDFAIL(statusptr)
#define TRY(func, statusptr)
#define ATTATCHSTATUSPTR(statusptr)
#define ASSERT(assertion, statusptr, code, mesg)
#define DETATCHSTATUSPTR(statusptr)
#define INITSTATUS(statusptr)
#define RETURN(statusptr)
#define BEGINFAIL(statusptr)
#define MATRIXUTILSH_MSGEDIM
Definition: MatrixUtils.h:138
#define MATRIXUTILSH_MSGEITER
Definition: MatrixUtils.h:139
#define MATRIXUTILSH_MSGENUL
Definition: MatrixUtils.h:137
void LALDSymmetricEigenVectors(LALStatus *stat, REAL8Vector *values, REAL8Array *matrix)
Definition: Eigen.c:772
void LALSSymmetricEigenVectors(LALStatus *stat, REAL4Vector *values, REAL4Array *matrix)
Definition: Eigen.c:734
#define LAL_REAL8_EPS
Difference between 1 and the next resolvable REAL8 2^-52.
Definition: LALConstants.h:61
#define LAL_REAL4_MIN
Smallest normalized REAL4 number 2^-126.
Definition: LALConstants.h:56
#define LAL_REAL8_MIN
Smallest normalized REAL8 number 2^-1022.
Definition: LALConstants.h:60
#define LAL_REAL4_EPS
Difference between 1 and the next resolvable REAL4 2^-23.
Definition: LALConstants.h:57
double REAL8
Double precision real floating-point number (8 bytes).
uint32_t UINT4
Four-byte unsigned integer.
int32_t INT4
Four-byte signed integer.
float REAL4
Single precision real floating-point number (4 bytes).
#define MATRIXUTILSH_ENUL
Unexpected null pointer in arguments.
Definition: MatrixUtils.h:128
#define MATRIXUTILSH_EDIM
Bad matrix dimensions.
Definition: MatrixUtils.h:129
#define MATRIXUTILSH_EITER
Did not converge after maximum iterations.
Definition: MatrixUtils.h:130
static const INT4 r
Definition: Random.c:82
static const INT4 m
Definition: Random.c:80
void LALDCreateVector(LALStatus *, REAL8Vector **, UINT4)
void LALDDestroyVector(LALStatus *, REAL8Vector **)
void LALSDestroyVector(LALStatus *, REAL4Vector **)
void LALSCreateVector(LALStatus *, REAL4Vector **, UINT4)
LAL status structure, see The LALStatus structure for more details.
Definition: LALDatatypes.h:947
struct tagLALStatus * statusPtr
Pointer to the next node in the list; NULL if this function is not reporting a subroutine error.
Definition: LALDatatypes.h:954
Multidimentional array of REAL4, see DATATYPE-Array types for more details.
Definition: LALDatatypes.h:220
UINT4Vector * dimLength
Vector of array dimensions.
Definition: LALDatatypes.h:221
REAL4 * data
Pointer to the data array.
Definition: LALDatatypes.h:222
Vector of type REAL4, see DATATYPE-Vector types for more details.
Definition: LALDatatypes.h:145
REAL4 * data
Pointer to the data array.
Definition: LALDatatypes.h:150
UINT4 length
Number of elements in array.
Definition: LALDatatypes.h:149
Multidimentional array of REAL8, see DATATYPE-Array types for more details.
Definition: LALDatatypes.h:226
UINT4Vector * dimLength
Vector of array dimensions.
Definition: LALDatatypes.h:227
REAL8 * data
Pointer to the data array.
Definition: LALDatatypes.h:228
Vector of type REAL8, see DATATYPE-Vector types for more details.
Definition: LALDatatypes.h:154
REAL8 * data
Pointer to the data array.
Definition: LALDatatypes.h:159
UINT4 length
Number of elements in array.
Definition: LALDatatypes.h:158
UINT4 length
Number of elements in array.
Definition: LALDatatypes.h:122
UINT4 * data
Pointer to the data array.
Definition: LALDatatypes.h:123