gsl_eigen__francis.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047
  1. /* eigen/francis.c
  2. *
  3. * Copyright (C) 2006, 2007 Patrick Alken
  4. *
  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.
  9. *
  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.
  14. *
  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.
  18. */
  19. #include "gsl__config.h"
  20. #include <stdlib.h>
  21. #include <math.h>
  22. #include "gsl_eigen.h"
  23. #include "gsl_linalg.h"
  24. #include "gsl_math.h"
  25. #include "gsl_blas.h"
  26. #include "gsl_vector.h"
  27. #include "gsl_vector_complex.h"
  28. #include "gsl_matrix.h"
  29. #include "gsl_cblas.h"
  30. #include "gsl_complex.h"
  31. #include "gsl_complex_math.h"
  32. /*
  33. * This module computes the eigenvalues of a real upper hessenberg
  34. * matrix, using the classical double shift Francis QR algorithm.
  35. * It will also optionally compute the full Schur form and matrix of
  36. * Schur vectors.
  37. *
  38. * See Golub & Van Loan, "Matrix Computations" (3rd ed),
  39. * algorithm 7.5.2
  40. */
  41. /* exceptional shift coefficients - these values are from LAPACK DLAHQR */
  42. #define GSL_FRANCIS_COEFF1 (0.75)
  43. #define GSL_FRANCIS_COEFF2 (-0.4375)
  44. static inline void francis_schur_decomp(gsl_matrix * H,
  45. gsl_vector_complex * eval,
  46. gsl_eigen_francis_workspace * w);
  47. static inline size_t francis_search_subdiag_small_elements(gsl_matrix * A);
  48. static inline int francis_qrstep(gsl_matrix * H,
  49. gsl_eigen_francis_workspace * w);
  50. static inline void francis_schur_standardize(gsl_matrix *A,
  51. gsl_complex *eval1,
  52. gsl_complex *eval2,
  53. gsl_eigen_francis_workspace *w);
  54. static inline size_t francis_get_submatrix(gsl_matrix *A, gsl_matrix *B);
  55. static void francis_standard_form(gsl_matrix *A, double *cs, double *sn);
  56. /*
  57. gsl_eigen_francis_alloc()
  58. Allocate a workspace for solving the nonsymmetric eigenvalue problem.
  59. The size of this workspace is O(1)
  60. Inputs: none
  61. Return: pointer to workspace
  62. */
  63. gsl_eigen_francis_workspace *
  64. gsl_eigen_francis_alloc(void)
  65. {
  66. gsl_eigen_francis_workspace *w;
  67. w = (gsl_eigen_francis_workspace *)
  68. calloc (1, sizeof (gsl_eigen_francis_workspace));
  69. if (w == 0)
  70. {
  71. GSL_ERROR_NULL ("failed to allocate space for workspace", GSL_ENOMEM);
  72. }
  73. /* these are filled in later */
  74. w->size = 0;
  75. w->max_iterations = 0;
  76. w->n_iter = 0;
  77. w->n_evals = 0;
  78. w->compute_t = 0;
  79. w->Z = NULL;
  80. w->H = NULL;
  81. return (w);
  82. } /* gsl_eigen_francis_alloc() */
  83. /*
  84. gsl_eigen_francis_free()
  85. Free francis workspace w
  86. */
  87. void
  88. gsl_eigen_francis_free (gsl_eigen_francis_workspace *w)
  89. {
  90. free(w);
  91. } /* gsl_eigen_francis_free() */
  92. /*
  93. gsl_eigen_francis_T()
  94. Called when we want to compute the Schur form T, or no longer
  95. compute the Schur form T
  96. Inputs: compute_t - 1 to compute T, 0 to not compute T
  97. w - francis workspace
  98. */
  99. void
  100. gsl_eigen_francis_T (const int compute_t, gsl_eigen_francis_workspace *w)
  101. {
  102. w->compute_t = compute_t;
  103. }
  104. /*
  105. gsl_eigen_francis()
  106. Solve the nonsymmetric eigenvalue problem
  107. H x = \lambda x
  108. for the eigenvalues \lambda using algorithm 7.5.2 of
  109. Golub & Van Loan, "Matrix Computations" (3rd ed)
  110. Inputs: H - upper hessenberg matrix
  111. eval - where to store eigenvalues
  112. w - workspace
  113. Return: success or error - if error code is returned,
  114. then the QR procedure did not converge in the
  115. allowed number of iterations. In the event of non-
  116. convergence, the number of eigenvalues found will
  117. still be stored in the beginning of eval,
  118. Notes: On output, the diagonal of H contains 1-by-1 or 2-by-2
  119. blocks containing the eigenvalues. If T is desired,
  120. H will contain the full Schur form on output.
  121. */
  122. int
  123. gsl_eigen_francis (gsl_matrix * H, gsl_vector_complex * eval,
  124. gsl_eigen_francis_workspace * w)
  125. {
  126. /* check matrix and vector sizes */
  127. if (H->size1 != H->size2)
  128. {
  129. GSL_ERROR ("matrix must be square to compute eigenvalues", GSL_ENOTSQR);
  130. }
  131. else if (eval->size != H->size1)
  132. {
  133. GSL_ERROR ("eigenvalue vector must match matrix size", GSL_EBADLEN);
  134. }
  135. else
  136. {
  137. const size_t N = H->size1;
  138. int j;
  139. /*
  140. * Set internal parameters which depend on matrix size.
  141. * The Francis solver can be called with any size matrix
  142. * since the workspace does not depend on N.
  143. * Furthermore, multishift solvers which call the Francis
  144. * solver may need to call it with different sized matrices
  145. */
  146. w->size = N;
  147. w->max_iterations = 30 * N;
  148. /*
  149. * save a pointer to original matrix since francis_schur_decomp
  150. * is recursive
  151. */
  152. w->H = H;
  153. w->n_iter = 0;
  154. w->n_evals = 0;
  155. /*
  156. * zero out the first two subdiagonals (below the main subdiagonal)
  157. * needed as scratch space by the QR sweep routine
  158. */
  159. for (j = 0; j < (int) N - 3; ++j)
  160. {
  161. gsl_matrix_set(H, (size_t) j + 2, (size_t) j, 0.0);
  162. gsl_matrix_set(H, (size_t) j + 3, (size_t) j, 0.0);
  163. }
  164. if (N > 2)
  165. gsl_matrix_set(H, N - 1, N - 3, 0.0);
  166. /*
  167. * compute Schur decomposition of H and store eigenvalues
  168. * into eval
  169. */
  170. francis_schur_decomp(H, eval, w);
  171. if (w->n_evals != N)
  172. return GSL_EMAXITER;
  173. return GSL_SUCCESS;
  174. }
  175. } /* gsl_eigen_francis() */
  176. /*
  177. gsl_eigen_francis_Z()
  178. Solve the nonsymmetric eigenvalue problem for a Hessenberg
  179. matrix
  180. H x = \lambda x
  181. for the eigenvalues \lambda using the Francis double-shift
  182. method.
  183. Here we compute the real Schur form
  184. T = Q^t H Q
  185. with the diagonal blocks of T giving us the eigenvalues.
  186. Q is the matrix of Schur vectors.
  187. Originally, H was obtained from a general nonsymmetric matrix
  188. A via a transformation
  189. H = U^t A U
  190. so that
  191. T = (UQ)^t A (UQ) = Z^t A Z
  192. Z is the matrix of Schur vectors computed by this algorithm
  193. Inputs: H - upper hessenberg matrix
  194. eval - where to store eigenvalues
  195. Z - where to store Schur vectors
  196. w - workspace
  197. Notes: 1) If T is computed, it is stored in H on output. Otherwise,
  198. the diagonal of H will contain 1-by-1 and 2-by-2 blocks
  199. containing the eigenvalues.
  200. 2) The matrix Z must be initialized to the Hessenberg
  201. similarity matrix U. Or if you want the eigenvalues
  202. of H, initialize Z to the identity matrix.
  203. */
  204. int
  205. gsl_eigen_francis_Z (gsl_matrix * H, gsl_vector_complex * eval,
  206. gsl_matrix * Z, gsl_eigen_francis_workspace * w)
  207. {
  208. int s;
  209. /* set internal Z pointer so we know to accumulate transformations */
  210. w->Z = Z;
  211. s = gsl_eigen_francis(H, eval, w);
  212. w->Z = NULL;
  213. return s;
  214. } /* gsl_eigen_francis_Z() */
  215. /********************************************
  216. * INTERNAL ROUTINES *
  217. ********************************************/
  218. /*
  219. francis_schur_decomp()
  220. Compute the Schur decomposition of the matrix H
  221. Inputs: H - hessenberg matrix
  222. eval - where to store eigenvalues
  223. w - workspace
  224. Return: none
  225. */
  226. static inline void
  227. francis_schur_decomp(gsl_matrix * H, gsl_vector_complex * eval,
  228. gsl_eigen_francis_workspace * w)
  229. {
  230. gsl_matrix_view m; /* active matrix we are working on */
  231. size_t N; /* size of matrix */
  232. size_t q; /* index of small subdiagonal element */
  233. gsl_complex lambda1, /* eigenvalues */
  234. lambda2;
  235. N = H->size1;
  236. m = gsl_matrix_submatrix(H, 0, 0, N, N);
  237. while ((N > 2) && ((w->n_iter)++ < w->max_iterations))
  238. {
  239. q = francis_search_subdiag_small_elements(&m.matrix);
  240. if (q == 0)
  241. {
  242. /*
  243. * no small subdiagonal element found - perform a QR
  244. * sweep on the active reduced hessenberg matrix
  245. */
  246. francis_qrstep(&m.matrix, w);
  247. continue;
  248. }
  249. /*
  250. * a small subdiagonal element was found - one or two eigenvalues
  251. * have converged or the matrix has split into two smaller matrices
  252. */
  253. if (q == (N - 1))
  254. {
  255. /*
  256. * the last subdiagonal element of the matrix is 0 -
  257. * m_{NN} is a real eigenvalue
  258. */
  259. GSL_SET_COMPLEX(&lambda1,
  260. gsl_matrix_get(&m.matrix, q, q), 0.0);
  261. gsl_vector_complex_set(eval, w->n_evals, lambda1);
  262. w->n_evals += 1;
  263. w->n_iter = 0;
  264. --N;
  265. m = gsl_matrix_submatrix(&m.matrix, 0, 0, N, N);
  266. }
  267. else if (q == (N - 2))
  268. {
  269. gsl_matrix_view v;
  270. /*
  271. * The bottom right 2-by-2 block of m is an eigenvalue
  272. * system
  273. */
  274. v = gsl_matrix_submatrix(&m.matrix, q, q, 2, 2);
  275. francis_schur_standardize(&v.matrix, &lambda1, &lambda2, w);
  276. gsl_vector_complex_set(eval, w->n_evals, lambda1);
  277. gsl_vector_complex_set(eval, w->n_evals + 1, lambda2);
  278. w->n_evals += 2;
  279. w->n_iter = 0;
  280. N -= 2;
  281. m = gsl_matrix_submatrix(&m.matrix, 0, 0, N, N);
  282. }
  283. else if (q == 1)
  284. {
  285. /* the first matrix element is an eigenvalue */
  286. GSL_SET_COMPLEX(&lambda1,
  287. gsl_matrix_get(&m.matrix, 0, 0), 0.0);
  288. gsl_vector_complex_set(eval, w->n_evals, lambda1);
  289. w->n_evals += 1;
  290. w->n_iter = 0;
  291. --N;
  292. m = gsl_matrix_submatrix(&m.matrix, 1, 1, N, N);
  293. }
  294. else if (q == 2)
  295. {
  296. gsl_matrix_view v;
  297. /* the upper left 2-by-2 block is an eigenvalue system */
  298. v = gsl_matrix_submatrix(&m.matrix, 0, 0, 2, 2);
  299. francis_schur_standardize(&v.matrix, &lambda1, &lambda2, w);
  300. gsl_vector_complex_set(eval, w->n_evals, lambda1);
  301. gsl_vector_complex_set(eval, w->n_evals + 1, lambda2);
  302. w->n_evals += 2;
  303. w->n_iter = 0;
  304. N -= 2;
  305. m = gsl_matrix_submatrix(&m.matrix, 2, 2, N, N);
  306. }
  307. else
  308. {
  309. gsl_matrix_view v;
  310. /*
  311. * There is a zero element on the subdiagonal somewhere
  312. * in the middle of the matrix - we can now operate
  313. * separately on the two submatrices split by this
  314. * element. q is the row index of the zero element.
  315. */
  316. /* operate on lower right (N - q)-by-(N - q) block first */
  317. v = gsl_matrix_submatrix(&m.matrix, q, q, N - q, N - q);
  318. francis_schur_decomp(&v.matrix, eval, w);
  319. /* operate on upper left q-by-q block */
  320. v = gsl_matrix_submatrix(&m.matrix, 0, 0, q, q);
  321. francis_schur_decomp(&v.matrix, eval, w);
  322. N = 0;
  323. }
  324. }
  325. /* handle special cases of N = 1 or 2 */
  326. if (N == 1)
  327. {
  328. GSL_SET_COMPLEX(&lambda1, gsl_matrix_get(&m.matrix, 0, 0), 0.0);
  329. gsl_vector_complex_set(eval, w->n_evals, lambda1);
  330. w->n_evals += 1;
  331. w->n_iter = 0;
  332. }
  333. else if (N == 2)
  334. {
  335. francis_schur_standardize(&m.matrix, &lambda1, &lambda2, w);
  336. gsl_vector_complex_set(eval, w->n_evals, lambda1);
  337. gsl_vector_complex_set(eval, w->n_evals + 1, lambda2);
  338. w->n_evals += 2;
  339. w->n_iter = 0;
  340. }
  341. } /* francis_schur_decomp() */
  342. /*
  343. francis_qrstep()
  344. Perform a Francis QR step.
  345. See Golub & Van Loan, "Matrix Computations" (3rd ed),
  346. algorithm 7.5.1
  347. Inputs: H - upper Hessenberg matrix
  348. w - workspace
  349. Notes: The matrix H must be "reduced", ie: have no tiny subdiagonal
  350. elements. When computing the first householder reflection,
  351. we divide by H_{21} so it is necessary that this element
  352. is not zero. When a subdiagonal element becomes negligible,
  353. the calling function should call this routine with the
  354. submatrices split by that element, so that we don't divide
  355. by zeros.
  356. */
  357. static inline int
  358. francis_qrstep(gsl_matrix * H, gsl_eigen_francis_workspace * w)
  359. {
  360. const size_t N = H->size1;
  361. size_t i; /* looping */
  362. gsl_matrix_view m;
  363. double tau_i; /* householder coefficient */
  364. double dat[3]; /* householder vector */
  365. double scale; /* scale factor to avoid overflow */
  366. gsl_vector_view v2, v3;
  367. size_t q, r;
  368. size_t top = 0; /* location of H in original matrix */
  369. double s,
  370. disc;
  371. double h_nn, /* H(n,n) */
  372. h_nm1nm1, /* H(n-1,n-1) */
  373. h_cross, /* H(n,n-1) * H(n-1,n) */
  374. h_tmp1,
  375. h_tmp2;
  376. v2 = gsl_vector_view_array(dat, 2);
  377. v3 = gsl_vector_view_array(dat, 3);
  378. if ((w->n_iter % 10) == 0)
  379. {
  380. /*
  381. * exceptional shifts: we have gone 10 iterations
  382. * without finding a new eigenvalue, try a new choice of shifts.
  383. * See LAPACK routine DLAHQR
  384. */
  385. s = fabs(gsl_matrix_get(H, N - 1, N - 2)) +
  386. fabs(gsl_matrix_get(H, N - 2, N - 3));
  387. h_nn = gsl_matrix_get(H, N - 1, N - 1) + GSL_FRANCIS_COEFF1 * s;
  388. h_nm1nm1 = h_nn;
  389. h_cross = GSL_FRANCIS_COEFF2 * s * s;
  390. }
  391. else
  392. {
  393. /*
  394. * normal shifts - compute Rayleigh quotient and use
  395. * Wilkinson shift if possible
  396. */
  397. h_nn = gsl_matrix_get(H, N - 1, N - 1);
  398. h_nm1nm1 = gsl_matrix_get(H, N - 2, N - 2);
  399. h_cross = gsl_matrix_get(H, N - 1, N - 2) *
  400. gsl_matrix_get(H, N - 2, N - 1);
  401. disc = 0.5 * (h_nm1nm1 - h_nn);
  402. disc = disc * disc + h_cross;
  403. if (disc > 0.0)
  404. {
  405. double ave;
  406. /* real roots - use Wilkinson's shift twice */
  407. disc = sqrt(disc);
  408. ave = 0.5 * (h_nm1nm1 + h_nn);
  409. if (fabs(h_nm1nm1) - fabs(h_nn) > 0.0)
  410. {
  411. h_nm1nm1 = h_nm1nm1 * h_nn - h_cross;
  412. h_nn = h_nm1nm1 / (disc * GSL_SIGN(ave) + ave);
  413. }
  414. else
  415. {
  416. h_nn = disc * GSL_SIGN(ave) + ave;
  417. }
  418. h_nm1nm1 = h_nn;
  419. h_cross = 0.0;
  420. }
  421. }
  422. h_tmp1 = h_nm1nm1 - gsl_matrix_get(H, 0, 0);
  423. h_tmp2 = h_nn - gsl_matrix_get(H, 0, 0);
  424. /*
  425. * These formulas are equivalent to those in Golub & Van Loan
  426. * for the normal shift case - the terms have been rearranged
  427. * to reduce possible roundoff error when subdiagonal elements
  428. * are small
  429. */
  430. dat[0] = (h_tmp1*h_tmp2 - h_cross) / gsl_matrix_get(H, 1, 0) +
  431. gsl_matrix_get(H, 0, 1);
  432. dat[1] = gsl_matrix_get(H, 1, 1) - gsl_matrix_get(H, 0, 0) - h_tmp1 -
  433. h_tmp2;
  434. dat[2] = gsl_matrix_get(H, 2, 1);
  435. scale = fabs(dat[0]) + fabs(dat[1]) + fabs(dat[2]);
  436. if (scale != 0.0)
  437. {
  438. /* scale to prevent overflow or underflow */
  439. dat[0] /= scale;
  440. dat[1] /= scale;
  441. dat[2] /= scale;
  442. }
  443. if (w->Z || w->compute_t)
  444. {
  445. /*
  446. * get absolute indices of this (sub)matrix relative to the
  447. * original Hessenberg matrix
  448. */
  449. top = francis_get_submatrix(w->H, H);
  450. }
  451. for (i = 0; i < N - 2; ++i)
  452. {
  453. tau_i = gsl_linalg_householder_transform(&v3.vector);
  454. if (tau_i != 0.0)
  455. {
  456. /* q = max(1, i - 1) */
  457. q = (1 > ((int)i - 1)) ? 0 : (i - 1);
  458. /* r = min(i + 3, N - 1) */
  459. r = ((i + 3) < (N - 1)) ? (i + 3) : (N - 1);
  460. if (w->compute_t)
  461. {
  462. /*
  463. * We are computing the Schur form T, so we
  464. * need to transform the whole matrix H
  465. *
  466. * H -> P_k^t H P_k
  467. *
  468. * where P_k is the current Householder matrix
  469. */
  470. /* apply left householder matrix (I - tau_i v v') to H */
  471. m = gsl_matrix_submatrix(w->H,
  472. top + i,
  473. top + q,
  474. 3,
  475. w->size - top - q);
  476. gsl_linalg_householder_hm(tau_i, &v3.vector, &m.matrix);
  477. /* apply right householder matrix (I - tau_i v v') to H */
  478. m = gsl_matrix_submatrix(w->H,
  479. 0,
  480. top + i,
  481. top + r + 1,
  482. 3);
  483. gsl_linalg_householder_mh(tau_i, &v3.vector, &m.matrix);
  484. }
  485. else
  486. {
  487. /*
  488. * We are not computing the Schur form T, so we
  489. * only need to transform the active block
  490. */
  491. /* apply left householder matrix (I - tau_i v v') to H */
  492. m = gsl_matrix_submatrix(H, i, q, 3, N - q);
  493. gsl_linalg_householder_hm(tau_i, &v3.vector, &m.matrix);
  494. /* apply right householder matrix (I - tau_i v v') to H */
  495. m = gsl_matrix_submatrix(H, 0, i, r + 1, 3);
  496. gsl_linalg_householder_mh(tau_i, &v3.vector, &m.matrix);
  497. }
  498. if (w->Z)
  499. {
  500. /* accumulate the similarity transformation into Z */
  501. m = gsl_matrix_submatrix(w->Z, 0, top + i, w->size, 3);
  502. gsl_linalg_householder_mh(tau_i, &v3.vector, &m.matrix);
  503. }
  504. } /* if (tau_i != 0.0) */
  505. dat[0] = gsl_matrix_get(H, i + 1, i);
  506. dat[1] = gsl_matrix_get(H, i + 2, i);
  507. if (i < (N - 3))
  508. {
  509. dat[2] = gsl_matrix_get(H, i + 3, i);
  510. }
  511. scale = fabs(dat[0]) + fabs(dat[1]) + fabs(dat[2]);
  512. if (scale != 0.0)
  513. {
  514. /* scale to prevent overflow or underflow */
  515. dat[0] /= scale;
  516. dat[1] /= scale;
  517. dat[2] /= scale;
  518. }
  519. } /* for (i = 0; i < N - 2; ++i) */
  520. scale = fabs(dat[0]) + fabs(dat[1]);
  521. if (scale != 0.0)
  522. {
  523. /* scale to prevent overflow or underflow */
  524. dat[0] /= scale;
  525. dat[1] /= scale;
  526. }
  527. tau_i = gsl_linalg_householder_transform(&v2.vector);
  528. if (w->compute_t)
  529. {
  530. m = gsl_matrix_submatrix(w->H,
  531. top + N - 2,
  532. top + N - 3,
  533. 2,
  534. w->size - top - N + 3);
  535. gsl_linalg_householder_hm(tau_i, &v2.vector, &m.matrix);
  536. m = gsl_matrix_submatrix(w->H,
  537. 0,
  538. top + N - 2,
  539. top + N,
  540. 2);
  541. gsl_linalg_householder_mh(tau_i, &v2.vector, &m.matrix);
  542. }
  543. else
  544. {
  545. m = gsl_matrix_submatrix(H, N - 2, N - 3, 2, 3);
  546. gsl_linalg_householder_hm(tau_i, &v2.vector, &m.matrix);
  547. m = gsl_matrix_submatrix(H, 0, N - 2, N, 2);
  548. gsl_linalg_householder_mh(tau_i, &v2.vector, &m.matrix);
  549. }
  550. if (w->Z)
  551. {
  552. /* accumulate transformation into Z */
  553. m = gsl_matrix_submatrix(w->Z, 0, top + N - 2, w->size, 2);
  554. gsl_linalg_householder_mh(tau_i, &v2.vector, &m.matrix);
  555. }
  556. return GSL_SUCCESS;
  557. } /* francis_qrstep() */
  558. /*
  559. francis_search_subdiag_small_elements()
  560. Search for a small subdiagonal element starting from the bottom
  561. of a matrix A. A small element is one that satisfies:
  562. |A_{i,i-1}| <= eps * (|A_{i,i}| + |A_{i-1,i-1}|)
  563. Inputs: A - matrix (must be at least 3-by-3)
  564. Return: row index of small subdiagonal element or 0 if not found
  565. Notes: the first small element that is found (starting from bottom)
  566. is set to zero
  567. */
  568. static inline size_t
  569. francis_search_subdiag_small_elements(gsl_matrix * A)
  570. {
  571. const size_t N = A->size1;
  572. size_t i;
  573. double dpel = gsl_matrix_get(A, N - 2, N - 2);
  574. for (i = N - 1; i > 0; --i)
  575. {
  576. double sel = gsl_matrix_get(A, i, i - 1);
  577. double del = gsl_matrix_get(A, i, i);
  578. if ((sel == 0.0) ||
  579. (fabs(sel) < GSL_DBL_EPSILON * (fabs(del) + fabs(dpel))))
  580. {
  581. gsl_matrix_set(A, i, i - 1, 0.0);
  582. return (i);
  583. }
  584. dpel = del;
  585. }
  586. return (0);
  587. } /* francis_search_subdiag_small_elements() */
  588. /*
  589. francis_schur_standardize()
  590. Convert a 2-by-2 diagonal block in the Schur form to standard form
  591. and update the rest of T and Z matrices if required.
  592. Inputs: A - 2-by-2 matrix
  593. eval1 - where to store eigenvalue 1
  594. eval2 - where to store eigenvalue 2
  595. w - francis workspace
  596. */
  597. static inline void
  598. francis_schur_standardize(gsl_matrix *A, gsl_complex *eval1,
  599. gsl_complex *eval2,
  600. gsl_eigen_francis_workspace *w)
  601. {
  602. const size_t N = w->size;
  603. double cs, sn;
  604. size_t top;
  605. /*
  606. * figure out where the submatrix A resides in the
  607. * original matrix H
  608. */
  609. top = francis_get_submatrix(w->H, A);
  610. /* convert 2-by-2 block to standard form */
  611. francis_standard_form(A, &cs, &sn);
  612. /* set eigenvalues */
  613. GSL_SET_REAL(eval1, gsl_matrix_get(A, 0, 0));
  614. GSL_SET_REAL(eval2, gsl_matrix_get(A, 1, 1));
  615. if (gsl_matrix_get(A, 1, 0) == 0.0)
  616. {
  617. GSL_SET_IMAG(eval1, 0.0);
  618. GSL_SET_IMAG(eval2, 0.0);
  619. }
  620. else
  621. {
  622. double tmp = sqrt(fabs(gsl_matrix_get(A, 0, 1)) *
  623. fabs(gsl_matrix_get(A, 1, 0)));
  624. GSL_SET_IMAG(eval1, tmp);
  625. GSL_SET_IMAG(eval2, -tmp);
  626. }
  627. if (w->compute_t)
  628. {
  629. gsl_vector_view xv, yv;
  630. /*
  631. * The above call to francis_standard_form transformed a 2-by-2 block
  632. * of T into upper triangular form via the transformation
  633. *
  634. * U = [ CS -SN ]
  635. * [ SN CS ]
  636. *
  637. * The original matrix T was
  638. *
  639. * T = [ T_{11} | T_{12} | T_{13} ]
  640. * [ 0* | A | T_{23} ]
  641. * [ 0 | 0* | T_{33} ]
  642. *
  643. * where 0* indicates all zeros except for possibly
  644. * one subdiagonal element next to A.
  645. *
  646. * After francis_standard_form, T looks like this:
  647. *
  648. * T = [ T_{11} | T_{12} | T_{13} ]
  649. * [ 0* | U^t A U | T_{23} ]
  650. * [ 0 | 0* | T_{33} ]
  651. *
  652. * since only the 2-by-2 block of A was changed. However,
  653. * in order to be able to back transform T at the end,
  654. * we need to apply the U transformation to the rest
  655. * of the matrix T since there is no way to apply a
  656. * similarity transformation to T and change only the
  657. * middle 2-by-2 block. In other words, let
  658. *
  659. * M = [ I 0 0 ]
  660. * [ 0 U 0 ]
  661. * [ 0 0 I ]
  662. *
  663. * and compute
  664. *
  665. * M^t T M = [ T_{11} | T_{12} U | T_{13} ]
  666. * [ U^t 0* | U^t A U | U^t T_{23} ]
  667. * [ 0 | 0* U | T_{33} ]
  668. *
  669. * So basically we need to apply the transformation U
  670. * to the i x 2 matrix T_{12} and the 2 x (n - i + 2)
  671. * matrix T_{23}, where i is the index of the top of A
  672. * in T.
  673. *
  674. * The BLAS routine drot() is suited for this.
  675. */
  676. if (top < (N - 2))
  677. {
  678. /* transform the 2 rows of T_{23} */
  679. xv = gsl_matrix_subrow(w->H, top, top + 2, N - top - 2);
  680. yv = gsl_matrix_subrow(w->H, top + 1, top + 2, N - top - 2);
  681. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  682. }
  683. if (top > 0)
  684. {
  685. /* transform the 2 columns of T_{12} */
  686. xv = gsl_matrix_subcolumn(w->H, top, 0, top);
  687. yv = gsl_matrix_subcolumn(w->H, top + 1, 0, top);
  688. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  689. }
  690. } /* if (w->compute_t) */
  691. if (w->Z)
  692. {
  693. gsl_vector_view xv, yv;
  694. /*
  695. * Accumulate the transformation in Z. Here, Z -> Z * M
  696. *
  697. * So:
  698. *
  699. * Z -> [ Z_{11} | Z_{12} U | Z_{13} ]
  700. * [ Z_{21} | Z_{22} U | Z_{23} ]
  701. * [ Z_{31} | Z_{32} U | Z_{33} ]
  702. *
  703. * So we just need to apply drot() to the 2 columns
  704. * starting at index 'top'
  705. */
  706. xv = gsl_matrix_column(w->Z, top);
  707. yv = gsl_matrix_column(w->Z, top + 1);
  708. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  709. } /* if (w->Z) */
  710. } /* francis_schur_standardize() */
  711. /*
  712. francis_get_submatrix()
  713. B is a submatrix of A. The goal of this function is to
  714. compute the indices in A of where the matrix B resides
  715. */
  716. static inline size_t
  717. francis_get_submatrix(gsl_matrix *A, gsl_matrix *B)
  718. {
  719. size_t diff;
  720. double ratio;
  721. size_t top;
  722. diff = (size_t) (B->data - A->data);
  723. ratio = (double)diff / ((double) (A->tda + 1));
  724. top = (size_t) floor(ratio);
  725. return top;
  726. } /* francis_get_submatrix() */
  727. /*
  728. francis_standard_form()
  729. Compute the Schur factorization of a real 2-by-2 matrix in
  730. standard form:
  731. [ A B ] = [ CS -SN ] [ T11 T12 ] [ CS SN ]
  732. [ C D ] [ SN CS ] [ T21 T22 ] [-SN CS ]
  733. where either:
  734. 1) T21 = 0 so that T11 and T22 are real eigenvalues of the matrix, or
  735. 2) T11 = T22 and T21*T12 < 0, so that T11 +/- sqrt(|T21*T12|) are
  736. complex conjugate eigenvalues
  737. Inputs: A - 2-by-2 matrix
  738. cs - where to store cosine parameter of rotation matrix
  739. sn - where to store sine parameter of rotation matrix
  740. Notes: 1) based on LAPACK routine DLANV2
  741. 2) On output, A is modified to contain the matrix in standard form
  742. */
  743. static void
  744. francis_standard_form(gsl_matrix *A, double *cs, double *sn)
  745. {
  746. double a, b, c, d; /* input matrix values */
  747. double tmp;
  748. double p, z;
  749. double bcmax, bcmis, scale;
  750. double tau, sigma;
  751. double cs1, sn1;
  752. double aa, bb, cc, dd;
  753. double sab, sac;
  754. a = gsl_matrix_get(A, 0, 0);
  755. b = gsl_matrix_get(A, 0, 1);
  756. c = gsl_matrix_get(A, 1, 0);
  757. d = gsl_matrix_get(A, 1, 1);
  758. if (c == 0.0)
  759. {
  760. /*
  761. * matrix is already upper triangular - set rotation matrix
  762. * to the identity
  763. */
  764. *cs = 1.0;
  765. *sn = 0.0;
  766. }
  767. else if (b == 0.0)
  768. {
  769. /* swap rows and columns to make it upper triangular */
  770. *cs = 0.0;
  771. *sn = 1.0;
  772. tmp = d;
  773. d = a;
  774. a = tmp;
  775. b = -c;
  776. c = 0.0;
  777. }
  778. else if (((a - d) == 0.0) && (GSL_SIGN(b) != GSL_SIGN(c)))
  779. {
  780. /* the matrix has complex eigenvalues with a == d */
  781. *cs = 1.0;
  782. *sn = 0.0;
  783. }
  784. else
  785. {
  786. tmp = a - d;
  787. p = 0.5 * tmp;
  788. bcmax = GSL_MAX(fabs(b), fabs(c));
  789. bcmis = GSL_MIN(fabs(b), fabs(c)) * GSL_SIGN(b) * GSL_SIGN(c);
  790. scale = GSL_MAX(fabs(p), bcmax);
  791. z = (p / scale) * p + (bcmax / scale) * bcmis;
  792. if (z >= 4.0 * GSL_DBL_EPSILON)
  793. {
  794. /* real eigenvalues, compute a and d */
  795. z = p + GSL_SIGN(p) * fabs(sqrt(scale) * sqrt(z));
  796. a = d + z;
  797. d -= (bcmax / z) * bcmis;
  798. /* compute b and the rotation matrix */
  799. tau = gsl_hypot(c, z);
  800. *cs = z / tau;
  801. *sn = c / tau;
  802. b -= c;
  803. c = 0.0;
  804. }
  805. else
  806. {
  807. /*
  808. * complex eigenvalues, or real (almost) equal eigenvalues -
  809. * make diagonal elements equal
  810. */
  811. sigma = b + c;
  812. tau = gsl_hypot(sigma, tmp);
  813. *cs = sqrt(0.5 * (1.0 + fabs(sigma) / tau));
  814. *sn = -(p / (tau * (*cs))) * GSL_SIGN(sigma);
  815. /*
  816. * Compute [ AA BB ] = [ A B ] [ CS -SN ]
  817. * [ CC DD ] [ C D ] [ SN CS ]
  818. */
  819. aa = a * (*cs) + b * (*sn);
  820. bb = -a * (*sn) + b * (*cs);
  821. cc = c * (*cs) + d * (*sn);
  822. dd = -c * (*sn) + d * (*cs);
  823. /*
  824. * Compute [ A B ] = [ CS SN ] [ AA BB ]
  825. * [ C D ] [-SN CS ] [ CC DD ]
  826. */
  827. a = aa * (*cs) + cc * (*sn);
  828. b = bb * (*cs) + dd * (*sn);
  829. c = -aa * (*sn) + cc * (*cs);
  830. d = -bb * (*sn) + dd * (*cs);
  831. tmp = 0.5 * (a + d);
  832. a = d = tmp;
  833. if (c != 0.0)
  834. {
  835. if (b != 0.0)
  836. {
  837. if (GSL_SIGN(b) == GSL_SIGN(c))
  838. {
  839. /*
  840. * real eigenvalues: reduce to upper triangular
  841. * form
  842. */
  843. sab = sqrt(fabs(b));
  844. sac = sqrt(fabs(c));
  845. p = GSL_SIGN(c) * fabs(sab * sac);
  846. tau = 1.0 / sqrt(fabs(b + c));
  847. a = tmp + p;
  848. d = tmp - p;
  849. b -= c;
  850. c = 0.0;
  851. cs1 = sab * tau;
  852. sn1 = sac * tau;
  853. tmp = (*cs) * cs1 - (*sn) * sn1;
  854. *sn = (*cs) * sn1 + (*sn) * cs1;
  855. *cs = tmp;
  856. }
  857. }
  858. else
  859. {
  860. b = -c;
  861. c = 0.0;
  862. tmp = *cs;
  863. *cs = -(*sn);
  864. *sn = tmp;
  865. }
  866. }
  867. }
  868. }
  869. /* set new matrix elements */
  870. gsl_matrix_set(A, 0, 0, a);
  871. gsl_matrix_set(A, 0, 1, b);
  872. gsl_matrix_set(A, 1, 0, c);
  873. gsl_matrix_set(A, 1, 1, d);
  874. } /* francis_standard_form() */