3 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2006, 2007 Gerard Jungman, Patrick Alken, Brian Gough
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or (at
8 * your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include <gsl/gsl_test.h>
26 #include <gsl/gsl_math.h>
27 #include <gsl/gsl_blas.h>
28 #include <gsl/gsl_ieee_utils.h>
29 #include <gsl/gsl_complex_math.h>
30 #include <gsl/gsl_eigen.h>
31 #include <gsl/gsl_linalg.h>
32 #include <gsl/gsl_rng.h>
33 #include <gsl/gsl_randist.h>
34 #include <gsl/gsl_errno.h>
35 #include <gsl/gsl_sort.h>
36 #include <gsl/gsl_sort_vector.h>
37 #include <gsl/gsl_matrix.h>
38 #include <gsl/gsl_vector.h>
40 /******************************************
42 ******************************************/
45 chop_subnormals (double x)
47 /* Chop any subnormal values */
48 return fabs(x) < GSL_DBL_MIN ? 0 : x;
52 create_random_symm_matrix(gsl_matrix *m, gsl_rng *r, int lower, int upper)
56 for (i = 0; i < m->size1; ++i)
58 for (j = i; j < m->size2; ++j)
60 double x = gsl_rng_uniform(r) * (upper - lower) + lower;
61 gsl_matrix_set(m, i, j, x);
62 gsl_matrix_set(m, j, i, x);
65 } /* create_random_symm_matrix() */
68 create_random_herm_matrix(gsl_matrix_complex *m, gsl_rng *r, int lower,
73 for (i = 0; i < m->size1; ++i)
75 for (j = i; j < m->size2; ++j)
79 GSL_REAL(z) = gsl_rng_uniform(r) * (upper - lower) + lower;
84 GSL_IMAG(z) = gsl_rng_uniform(r) * (upper - lower) + lower;
86 gsl_matrix_complex_set(m, i, j, z);
87 gsl_matrix_complex_set(m, j, i, gsl_complex_conjugate(z));
90 } /* create_random_herm_matrix() */
92 /* with r \in (0,1) if m_{ij} = r^{|i - j|} then m is positive definite */
94 create_random_posdef_matrix(gsl_matrix *m, gsl_rng *r)
97 double x = gsl_rng_uniform(r);
99 for (i = 0; i < m->size1; ++i)
101 for (j = i; j < m->size2; ++j)
103 double a = pow(x, (double) (j - i));
105 gsl_matrix_set(m, i, j, a);
106 gsl_matrix_set(m, j, i, a);
109 } /* create_random_posdef_matrix() */
112 create_random_complex_posdef_matrix(gsl_matrix_complex *m, gsl_rng *r,
113 gsl_vector_complex *work)
115 const size_t N = m->size1;
121 GSL_SET_IMAG(&z, 0.0);
123 /* make a positive diagonal matrix */
124 gsl_matrix_complex_set_zero(m);
125 for (i = 0; i < N; ++i)
127 x = gsl_rng_uniform(r);
129 gsl_matrix_complex_set(m, i, i, z);
132 /* now generate random householder reflections and form P D P^H */
133 for (i = 0; i < N; ++i)
135 /* form complex vector */
136 for (j = 0; j < N; ++j)
138 x = 2.0 * gsl_rng_uniform(r) - 1.0;
139 y = 2.0 * gsl_rng_uniform(r) - 1.0;
140 GSL_SET_COMPLEX(&z, x, y);
141 gsl_vector_complex_set(work, j, z);
144 tau = gsl_linalg_complex_householder_transform(work);
145 gsl_linalg_complex_householder_hm(tau, work, m);
146 gsl_linalg_complex_householder_mh(gsl_complex_conjugate(tau), work, m);
148 } /* create_random_complex_posdef_matrix() */
151 create_random_nonsymm_matrix(gsl_matrix *m, gsl_rng *r, int lower,
156 for (i = 0; i < m->size1; ++i)
158 for (j = 0; j < m->size2; ++j)
163 gsl_rng_uniform(r) * (upper - lower) + lower);
166 } /* create_random_nonsymm_matrix() */
168 /* test if A Z = Q S */
170 test_eigen_schur(const gsl_matrix * A, const gsl_matrix * S,
171 const gsl_matrix * Q, const gsl_matrix * Z,
172 size_t count, const char * desc,
175 const size_t N = A->size1;
178 gsl_matrix * T1 = gsl_matrix_alloc(N, N);
179 gsl_matrix * T2 = gsl_matrix_alloc(N, N);
181 /* compute T1 = A Z */
182 gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, A, Z, 0.0, T1);
184 /* compute T2 = Q S */
185 gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, Q, S, 0.0, T2);
187 for (i = 0; i < N; ++i)
189 for (j = 0; j < N; ++j)
191 double x = gsl_matrix_get(T1, i, j);
192 double y = gsl_matrix_get(T2, i, j);
194 gsl_test_abs(x, y, 1.0e8 * GSL_DBL_EPSILON,
195 "%s(N=%u,cnt=%u), %s, schur(%d,%d)", desc, N, count, desc2, i, j);
199 gsl_matrix_free (T1);
200 gsl_matrix_free (T2);
201 } /* test_eigen_schur() */
204 test_eigenvalues_real (const gsl_vector *eval, const gsl_vector * eval2,
205 const char * desc, const char * desc2)
207 const size_t N = eval->size;
212 /* check eigenvalues */
213 for (i = 0; i < N; i++)
215 double ei = gsl_vector_get (eval, i);
216 if (fabs(ei) > emax) emax = fabs(ei);
219 for (i = 0; i < N; i++)
221 double ei = gsl_vector_get (eval, i);
222 double e2i = gsl_vector_get (eval2, i);
223 e2i = chop_subnormals(e2i);
224 gsl_test_abs(ei, e2i, emax * 1e8 * GSL_DBL_EPSILON,
225 "%s, direct eigenvalue(%d), %s",
231 test_eigenvalues_complex (const gsl_vector_complex * eval,
232 const gsl_vector_complex * eval2,
233 const char * desc, const char * desc2)
235 const size_t N = eval->size;
238 for (i = 0; i < N; i++)
240 gsl_complex ei = gsl_vector_complex_get (eval, i);
241 gsl_complex e2i = gsl_vector_complex_get (eval2, i);
242 gsl_test_rel(GSL_REAL(ei), GSL_REAL(e2i), 10*N*GSL_DBL_EPSILON,
243 "%s, direct eigenvalue(%d) real, %s",
245 gsl_test_rel(GSL_IMAG(ei), GSL_IMAG(e2i), 10*N*GSL_DBL_EPSILON,
246 "%s, direct eigenvalue(%d) imag, %s",
251 /******************************************
253 ******************************************/
256 test_eigen_symm_results (const gsl_matrix * A,
257 const gsl_vector * eval,
258 const gsl_matrix * evec,
263 const size_t N = A->size1;
267 gsl_vector * x = gsl_vector_alloc(N);
268 gsl_vector * y = gsl_vector_alloc(N);
270 /* check eigenvalues */
271 for (i = 0; i < N; i++)
273 double ei = gsl_vector_get (eval, i);
274 if (fabs(ei) > emax) emax = fabs(ei);
277 for (i = 0; i < N; i++)
279 double ei = gsl_vector_get (eval, i);
280 gsl_vector_const_view vi = gsl_matrix_const_column(evec, i);
281 gsl_vector_memcpy(x, &vi.vector);
282 /* compute y = A x (should = lambda v) */
283 gsl_blas_dgemv (CblasNoTrans, 1.0, A, x, 0.0, y);
284 for (j = 0; j < N; j++)
286 double xj = gsl_vector_get (x, j);
287 double yj = gsl_vector_get (y, j);
288 double eixj = chop_subnormals(ei * xj);
289 gsl_test_abs(yj, eixj, emax * 1e8 * GSL_DBL_EPSILON,
290 "%s, eigenvalue(%d,%d), %s", desc, i, j, desc2);
294 /* check eigenvectors are orthonormal */
296 for (i = 0; i < N; i++)
298 gsl_vector_const_view vi = gsl_matrix_const_column(evec, i);
299 double nrm_v = gsl_blas_dnrm2(&vi.vector);
300 gsl_test_rel (nrm_v, 1.0, N * GSL_DBL_EPSILON, "%s, normalized(%d), %s",
304 for (i = 0; i < N; i++)
306 gsl_vector_const_view vi = gsl_matrix_const_column(evec, i);
307 for (j = i + 1; j < N; j++)
309 gsl_vector_const_view vj = gsl_matrix_const_column(evec, j);
311 gsl_blas_ddot (&vi.vector, &vj.vector, &vivj);
312 gsl_test_abs (vivj, 0.0, N * GSL_DBL_EPSILON,
313 "%s, orthogonal(%d,%d), %s", desc, i, j, desc2);
322 test_eigen_symm_matrix(const gsl_matrix * m, size_t count,
325 const size_t N = m->size1;
326 gsl_matrix * A = gsl_matrix_alloc(N, N);
327 gsl_vector * eval = gsl_vector_alloc(N);
328 gsl_vector * evalv = gsl_vector_alloc(N);
329 gsl_vector * x = gsl_vector_alloc(N);
330 gsl_vector * y = gsl_vector_alloc(N);
331 gsl_matrix * evec = gsl_matrix_alloc(N, N);
332 gsl_eigen_symm_workspace * w = gsl_eigen_symm_alloc(N);
333 gsl_eigen_symmv_workspace * wv = gsl_eigen_symmv_alloc(N);
335 gsl_matrix_memcpy(A, m);
337 gsl_eigen_symmv(A, evalv, evec, wv);
338 test_eigen_symm_results(m, evalv, evec, count, desc, "unsorted");
340 gsl_matrix_memcpy(A, m);
342 gsl_eigen_symm(A, eval, w);
344 /* sort eval and evalv */
345 gsl_vector_memcpy(x, eval);
346 gsl_vector_memcpy(y, evalv);
349 test_eigenvalues_real(y, x, desc, "unsorted");
351 gsl_eigen_symmv_sort(evalv, evec, GSL_EIGEN_SORT_VAL_ASC);
352 test_eigen_symm_results(m, evalv, evec, count, desc, "val/asc");
354 gsl_eigen_symmv_sort(evalv, evec, GSL_EIGEN_SORT_VAL_DESC);
355 test_eigen_symm_results(m, evalv, evec, count, desc, "val/desc");
357 gsl_eigen_symmv_sort(evalv, evec, GSL_EIGEN_SORT_ABS_ASC);
358 test_eigen_symm_results(m, evalv, evec, count, desc, "abs/asc");
360 gsl_eigen_symmv_sort(evalv, evec, GSL_EIGEN_SORT_ABS_DESC);
361 test_eigen_symm_results(m, evalv, evec, count, desc, "abs/desc");
364 gsl_vector_free(eval);
365 gsl_vector_free(evalv);
368 gsl_matrix_free(evec);
369 gsl_eigen_symm_free(w);
370 gsl_eigen_symmv_free(wv);
371 } /* test_eigen_symm_matrix() */
374 test_eigen_symm(void)
378 gsl_rng *r = gsl_rng_alloc(gsl_rng_default);
380 for (n = 1; n <= N_max; ++n)
382 gsl_matrix * A = gsl_matrix_alloc(n, n);
384 for (i = 0; i < 5; ++i)
386 create_random_symm_matrix(A, r, -10, 10);
387 test_eigen_symm_matrix(A, i, "symm random");
396 double dat1[] = { 0, 0, -1, 0,
400 double dat2[] = { 1, 0, 0, 0,
406 m = gsl_matrix_view_array (dat1, 4, 4);
407 test_eigen_symm_matrix(&m.matrix, 0, "symm(4)");
409 m = gsl_matrix_view_array (dat2, 4, 4);
410 test_eigen_symm_matrix(&m.matrix, 0, "symm(4) diag");
414 double dat[27*27] = {
415 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
416 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,
417 0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,
418 0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
419 0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
420 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
421 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
422 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
423 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
424 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
425 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
426 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
427 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
428 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
429 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
430 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
431 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
432 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
433 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
434 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
435 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
436 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
437 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
438 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
439 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
440 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
441 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
445 m = gsl_matrix_view_array (dat, 27, 27);
446 test_eigen_symm_matrix(&m.matrix, 0, "symm(27)");
449 } /* test_eigen_symm() */
451 /******************************************
453 ******************************************/
456 test_eigen_herm_results (const gsl_matrix_complex * A,
457 const gsl_vector * eval,
458 const gsl_matrix_complex * evec,
463 const size_t N = A->size1;
466 gsl_vector_complex * x = gsl_vector_complex_alloc(N);
467 gsl_vector_complex * y = gsl_vector_complex_alloc(N);
469 /* check eigenvalues */
471 for (i = 0; i < N; i++)
473 double ei = gsl_vector_get (eval, i);
474 gsl_vector_complex_const_view vi =
475 gsl_matrix_complex_const_column(evec, i);
476 gsl_vector_complex_memcpy(x, &vi.vector);
477 /* compute y = m x (should = lambda v) */
478 gsl_blas_zgemv (CblasNoTrans, GSL_COMPLEX_ONE, A, x,
479 GSL_COMPLEX_ZERO, y);
480 for (j = 0; j < N; j++)
482 gsl_complex xj = gsl_vector_complex_get (x, j);
483 gsl_complex yj = gsl_vector_complex_get (y, j);
484 gsl_test_rel(GSL_REAL(yj), ei * GSL_REAL(xj), 1e8*GSL_DBL_EPSILON,
485 "%s, eigenvalue(%d,%d), real, %s", desc, i, j, desc2);
486 gsl_test_rel(GSL_IMAG(yj), ei * GSL_IMAG(xj), 1e8*GSL_DBL_EPSILON,
487 "%s, eigenvalue(%d,%d), imag, %s", desc, i, j, desc2);
491 /* check eigenvectors are orthonormal */
493 for (i = 0; i < N; i++)
495 gsl_vector_complex_const_view vi = gsl_matrix_complex_const_column(evec, i);
496 double nrm_v = gsl_blas_dznrm2(&vi.vector);
497 gsl_test_rel (nrm_v, 1.0, N * GSL_DBL_EPSILON, "%s, normalized(%d), %s",
501 for (i = 0; i < N; i++)
503 gsl_vector_complex_const_view vi = gsl_matrix_complex_const_column(evec, i);
504 for (j = i + 1; j < N; j++)
506 gsl_vector_complex_const_view vj
507 = gsl_matrix_complex_const_column(evec, j);
509 gsl_blas_zdotc (&vi.vector, &vj.vector, &vivj);
510 gsl_test_abs (gsl_complex_abs(vivj), 0.0, N * GSL_DBL_EPSILON,
511 "%s, orthogonal(%d,%d), %s", desc, i, j, desc2);
515 gsl_vector_complex_free(x);
516 gsl_vector_complex_free(y);
517 } /* test_eigen_herm_results() */
520 test_eigen_herm_matrix(const gsl_matrix_complex * m, size_t count,
523 const size_t N = m->size1;
524 gsl_matrix_complex * A = gsl_matrix_complex_alloc(N, N);
525 gsl_vector * eval = gsl_vector_alloc(N);
526 gsl_vector * evalv = gsl_vector_alloc(N);
527 gsl_vector * x = gsl_vector_alloc(N);
528 gsl_vector * y = gsl_vector_alloc(N);
529 gsl_matrix_complex * evec = gsl_matrix_complex_alloc(N, N);
530 gsl_eigen_herm_workspace * w = gsl_eigen_herm_alloc(N);
531 gsl_eigen_hermv_workspace * wv = gsl_eigen_hermv_alloc(N);
533 gsl_matrix_complex_memcpy(A, m);
535 gsl_eigen_hermv(A, evalv, evec, wv);
536 test_eigen_herm_results(m, evalv, evec, count, desc, "unsorted");
538 gsl_matrix_complex_memcpy(A, m);
540 gsl_eigen_herm(A, eval, w);
542 /* sort eval and evalv */
543 gsl_vector_memcpy(x, eval);
544 gsl_vector_memcpy(y, evalv);
547 test_eigenvalues_real(y, x, desc, "unsorted");
549 gsl_eigen_hermv_sort(evalv, evec, GSL_EIGEN_SORT_VAL_ASC);
550 test_eigen_herm_results(m, evalv, evec, count, desc, "val/asc");
552 gsl_eigen_hermv_sort(evalv, evec, GSL_EIGEN_SORT_VAL_DESC);
553 test_eigen_herm_results(m, evalv, evec, count, desc, "val/desc");
555 gsl_eigen_hermv_sort(evalv, evec, GSL_EIGEN_SORT_ABS_ASC);
556 test_eigen_herm_results(m, evalv, evec, count, desc, "abs/asc");
558 gsl_eigen_hermv_sort(evalv, evec, GSL_EIGEN_SORT_ABS_DESC);
559 test_eigen_herm_results(m, evalv, evec, count, desc, "abs/desc");
561 gsl_matrix_complex_free(A);
562 gsl_vector_free(eval);
563 gsl_vector_free(evalv);
566 gsl_matrix_complex_free(evec);
567 gsl_eigen_herm_free(w);
568 gsl_eigen_hermv_free(wv);
569 } /* test_eigen_herm_matrix() */
572 test_eigen_herm(void)
576 gsl_rng *r = gsl_rng_alloc(gsl_rng_default);
578 for (n = 1; n <= N_max; ++n)
580 gsl_matrix_complex * A = gsl_matrix_complex_alloc(n, n);
582 for (i = 0; i < 5; ++i)
584 create_random_herm_matrix(A, r, -10, 10);
585 test_eigen_herm_matrix(A, i, "herm random");
588 gsl_matrix_complex_free(A);
594 double dat1[] = { 0,0, 0,0, -1,0, 0,0,
597 0,0, 1,0, 0,0, 0,0 };
598 double dat2[] = { 1,0, 0,0, 0,0, 0,0,
601 0,0, 0,0, 0,0, 4,0 };
602 gsl_matrix_complex_view m;
604 m = gsl_matrix_complex_view_array (dat1, 4, 4);
605 test_eigen_herm_matrix(&m.matrix, 0, "herm(4)");
607 m = gsl_matrix_complex_view_array (dat2, 4, 4);
608 test_eigen_herm_matrix(&m.matrix, 1, "herm(4) diag");
610 } /* test_eigen_herm() */
612 /******************************************
613 * nonsymm test code *
614 ******************************************/
617 test_eigen_nonsymm_results (const gsl_matrix * m,
618 const gsl_vector_complex * eval,
619 const gsl_matrix_complex * evec,
627 gsl_vector_complex * x = gsl_vector_complex_alloc(N);
628 gsl_vector_complex * y = gsl_vector_complex_alloc(N);
629 gsl_matrix_complex * A = gsl_matrix_complex_alloc(N, N);
631 /* we need a complex matrix for the blas routines, so copy m into A */
632 for (i = 0; i < N; ++i)
634 for (j = 0; j < N; ++j)
637 GSL_SET_COMPLEX(&z, gsl_matrix_get(m, i, j), 0.0);
638 gsl_matrix_complex_set(A, i, j, z);
642 for (i = 0; i < N; i++)
644 gsl_complex ei = gsl_vector_complex_get (eval, i);
645 gsl_vector_complex_const_view vi = gsl_matrix_complex_const_column(evec, i);
646 double norm = gsl_blas_dznrm2(&vi.vector);
648 /* check that eigenvector is normalized */
649 gsl_test_rel(norm, 1.0, N * GSL_DBL_EPSILON,
650 "nonsymm(N=%u,cnt=%u), %s, normalized(%d), %s", N, count, desc, i, desc2);
652 gsl_vector_complex_memcpy(x, &vi.vector);
654 /* compute y = m x (should = lambda v) */
655 gsl_blas_zgemv (CblasNoTrans, GSL_COMPLEX_ONE, A, x,
656 GSL_COMPLEX_ZERO, y);
658 /* compute x = lambda v */
659 gsl_blas_zscal(ei, x);
661 /* now test if y = x */
662 for (j = 0; j < N; j++)
664 gsl_complex xj = gsl_vector_complex_get (x, j);
665 gsl_complex yj = gsl_vector_complex_get (y, j);
667 /* use abs here in case the values are close to 0 */
668 gsl_test_abs(GSL_REAL(yj), GSL_REAL(xj), 1e8*GSL_DBL_EPSILON,
669 "nonsymm(N=%u,cnt=%u), %s, eigenvalue(%d,%d), real, %s", N, count, desc, i, j, desc2);
670 gsl_test_abs(GSL_IMAG(yj), GSL_IMAG(xj), 1e8*GSL_DBL_EPSILON,
671 "nonsymm(N=%u,cnt=%u), %s, eigenvalue(%d,%d), imag, %s", N, count, desc, i, j, desc2);
675 gsl_matrix_complex_free(A);
676 gsl_vector_complex_free(x);
677 gsl_vector_complex_free(y);
681 test_eigen_nonsymm_matrix(const gsl_matrix * m, size_t count,
683 gsl_eigen_nonsymmv_workspace *w)
685 const size_t N = m->size1;
686 gsl_matrix * A = gsl_matrix_alloc(N, N);
687 gsl_matrix * Z = gsl_matrix_alloc(N, N);
688 gsl_matrix_complex * evec = gsl_matrix_complex_alloc(N, N);
689 gsl_vector_complex * eval = gsl_vector_complex_alloc(N);
692 * calculate eigenvalues and eigenvectors - it is sufficient to
693 * test gsl_eigen_nonsymmv() since that function calls
694 * gsl_eigen_nonsymm() for the eigenvalues
696 gsl_matrix_memcpy(A, m);
697 gsl_eigen_nonsymmv(A, eval, evec, w);
698 test_eigen_nonsymm_results (m, eval, evec, count, desc, "unsorted");
700 /* test sort routines */
701 gsl_eigen_nonsymmv_sort (eval, evec, GSL_EIGEN_SORT_ABS_ASC);
702 test_eigen_nonsymm_results (m, eval, evec, count, desc, "abs/asc");
704 gsl_eigen_nonsymmv_sort (eval, evec, GSL_EIGEN_SORT_ABS_DESC);
705 test_eigen_nonsymm_results (m, eval, evec, count, desc, "abs/desc");
707 /* test Schur vectors */
708 gsl_matrix_memcpy(A, m);
709 gsl_eigen_nonsymmv_Z(A, eval, evec, Z, w);
710 gsl_linalg_hessenberg_set_zero(A);
711 test_eigen_schur(m, A, Z, Z, count, "nonsymm", desc);
715 gsl_matrix_complex_free(evec);
716 gsl_vector_complex_free(eval);
720 test_eigen_nonsymm(void)
724 gsl_rng *r = gsl_rng_alloc(gsl_rng_default);
726 for (n = 1; n <= N_max; ++n)
728 gsl_matrix * m = gsl_matrix_alloc(n, n);
729 gsl_eigen_nonsymmv_workspace * w = gsl_eigen_nonsymmv_alloc(n);
731 for (i = 0; i < 5; ++i)
733 create_random_nonsymm_matrix(m, r, -10, 10);
735 gsl_eigen_nonsymm_params(1, 0, w->nonsymm_workspace_p);
736 test_eigen_nonsymm_matrix(m, i, "random, unbalanced", w);
738 gsl_eigen_nonsymm_params(1, 1, w->nonsymm_workspace_p);
739 test_eigen_nonsymm_matrix(m, i, "random, balanced", w);
743 gsl_eigen_nonsymmv_free(w);
749 double dat1[] = { 0, 1, 1, 1,
753 double dat2[] = { 1, 1, 0, 1,
758 gsl_eigen_nonsymmv_workspace * w = gsl_eigen_nonsymmv_alloc(4);
760 v = gsl_matrix_view_array (dat1, 4, 4);
761 test_eigen_nonsymm_matrix(&v.matrix, 0, "integer", w);
763 v = gsl_matrix_view_array (dat2, 4, 4);
764 test_eigen_nonsymm_matrix(&v.matrix, 1, "integer", w);
766 gsl_eigen_nonsymmv_free(w);
768 } /* test_eigen_nonsymm() */
770 /******************************************
771 * gensymm test code *
772 ******************************************/
775 test_eigen_gensymm_results (const gsl_matrix * A,
776 const gsl_matrix * B,
777 const gsl_vector * eval,
778 const gsl_matrix * evec,
783 const size_t N = A->size1;
786 gsl_vector * x = gsl_vector_alloc(N);
787 gsl_vector * y = gsl_vector_alloc(N);
788 gsl_vector * z = gsl_vector_alloc(N);
790 /* check A v = lambda B v */
791 for (i = 0; i < N; i++)
793 double ei = gsl_vector_get (eval, i);
794 gsl_vector_const_view vi = gsl_matrix_const_column(evec, i);
795 double norm = gsl_blas_dnrm2(&vi.vector);
797 /* check that eigenvector is normalized */
798 gsl_test_rel(norm, 1.0, N * GSL_DBL_EPSILON,
799 "gensymm(N=%u,cnt=%u), %s, normalized(%d), %s", N, count,
802 gsl_vector_memcpy(z, &vi.vector);
804 /* compute y = A z */
805 gsl_blas_dgemv (CblasNoTrans, 1.0, A, z, 0.0, y);
807 /* compute x = B z */
808 gsl_blas_dgemv (CblasNoTrans, 1.0, B, z, 0.0, x);
810 /* compute x = lambda B z */
811 gsl_blas_dscal(ei, x);
813 /* now test if y = x */
814 for (j = 0; j < N; j++)
816 double xj = gsl_vector_get (x, j);
817 double yj = gsl_vector_get (y, j);
819 gsl_test_rel(yj, xj, 1e9 * GSL_DBL_EPSILON,
820 "gensymm(N=%u,cnt=%u), %s, eigenvalue(%d,%d), real, %s", N, count, desc, i, j, desc2);
830 test_eigen_gensymm(void)
834 gsl_rng *r = gsl_rng_alloc(gsl_rng_default);
836 for (n = 1; n <= N_max; ++n)
838 gsl_matrix * A = gsl_matrix_alloc(n, n);
839 gsl_matrix * B = gsl_matrix_alloc(n, n);
840 gsl_matrix * ma = gsl_matrix_alloc(n, n);
841 gsl_matrix * mb = gsl_matrix_alloc(n, n);
842 gsl_vector * eval = gsl_vector_alloc(n);
843 gsl_vector * evalv = gsl_vector_alloc(n);
844 gsl_vector * x = gsl_vector_alloc(n);
845 gsl_vector * y = gsl_vector_alloc(n);
846 gsl_matrix * evec = gsl_matrix_alloc(n, n);
847 gsl_eigen_gensymm_workspace * w = gsl_eigen_gensymm_alloc(n);
848 gsl_eigen_gensymmv_workspace * wv = gsl_eigen_gensymmv_alloc(n);
850 for (i = 0; i < 5; ++i)
852 create_random_symm_matrix(A, r, -10, 10);
853 create_random_posdef_matrix(B, r);
855 gsl_matrix_memcpy(ma, A);
856 gsl_matrix_memcpy(mb, B);
858 gsl_eigen_gensymmv(ma, mb, evalv, evec, wv);
859 test_eigen_gensymm_results(A, B, evalv, evec, i, "random", "unsorted");
861 gsl_matrix_memcpy(ma, A);
862 gsl_matrix_memcpy(mb, B);
864 gsl_eigen_gensymm(ma, mb, eval, w);
866 /* eval and evalv have to be sorted? not sure why */
867 gsl_vector_memcpy(x, eval);
868 gsl_vector_memcpy(y, evalv);
871 test_eigenvalues_real(y, x, "gensymm, random", "unsorted");
873 gsl_eigen_gensymmv_sort(evalv, evec, GSL_EIGEN_SORT_VAL_ASC);
874 test_eigen_gensymm_results(A, B, evalv, evec, i, "random", "val/asc");
876 gsl_eigen_gensymmv_sort(evalv, evec, GSL_EIGEN_SORT_VAL_DESC);
877 test_eigen_gensymm_results(A, B, evalv, evec, i, "random", "val/desc");
879 gsl_eigen_gensymmv_sort(evalv, evec, GSL_EIGEN_SORT_ABS_ASC);
880 test_eigen_gensymm_results(A, B, evalv, evec, i, "random", "abs/asc");
881 gsl_eigen_gensymmv_sort(evalv, evec, GSL_EIGEN_SORT_ABS_DESC);
882 test_eigen_gensymm_results(A, B, evalv, evec, i, "random", "abs/desc");
889 gsl_vector_free(eval);
890 gsl_vector_free(evalv);
893 gsl_matrix_free(evec);
894 gsl_eigen_gensymm_free(w);
895 gsl_eigen_gensymmv_free(wv);
899 } /* test_eigen_gensymm() */
901 /******************************************
902 * genherm test code *
903 ******************************************/
906 test_eigen_genherm_results (const gsl_matrix_complex * A,
907 const gsl_matrix_complex * B,
908 const gsl_vector * eval,
909 const gsl_matrix_complex * evec,
914 const size_t N = A->size1;
917 gsl_vector_complex * x = gsl_vector_complex_alloc(N);
918 gsl_vector_complex * y = gsl_vector_complex_alloc(N);
920 /* check A v = lambda B v */
921 for (i = 0; i < N; i++)
923 double ei = gsl_vector_get (eval, i);
924 gsl_vector_complex_const_view vi =
925 gsl_matrix_complex_const_column(evec, i);
926 double norm = gsl_blas_dznrm2(&vi.vector);
928 /* check that eigenvector is normalized */
929 gsl_test_rel(norm, 1.0, N * GSL_DBL_EPSILON,
930 "genherm(N=%u,cnt=%u), %s, normalized(%d), %s", N, count,
933 /* compute y = A z */
934 gsl_blas_zgemv (CblasNoTrans, GSL_COMPLEX_ONE, A, &vi.vector, GSL_COMPLEX_ZERO, y);
936 /* compute x = B z */
937 gsl_blas_zgemv (CblasNoTrans, GSL_COMPLEX_ONE, B, &vi.vector, GSL_COMPLEX_ZERO, x);
939 /* compute x = lambda B z */
940 gsl_blas_zdscal(ei, x);
942 /* now test if y = x */
943 for (j = 0; j < N; j++)
945 gsl_complex xj = gsl_vector_complex_get (x, j);
946 gsl_complex yj = gsl_vector_complex_get (y, j);
948 gsl_test_rel(GSL_REAL(yj), GSL_REAL(xj), 1e9 * GSL_DBL_EPSILON,
949 "genherm(N=%u,cnt=%u), %s, eigenvalue(%d,%d), real, %s", N, count, desc, i, j, desc2);
950 gsl_test_abs(GSL_IMAG(yj), GSL_IMAG(xj), 1e9 * GSL_DBL_EPSILON,
951 "genherm(N=%u,cnt=%u), %s, eigenvalue(%d,%d), imag, %s", N, count, desc, i, j, desc2);
955 gsl_vector_complex_free(x);
956 gsl_vector_complex_free(y);
960 test_eigen_genherm(void)
964 gsl_rng *r = gsl_rng_alloc(gsl_rng_default);
966 for (n = 1; n <= N_max; ++n)
968 gsl_matrix_complex * A = gsl_matrix_complex_alloc(n, n);
969 gsl_matrix_complex * B = gsl_matrix_complex_alloc(n, n);
970 gsl_matrix_complex * ma = gsl_matrix_complex_alloc(n, n);
971 gsl_matrix_complex * mb = gsl_matrix_complex_alloc(n, n);
972 gsl_vector * eval = gsl_vector_alloc(n);
973 gsl_vector * evalv = gsl_vector_alloc(n);
974 gsl_vector * x = gsl_vector_alloc(n);
975 gsl_vector * y = gsl_vector_alloc(n);
976 gsl_vector_complex * work = gsl_vector_complex_alloc(n);
977 gsl_matrix_complex * evec = gsl_matrix_complex_alloc(n, n);
978 gsl_eigen_genherm_workspace * w = gsl_eigen_genherm_alloc(n);
979 gsl_eigen_genhermv_workspace * wv = gsl_eigen_genhermv_alloc(n);
981 for (i = 0; i < 5; ++i)
983 create_random_herm_matrix(A, r, -10, 10);
984 create_random_complex_posdef_matrix(B, r, work);
986 gsl_matrix_complex_memcpy(ma, A);
987 gsl_matrix_complex_memcpy(mb, B);
989 gsl_eigen_genhermv(ma, mb, evalv, evec, wv);
990 test_eigen_genherm_results(A, B, evalv, evec, i, "random", "unsorted");
992 gsl_matrix_complex_memcpy(ma, A);
993 gsl_matrix_complex_memcpy(mb, B);
995 gsl_eigen_genherm(ma, mb, eval, w);
997 /* eval and evalv have to be sorted? not sure why */
998 gsl_vector_memcpy(x, eval);
999 gsl_vector_memcpy(y, evalv);
1002 test_eigenvalues_real(y, x, "genherm, random", "unsorted");
1004 gsl_eigen_genhermv_sort(evalv, evec, GSL_EIGEN_SORT_VAL_ASC);
1005 test_eigen_genherm_results(A, B, evalv, evec, i, "random", "val/asc");
1007 gsl_eigen_genhermv_sort(evalv, evec, GSL_EIGEN_SORT_VAL_DESC);
1008 test_eigen_genherm_results(A, B, evalv, evec, i, "random", "val/desc");
1010 gsl_eigen_genhermv_sort(evalv, evec, GSL_EIGEN_SORT_ABS_ASC);
1011 test_eigen_genherm_results(A, B, evalv, evec, i, "random", "abs/asc");
1012 gsl_eigen_genhermv_sort(evalv, evec, GSL_EIGEN_SORT_ABS_DESC);
1013 test_eigen_genherm_results(A, B, evalv, evec, i, "random", "abs/desc");
1016 gsl_matrix_complex_free(A);
1017 gsl_matrix_complex_free(B);
1018 gsl_matrix_complex_free(ma);
1019 gsl_matrix_complex_free(mb);
1020 gsl_vector_free(eval);
1021 gsl_vector_free(evalv);
1024 gsl_vector_complex_free(work);
1025 gsl_matrix_complex_free(evec);
1026 gsl_eigen_genherm_free(w);
1027 gsl_eigen_genhermv_free(wv);
1031 } /* test_eigen_genherm() */
1033 /******************************************
1035 ******************************************/
1041 gsl_vector_complex *alpha;
1043 gsl_vector_complex *alphav;
1045 gsl_vector_complex *eval;
1046 gsl_vector_complex *evalv;
1051 gsl_matrix_complex *evec;
1052 gsl_eigen_gen_workspace *gen_p;
1053 gsl_eigen_genv_workspace *genv_p;
1054 } test_eigen_gen_workspace;
1056 test_eigen_gen_workspace *
1057 test_eigen_gen_alloc(const size_t n)
1059 test_eigen_gen_workspace *w;
1061 w = calloc(1, sizeof(test_eigen_gen_workspace));
1063 w->A = gsl_matrix_alloc(n, n);
1064 w->B = gsl_matrix_alloc(n, n);
1065 w->alpha = gsl_vector_complex_alloc(n);
1066 w->beta = gsl_vector_alloc(n);
1067 w->alphav = gsl_vector_complex_alloc(n);
1068 w->betav = gsl_vector_alloc(n);
1069 w->eval = gsl_vector_complex_alloc(n);
1070 w->evalv = gsl_vector_complex_alloc(n);
1071 w->x = gsl_vector_alloc(n);
1072 w->y = gsl_vector_alloc(n);
1073 w->Q = gsl_matrix_alloc(n, n);
1074 w->Z = gsl_matrix_alloc(n, n);
1075 w->evec = gsl_matrix_complex_alloc(n, n);
1076 w->gen_p = gsl_eigen_gen_alloc(n);
1077 w->genv_p = gsl_eigen_genv_alloc(n);
1080 } /* test_eigen_gen_alloc() */
1083 test_eigen_gen_free(test_eigen_gen_workspace *w)
1085 gsl_matrix_free(w->A);
1086 gsl_matrix_free(w->B);
1087 gsl_vector_complex_free(w->alpha);
1088 gsl_vector_free(w->beta);
1089 gsl_vector_complex_free(w->alphav);
1090 gsl_vector_free(w->betav);
1091 gsl_vector_complex_free(w->eval);
1092 gsl_vector_complex_free(w->evalv);
1093 gsl_vector_free(w->x);
1094 gsl_vector_free(w->y);
1095 gsl_matrix_free(w->Q);
1096 gsl_matrix_free(w->Z);
1097 gsl_matrix_complex_free(w->evec);
1098 gsl_eigen_gen_free(w->gen_p);
1099 gsl_eigen_genv_free(w->genv_p);
1101 } /* test_eigen_gen_free() */
1104 test_eigen_gen_results (const gsl_matrix * A, const gsl_matrix * B,
1105 const gsl_vector_complex * alpha,
1106 const gsl_vector * beta,
1107 const gsl_matrix_complex * evec,
1108 size_t count, const char * desc,
1111 const size_t N = A->size1;
1113 gsl_matrix_complex *ma, *mb;
1114 gsl_vector_complex *x, *y;
1115 gsl_complex z_one, z_zero;
1117 ma = gsl_matrix_complex_alloc(N, N);
1118 mb = gsl_matrix_complex_alloc(N, N);
1119 y = gsl_vector_complex_alloc(N);
1120 x = gsl_vector_complex_alloc(N);
1122 /* ma <- A, mb <- B */
1123 for (i = 0; i < N; ++i)
1125 for (j = 0; j < N; ++j)
1129 GSL_SET_COMPLEX(&z, gsl_matrix_get(A, i, j), 0.0);
1130 gsl_matrix_complex_set(ma, i, j, z);
1132 GSL_SET_COMPLEX(&z, gsl_matrix_get(B, i, j), 0.0);
1133 gsl_matrix_complex_set(mb, i, j, z);
1137 GSL_SET_COMPLEX(&z_one, 1.0, 0.0);
1138 GSL_SET_COMPLEX(&z_zero, 0.0, 0.0);
1140 /* check eigenvalues */
1141 for (i = 0; i < N; ++i)
1143 gsl_vector_complex_const_view vi =
1144 gsl_matrix_complex_const_column(evec, i);
1145 gsl_complex ai = gsl_vector_complex_get(alpha, i);
1146 double bi = gsl_vector_get(beta, i);
1148 /* compute x = alpha * B * v */
1149 gsl_blas_zgemv(CblasNoTrans, z_one, mb, &vi.vector, z_zero, x);
1150 gsl_blas_zscal(ai, x);
1152 /* compute y = beta * A v */
1153 gsl_blas_zgemv(CblasNoTrans, z_one, ma, &vi.vector, z_zero, y);
1154 gsl_blas_zdscal(bi, y);
1156 /* now test if y = x */
1157 for (j = 0; j < N; ++j)
1159 gsl_complex xj = gsl_vector_complex_get(x, j);
1160 gsl_complex yj = gsl_vector_complex_get(y, j);
1162 gsl_test_abs(GSL_REAL(yj), GSL_REAL(xj), 1e8*GSL_DBL_EPSILON,
1163 "gen(N=%u,cnt=%u), %s, eigenvalue(%d,%d), real, %s",
1164 N, count, desc, i, j, desc2);
1165 gsl_test_abs(GSL_IMAG(yj), GSL_IMAG(xj), 1e8*GSL_DBL_EPSILON,
1166 "gen(N=%u,cnt=%u), %s, eigenvalue(%d,%d), real, %s",
1167 N, count, desc, i, j, desc2);
1171 gsl_matrix_complex_free(ma);
1172 gsl_matrix_complex_free(mb);
1173 gsl_vector_complex_free(y);
1174 gsl_vector_complex_free(x);
1175 } /* test_eigen_gen_results() */
1178 test_eigen_gen_pencil(const gsl_matrix * A, const gsl_matrix * B,
1179 size_t count, const char * desc, int test_schur,
1180 test_eigen_gen_workspace *w)
1182 const size_t N = A->size1;
1185 gsl_matrix_memcpy(w->A, A);
1186 gsl_matrix_memcpy(w->B, B);
1190 gsl_eigen_genv_QZ(w->A, w->B, w->alphav, w->betav, w->evec, w->Q, w->Z, w->genv_p);
1191 test_eigen_schur(A, w->A, w->Q, w->Z, count, "genv/A", desc);
1192 test_eigen_schur(B, w->B, w->Q, w->Z, count, "genv/B", desc);
1195 gsl_eigen_genv(w->A, w->B, w->alphav, w->betav, w->evec, w->genv_p);
1197 test_eigen_gen_results(A, B, w->alphav, w->betav, w->evec, count, desc, "unsorted");
1199 gsl_matrix_memcpy(w->A, A);
1200 gsl_matrix_memcpy(w->B, B);
1204 gsl_eigen_gen_params(1, 1, 0, w->gen_p);
1205 gsl_eigen_gen_QZ(w->A, w->B, w->alpha, w->beta, w->Q, w->Z, w->gen_p);
1206 test_eigen_schur(A, w->A, w->Q, w->Z, count, "gen/A", desc);
1207 test_eigen_schur(B, w->B, w->Q, w->Z, count, "gen/B", desc);
1211 gsl_eigen_gen_params(0, 0, 0, w->gen_p);
1212 gsl_eigen_gen(w->A, w->B, w->alpha, w->beta, w->gen_p);
1215 /* compute eval = alpha / beta values */
1216 for (i = 0; i < N; ++i)
1221 ai = gsl_vector_complex_get(w->alpha, i);
1222 bi = gsl_vector_get(w->beta, i);
1223 GSL_SET_COMPLEX(&z, GSL_REAL(ai) / bi, GSL_IMAG(ai) / bi);
1224 gsl_vector_complex_set(w->eval, i, z);
1226 ai = gsl_vector_complex_get(w->alphav, i);
1227 bi = gsl_vector_get(w->betav, i);
1228 GSL_SET_COMPLEX(&z, GSL_REAL(ai) / bi, GSL_IMAG(ai) / bi);
1229 gsl_vector_complex_set(w->evalv, i, z);
1232 /* sort eval and evalv and test them */
1233 gsl_eigen_nonsymmv_sort(w->eval, NULL, GSL_EIGEN_SORT_ABS_ASC);
1234 gsl_eigen_nonsymmv_sort(w->evalv, NULL, GSL_EIGEN_SORT_ABS_ASC);
1235 test_eigenvalues_complex(w->evalv, w->eval, "gen", desc);
1237 gsl_eigen_genv_sort(w->alphav, w->betav, w->evec, GSL_EIGEN_SORT_ABS_ASC);
1238 test_eigen_gen_results(A, B, w->alphav, w->betav, w->evec, count, desc, "abs/asc");
1239 gsl_eigen_genv_sort(w->alphav, w->betav, w->evec, GSL_EIGEN_SORT_ABS_DESC);
1240 test_eigen_gen_results(A, B, w->alphav, w->betav, w->evec, count, desc, "abs/desc");
1241 } /* test_eigen_gen_pencil() */
1244 test_eigen_gen(void)
1248 gsl_rng *r = gsl_rng_alloc(gsl_rng_default);
1250 for (n = 1; n <= N_max; ++n)
1252 gsl_matrix * A = gsl_matrix_alloc(n, n);
1253 gsl_matrix * B = gsl_matrix_alloc(n, n);
1254 test_eigen_gen_workspace * w = test_eigen_gen_alloc(n);
1256 for (i = 0; i < 5; ++i)
1258 create_random_nonsymm_matrix(A, r, -10, 10);
1259 create_random_nonsymm_matrix(B, r, -10, 10);
1261 test_eigen_gen_pencil(A, B, i, "random", 0, w);
1262 test_eigen_gen_pencil(A, B, i, "random", 1, w);
1267 test_eigen_gen_free(w);
1272 /* this system will test the exceptional shift code */
1274 double datA[] = { 1, 1, 0,
1277 double datB[] = { -1, 0, -1,
1280 gsl_matrix_view va = gsl_matrix_view_array (datA, 3, 3);
1281 gsl_matrix_view vb = gsl_matrix_view_array (datB, 3, 3);
1282 test_eigen_gen_workspace * w = test_eigen_gen_alloc(3);
1284 test_eigen_gen_pencil(&va.matrix, &vb.matrix, 0, "integer", 0, w);
1285 test_eigen_gen_pencil(&va.matrix, &vb.matrix, 0, "integer", 1, w);
1287 test_eigen_gen_free(w);
1289 } /* test_eigen_gen() */
1294 gsl_ieee_env_setup ();
1295 gsl_rng_env_setup ();
1299 test_eigen_nonsymm();
1300 test_eigen_gensymm();
1301 test_eigen_genherm();
1304 exit (gsl_test_summary());