Loading [MathJax]/extensions/TeX/AMSsymbols.js
LAL 7.7.0.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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 ) ? \
33fabs( 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
103static 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. */
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
245static 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. */
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
367static 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. */
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
509static 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. */
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 */
734void
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 */
772void
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