gsl_eigen__gen.c 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115
  1. /* eigen/gen.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 <stdlib.h>
  20. #include <math.h>
  21. #include "gsl__config.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. /*
  30. * This module computes the eigenvalues of a real generalized
  31. * eigensystem A x = \lambda B x. Left and right Schur vectors
  32. * are optionally computed as well.
  33. *
  34. * Based on the algorithm from Moler and Stewart
  35. * [1] C. Moler, G. Stewart, "An Algorithm for Generalized Matrix
  36. * Eigenvalue Problems", SIAM J. Numer. Anal., Vol 10, No 2, 1973.
  37. *
  38. * This algorithm is also described in the book
  39. * [2] Golub & Van Loan, "Matrix Computations" (3rd ed), algorithm 7.7.3
  40. *
  41. * This file contains routines based on original code from LAPACK
  42. * which is distributed under the modified BSD license.
  43. */
  44. #define GEN_ESHIFT_COEFF (1.736)
  45. static void gen_schur_decomp(gsl_matrix *H, gsl_matrix *R,
  46. gsl_vector_complex *alpha, gsl_vector *beta,
  47. gsl_eigen_gen_workspace *w);
  48. static inline int gen_qzstep(gsl_matrix *H, gsl_matrix *R,
  49. gsl_eigen_gen_workspace *w);
  50. static inline void gen_qzstep_d(gsl_matrix *H, gsl_matrix *R,
  51. gsl_eigen_gen_workspace *w);
  52. static void gen_tri_split_top(gsl_matrix *H, gsl_matrix *R,
  53. gsl_eigen_gen_workspace *w);
  54. static inline void gen_tri_chase_zero(gsl_matrix *H, gsl_matrix *R,
  55. size_t q,
  56. gsl_eigen_gen_workspace *w);
  57. static inline void gen_tri_zero_H(gsl_matrix *H, gsl_matrix *R,
  58. gsl_eigen_gen_workspace *w);
  59. static inline size_t gen_search_small_elements(gsl_matrix *H,
  60. gsl_matrix *R,
  61. int *flag,
  62. gsl_eigen_gen_workspace *w);
  63. static int gen_schur_standardize1(gsl_matrix *A, gsl_matrix *B,
  64. double *alphar, double *beta,
  65. gsl_eigen_gen_workspace *w);
  66. static int gen_schur_standardize2(gsl_matrix *A, gsl_matrix *B,
  67. gsl_complex *alpha1,
  68. gsl_complex *alpha2,
  69. double *beta1, double *beta2,
  70. gsl_eigen_gen_workspace *w);
  71. static int gen_compute_eigenvals(gsl_matrix *A, gsl_matrix *B,
  72. gsl_complex *alpha1,
  73. gsl_complex *alpha2, double *beta1,
  74. double *beta2);
  75. static void gen_store_eigval1(const gsl_matrix *H, const double a,
  76. const double b, gsl_vector_complex *alpha,
  77. gsl_vector *beta,
  78. gsl_eigen_gen_workspace *w);
  79. static void gen_store_eigval2(const gsl_matrix *H,
  80. const gsl_complex *alpha1,
  81. const double beta1,
  82. const gsl_complex *alpha2,
  83. const double beta2,
  84. gsl_vector_complex *alpha,
  85. gsl_vector *beta,
  86. gsl_eigen_gen_workspace *w);
  87. static inline size_t gen_get_submatrix(const gsl_matrix *A,
  88. const gsl_matrix *B);
  89. /*FIX**/
  90. inline static double normF (gsl_matrix * A);
  91. inline static void create_givens (const double a, const double b, double *c, double *s);
  92. /*
  93. gsl_eigen_gen_alloc()
  94. Allocate a workspace for solving the generalized eigenvalue problem.
  95. The size of this workspace is O(n)
  96. Inputs: n - size of matrices
  97. Return: pointer to workspace
  98. */
  99. gsl_eigen_gen_workspace *
  100. gsl_eigen_gen_alloc(const size_t n)
  101. {
  102. gsl_eigen_gen_workspace *w;
  103. if (n == 0)
  104. {
  105. GSL_ERROR_NULL ("matrix dimension must be positive integer",
  106. GSL_EINVAL);
  107. }
  108. w = (gsl_eigen_gen_workspace *) calloc (1, sizeof (gsl_eigen_gen_workspace));
  109. if (w == 0)
  110. {
  111. GSL_ERROR_NULL ("failed to allocate space for workspace", GSL_ENOMEM);
  112. }
  113. w->size = n;
  114. w->max_iterations = 30 * n;
  115. w->n_evals = 0;
  116. w->n_iter = 0;
  117. w->needtop = 0;
  118. w->atol = 0.0;
  119. w->btol = 0.0;
  120. w->ascale = 0.0;
  121. w->bscale = 0.0;
  122. w->eshift = 0.0;
  123. w->H = NULL;
  124. w->R = NULL;
  125. w->compute_s = 0;
  126. w->compute_t = 0;
  127. w->Q = NULL;
  128. w->Z = NULL;
  129. w->work = gsl_vector_alloc(n);
  130. if (w->work == 0)
  131. {
  132. gsl_eigen_gen_free(w);
  133. GSL_ERROR_NULL ("failed to allocate space for additional workspace", GSL_ENOMEM);
  134. }
  135. return (w);
  136. } /* gsl_eigen_gen_alloc() */
  137. /*
  138. gsl_eigen_gen_free()
  139. Free workspace w
  140. */
  141. void
  142. gsl_eigen_gen_free (gsl_eigen_gen_workspace * w)
  143. {
  144. if (w->work)
  145. gsl_vector_free(w->work);
  146. free(w);
  147. } /* gsl_eigen_gen_free() */
  148. /*
  149. gsl_eigen_gen_params()
  150. Set parameters which define how we solve the eigenvalue problem
  151. Inputs: compute_s - 1 if we want to compute S, 0 if not
  152. compute_t - 1 if we want to compute T, 0 if not
  153. balance - 1 if we want to balance matrices, 0 if not
  154. w - gen workspace
  155. Return: none
  156. */
  157. void
  158. gsl_eigen_gen_params (const int compute_s, const int compute_t,
  159. const int balance, gsl_eigen_gen_workspace *w)
  160. {
  161. w->compute_s = compute_s;
  162. w->compute_t = compute_t;
  163. } /* gsl_eigen_gen_params() */
  164. /*
  165. gsl_eigen_gen()
  166. Solve the generalized eigenvalue problem
  167. A x = \lambda B x
  168. for the eigenvalues \lambda.
  169. Inputs: A - general real matrix
  170. B - general real matrix
  171. alpha - where to store eigenvalue numerators
  172. beta - where to store eigenvalue denominators
  173. w - workspace
  174. Return: success or error
  175. */
  176. int
  177. gsl_eigen_gen (gsl_matrix * A, gsl_matrix * B, gsl_vector_complex * alpha,
  178. gsl_vector * beta, gsl_eigen_gen_workspace * w)
  179. {
  180. const size_t N = A->size1;
  181. /* check matrix and vector sizes */
  182. if (N != A->size2)
  183. {
  184. GSL_ERROR ("matrix must be square to compute eigenvalues", GSL_ENOTSQR);
  185. }
  186. else if ((N != B->size1) || (N != B->size2))
  187. {
  188. GSL_ERROR ("B matrix dimensions must match A", GSL_EBADLEN);
  189. }
  190. else if (alpha->size != N || beta->size != N)
  191. {
  192. GSL_ERROR ("eigenvalue vector must match matrix size", GSL_EBADLEN);
  193. }
  194. else if (w->size != N)
  195. {
  196. GSL_ERROR ("matrix size does not match workspace", GSL_EBADLEN);
  197. }
  198. else
  199. {
  200. double anorm, bnorm;
  201. /* compute the Hessenberg-Triangular reduction of (A, B) */
  202. gsl_linalg_hesstri_decomp(A, B, w->Q, w->Z, w->work);
  203. /* save pointers to original matrices */
  204. w->H = A;
  205. w->R = B;
  206. w->n_evals = 0;
  207. w->n_iter = 0;
  208. w->eshift = 0.0;
  209. /* determine if we need to compute top indices in QZ step */
  210. w->needtop = w->Q != 0 || w->Z != 0 || w->compute_t || w->compute_s;
  211. /* compute matrix norms */
  212. anorm = normF(A);
  213. bnorm = normF(B);
  214. /* compute tolerances and scaling factors */
  215. w->atol = GSL_MAX(GSL_DBL_MIN, GSL_DBL_EPSILON * anorm);
  216. w->btol = GSL_MAX(GSL_DBL_MIN, GSL_DBL_EPSILON * bnorm);
  217. w->ascale = 1.0 / GSL_MAX(GSL_DBL_MIN, anorm);
  218. w->bscale = 1.0 / GSL_MAX(GSL_DBL_MIN, bnorm);
  219. /* compute the generalized Schur decomposition and eigenvalues */
  220. gen_schur_decomp(A, B, alpha, beta, w);
  221. if (w->n_evals != N)
  222. return GSL_EMAXITER;
  223. return GSL_SUCCESS;
  224. }
  225. } /* gsl_eigen_gen() */
  226. /*
  227. gsl_eigen_gen_QZ()
  228. Solve the generalized eigenvalue problem
  229. A x = \lambda B x
  230. for the eigenvalues \lambda. Optionally compute left and/or right
  231. Schur vectors Q and Z which satisfy:
  232. A = Q S Z^t
  233. B = Q T Z^t
  234. where (S, T) is the generalized Schur form of (A, B)
  235. Inputs: A - general real matrix
  236. B - general real matrix
  237. alpha - where to store eigenvalue numerators
  238. beta - where to store eigenvalue denominators
  239. Q - if non-null, where to store left Schur vectors
  240. Z - if non-null, where to store right Schur vectors
  241. w - workspace
  242. Return: success or error
  243. */
  244. int
  245. gsl_eigen_gen_QZ (gsl_matrix * A, gsl_matrix * B,
  246. gsl_vector_complex * alpha, gsl_vector * beta,
  247. gsl_matrix * Q, gsl_matrix * Z,
  248. gsl_eigen_gen_workspace * w)
  249. {
  250. if (Q && (A->size1 != Q->size1 || A->size1 != Q->size2))
  251. {
  252. GSL_ERROR("Q matrix has wrong dimensions", GSL_EBADLEN);
  253. }
  254. else if (Z && (A->size1 != Z->size1 || A->size1 != Z->size2))
  255. {
  256. GSL_ERROR("Z matrix has wrong dimensions", GSL_EBADLEN);
  257. }
  258. else
  259. {
  260. int s;
  261. w->Q = Q;
  262. w->Z = Z;
  263. s = gsl_eigen_gen(A, B, alpha, beta, w);
  264. w->Q = NULL;
  265. w->Z = NULL;
  266. return s;
  267. }
  268. } /* gsl_eigen_gen_QZ() */
  269. /********************************************
  270. * INTERNAL ROUTINES *
  271. ********************************************/
  272. /*
  273. gen_schur_decomp()
  274. Compute the generalized Schur decomposition of the matrix pencil
  275. (H, R) which is in Hessenberg-Triangular form
  276. Inputs: H - upper hessenberg matrix
  277. R - upper triangular matrix
  278. alpha - (output) where to store eigenvalue numerators
  279. beta - (output) where to store eigenvalue denominators
  280. w - workspace
  281. Return: none
  282. Notes: 1) w->n_evals is updated to keep track of how many eigenvalues
  283. are found
  284. */
  285. static void
  286. gen_schur_decomp(gsl_matrix *H, gsl_matrix *R, gsl_vector_complex *alpha,
  287. gsl_vector *beta, gsl_eigen_gen_workspace *w)
  288. {
  289. size_t N;
  290. gsl_matrix_view h, r;
  291. gsl_matrix_view vh, vr;
  292. size_t q; /* index of small subdiagonal element */
  293. gsl_complex z1, z2; /* complex values */
  294. double a, b;
  295. int s;
  296. int flag;
  297. N = H->size1;
  298. h = gsl_matrix_submatrix(H, 0, 0, N, N);
  299. r = gsl_matrix_submatrix(R, 0, 0, N, N);
  300. while ((N > 1) && (w->n_iter)++ < w->max_iterations)
  301. {
  302. q = gen_search_small_elements(&h.matrix, &r.matrix, &flag, w);
  303. if (flag == 0)
  304. {
  305. /* no small elements found - do a QZ sweep */
  306. s = gen_qzstep(&h.matrix, &r.matrix, w);
  307. if (s == GSL_CONTINUE)
  308. {
  309. /*
  310. * (h, r) is a 2-by-2 block with complex eigenvalues -
  311. * standardize and read off eigenvalues
  312. */
  313. s = gen_schur_standardize2(&h.matrix,
  314. &r.matrix,
  315. &z1,
  316. &z2,
  317. &a,
  318. &b,
  319. w);
  320. if (s != GSL_SUCCESS)
  321. {
  322. /*
  323. * if we get here, then the standardization process
  324. * perturbed the eigenvalues onto the real line -
  325. * continue QZ iteration to break them into 1-by-1
  326. * blocks
  327. */
  328. continue;
  329. }
  330. gen_store_eigval2(&h.matrix, &z1, a, &z2, b, alpha, beta, w);
  331. N = 0;
  332. } /* if (s) */
  333. continue;
  334. } /* if (flag == 0) */
  335. else if (flag == 2)
  336. {
  337. if (q == 0)
  338. {
  339. /*
  340. * the leading element of R is zero, split off a block
  341. * at the top
  342. */
  343. gen_tri_split_top(&h.matrix, &r.matrix, w);
  344. }
  345. else
  346. {
  347. /*
  348. * we found a small element on the diagonal of R - chase the
  349. * zero to the bottom of the active block and then zero
  350. * H(n, n - 1) to split off a 1-by-1 block
  351. */
  352. if (q != N - 1)
  353. gen_tri_chase_zero(&h.matrix, &r.matrix, q, w);
  354. /* now zero H(n, n - 1) */
  355. gen_tri_zero_H(&h.matrix, &r.matrix, w);
  356. }
  357. /* continue so the next iteration detects the zero in H */
  358. continue;
  359. }
  360. /*
  361. * a small subdiagonal element of H was found - one or two
  362. * eigenvalues have converged or the matrix has split into
  363. * two smaller matrices
  364. */
  365. if (q == (N - 1))
  366. {
  367. /*
  368. * the last subdiagonal element of the hessenberg matrix is 0 -
  369. * H_{NN} / R_{NN} is a real eigenvalue - standardize so
  370. * R_{NN} > 0
  371. */
  372. vh = gsl_matrix_submatrix(&h.matrix, q, q, 1, 1);
  373. vr = gsl_matrix_submatrix(&r.matrix, q, q, 1, 1);
  374. gen_schur_standardize1(&vh.matrix, &vr.matrix, &a, &b, w);
  375. gen_store_eigval1(&vh.matrix, a, b, alpha, beta, w);
  376. --N;
  377. h = gsl_matrix_submatrix(&h.matrix, 0, 0, N, N);
  378. r = gsl_matrix_submatrix(&r.matrix, 0, 0, N, N);
  379. }
  380. else if (q == (N - 2))
  381. {
  382. /* bottom right 2-by-2 block may have converged */
  383. vh = gsl_matrix_submatrix(&h.matrix, q, q, 2, 2);
  384. vr = gsl_matrix_submatrix(&r.matrix, q, q, 2, 2);
  385. s = gen_schur_standardize2(&vh.matrix,
  386. &vr.matrix,
  387. &z1,
  388. &z2,
  389. &a,
  390. &b,
  391. w);
  392. if (s != GSL_SUCCESS)
  393. {
  394. /*
  395. * this 2-by-2 block contains real eigenvalues that
  396. * have not yet separated into 1-by-1 blocks -
  397. * recursively call gen_schur_decomp() to finish off
  398. * this block
  399. */
  400. gen_schur_decomp(&vh.matrix, &vr.matrix, alpha, beta, w);
  401. }
  402. else
  403. {
  404. /* we got 2 complex eigenvalues */
  405. gen_store_eigval2(&vh.matrix, &z1, a, &z2, b, alpha, beta, w);
  406. }
  407. N -= 2;
  408. h = gsl_matrix_submatrix(&h.matrix, 0, 0, N, N);
  409. r = gsl_matrix_submatrix(&r.matrix, 0, 0, N, N);
  410. }
  411. else if (q == 1)
  412. {
  413. /* H_{11} / R_{11} is an eigenvalue */
  414. vh = gsl_matrix_submatrix(&h.matrix, 0, 0, 1, 1);
  415. vr = gsl_matrix_submatrix(&r.matrix, 0, 0, 1, 1);
  416. gen_schur_standardize1(&vh.matrix, &vr.matrix, &a, &b, w);
  417. gen_store_eigval1(&vh.matrix, a, b, alpha, beta, w);
  418. --N;
  419. h = gsl_matrix_submatrix(&h.matrix, 1, 1, N, N);
  420. r = gsl_matrix_submatrix(&r.matrix, 1, 1, N, N);
  421. }
  422. else if (q == 2)
  423. {
  424. /* upper left 2-by-2 block may have converged */
  425. vh = gsl_matrix_submatrix(&h.matrix, 0, 0, 2, 2);
  426. vr = gsl_matrix_submatrix(&r.matrix, 0, 0, 2, 2);
  427. s = gen_schur_standardize2(&vh.matrix,
  428. &vr.matrix,
  429. &z1,
  430. &z2,
  431. &a,
  432. &b,
  433. w);
  434. if (s != GSL_SUCCESS)
  435. {
  436. /*
  437. * this 2-by-2 block contains real eigenvalues that
  438. * have not yet separated into 1-by-1 blocks -
  439. * recursively call gen_schur_decomp() to finish off
  440. * this block
  441. */
  442. gen_schur_decomp(&vh.matrix, &vr.matrix, alpha, beta, w);
  443. }
  444. else
  445. {
  446. /* we got 2 complex eigenvalues */
  447. gen_store_eigval2(&vh.matrix, &z1, a, &z2, b, alpha, beta, w);
  448. }
  449. N -= 2;
  450. h = gsl_matrix_submatrix(&h.matrix, 2, 2, N, N);
  451. r = gsl_matrix_submatrix(&r.matrix, 2, 2, N, N);
  452. }
  453. else
  454. {
  455. /*
  456. * There is a zero element on the subdiagonal somewhere
  457. * in the middle of the matrix - we can now operate
  458. * separately on the two submatrices split by this
  459. * element. q is the row index of the zero element.
  460. */
  461. /* operate on lower right (N - q)-by-(N - q) block first */
  462. vh = gsl_matrix_submatrix(&h.matrix, q, q, N - q, N - q);
  463. vr = gsl_matrix_submatrix(&r.matrix, q, q, N - q, N - q);
  464. gen_schur_decomp(&vh.matrix, &vr.matrix, alpha, beta, w);
  465. /* operate on upper left q-by-q block */
  466. vh = gsl_matrix_submatrix(&h.matrix, 0, 0, q, q);
  467. vr = gsl_matrix_submatrix(&r.matrix, 0, 0, q, q);
  468. gen_schur_decomp(&vh.matrix, &vr.matrix, alpha, beta, w);
  469. N = 0;
  470. }
  471. } /* while ((N > 1) && (w->n_iter)++ < w->max_iterations) */
  472. /* handle special case of N = 1 */
  473. if (N == 1)
  474. {
  475. gen_schur_standardize1(&h.matrix, &r.matrix, &a, &b, w);
  476. gen_store_eigval1(&h.matrix, a, b, alpha, beta, w);
  477. }
  478. } /* gen_schur_decomp() */
  479. /*
  480. gen_qzstep()
  481. This routine determines what type of QZ step to perform on
  482. the generalized matrix pair (H, R). If the pair is 3-by-3 or bigger,
  483. we look at the bottom right 2-by-2 block. If this block has complex
  484. eigenvalues, we perform a Francis double shift QZ sweep. If it
  485. has real eigenvalues, we perform an implicit single shift QZ sweep.
  486. If the pair is 2-by-2 with real eigenvalues, we perform a single
  487. shift sweep. If it has complex eigenvalues, we return GSL_CONTINUE
  488. to notify the calling function that a 2-by-2 block with complex
  489. eigenvalues has converged, so that it may then call
  490. gen_schur_standardize2(). In the real eigenvalue case, we want to
  491. continue doing QZ sweeps to break it up into two 1-by-1 blocks.
  492. See LAPACK routine DHGEQZ and [1] for more information.
  493. Inputs: H - upper Hessenberg matrix (at least 2-by-2)
  494. R - upper triangular matrix (at least 2-by-2)
  495. w - workspace
  496. Return: GSL_SUCCESS on normal completion
  497. GSL_CONTINUE if we detect a 2-by-2 block with complex eigenvalues
  498. */
  499. static inline int
  500. gen_qzstep(gsl_matrix *H, gsl_matrix *R, gsl_eigen_gen_workspace *w)
  501. {
  502. const size_t N = H->size1;
  503. gsl_matrix_view vh, vr; /* views of bottom right 2-by-2 block */
  504. double wr1, wr2, wi;
  505. double scale1, scale2, scale;
  506. double cs, sn; /* givens rotation */
  507. double temp, /* temporary variables */
  508. temp2;
  509. size_t j; /* looping */
  510. gsl_vector_view xv, yv; /* temporary views */
  511. size_t top;
  512. size_t rows;
  513. if (w->n_iter % 10 == 0)
  514. {
  515. /*
  516. * Exceptional shift - we have gone 10 iterations without finding
  517. * a new eigenvalue, do a single shift sweep with an
  518. * exceptional shift
  519. */
  520. if ((GSL_DBL_MIN * w->max_iterations) *
  521. fabs(gsl_matrix_get(H, N - 2, N - 1)) <
  522. fabs(gsl_matrix_get(R, N - 2, N - 2)))
  523. {
  524. w->eshift += gsl_matrix_get(H, N - 2, N - 1) /
  525. gsl_matrix_get(R, N - 2, N - 2);
  526. }
  527. else
  528. w->eshift += 1.0 / (GSL_DBL_MIN * w->max_iterations);
  529. if ((w->eshift < GSL_DBL_EPSILON) &&
  530. (GSL_DBL_MIN * w->max_iterations) *
  531. fabs(gsl_matrix_get(H, N - 1, N - 2)) <
  532. fabs(gsl_matrix_get(R, N - 2, N - 2)))
  533. {
  534. w->eshift = GEN_ESHIFT_COEFF *
  535. (w->ascale * gsl_matrix_get(H, N - 1, N - 2)) /
  536. (w->bscale * gsl_matrix_get(R, N - 2, N - 2));
  537. }
  538. scale1 = 1.0;
  539. wr1 = w->eshift;
  540. }
  541. else
  542. {
  543. /*
  544. * Compute generalized eigenvalues of bottom right 2-by-2 block
  545. * to be used as shifts - wr1 is the Wilkinson shift
  546. */
  547. vh = gsl_matrix_submatrix(H, N - 2, N - 2, 2, 2);
  548. vr = gsl_matrix_submatrix(R, N - 2, N - 2, 2, 2);
  549. gsl_schur_gen_eigvals(&vh.matrix,
  550. &vr.matrix,
  551. &wr1,
  552. &wr2,
  553. &wi,
  554. &scale1,
  555. &scale2);
  556. if (wi != 0.0)
  557. {
  558. /* complex eigenvalues */
  559. if (N == 2)
  560. {
  561. /*
  562. * its a 2-by-2 block with complex eigenvalues - notify
  563. * the calling function to deflate
  564. */
  565. return (GSL_CONTINUE);
  566. }
  567. else
  568. {
  569. /* do a francis double shift sweep */
  570. gen_qzstep_d(H, R, w);
  571. }
  572. return GSL_SUCCESS;
  573. }
  574. }
  575. /* real eigenvalues - perform single shift QZ step */
  576. temp = GSL_MIN(w->ascale, 1.0) * (0.5 / GSL_DBL_MIN);
  577. if (scale1 > temp)
  578. scale = temp / scale1;
  579. else
  580. scale = 1.0;
  581. temp = GSL_MIN(w->bscale, 1.0) * (0.5 / GSL_DBL_MIN);
  582. if (fabs(wr1) > temp)
  583. scale = GSL_MIN(scale, temp / fabs(wr1));
  584. scale1 *= scale;
  585. wr1 *= scale;
  586. if (w->needtop)
  587. {
  588. /* get absolute index of this matrix relative to original matrix */
  589. top = gen_get_submatrix(w->H, H);
  590. }
  591. temp = scale1*gsl_matrix_get(H, 0, 0) - wr1*gsl_matrix_get(R, 0, 0);
  592. temp2 = scale1*gsl_matrix_get(H, 1, 0);
  593. create_givens(temp, temp2, &cs, &sn);
  594. sn = -sn;
  595. for (j = 0; j < N - 1; ++j)
  596. {
  597. if (j > 0)
  598. {
  599. temp = gsl_matrix_get(H, j, j - 1);
  600. temp2 = gsl_matrix_get(H, j + 1, j - 1);
  601. create_givens(temp, temp2, &cs, &sn);
  602. sn = -sn;
  603. /* apply to column (j - 1) */
  604. temp = cs * gsl_matrix_get(H, j, j - 1) +
  605. sn * gsl_matrix_get(H, j + 1, j - 1);
  606. gsl_matrix_set(H, j, j - 1, temp);
  607. gsl_matrix_set(H, j + 1, j - 1, 0.0);
  608. }
  609. /* apply G to H(j:j+1,:) and T(j:j+1,:) */
  610. if (w->compute_s)
  611. {
  612. xv = gsl_matrix_subrow(w->H, top + j, top + j, w->size - top - j);
  613. yv = gsl_matrix_subrow(w->H, top + j + 1, top + j, w->size - top - j);
  614. }
  615. else
  616. {
  617. xv = gsl_matrix_subrow(H, j, j, N - j);
  618. yv = gsl_matrix_subrow(H, j + 1, j, N - j);
  619. }
  620. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  621. if (w->compute_t)
  622. {
  623. xv = gsl_matrix_subrow(w->R, top + j, top + j, w->size - top - j);
  624. yv = gsl_matrix_subrow(w->R, top + j + 1, top + j, w->size - top - j);
  625. }
  626. else
  627. {
  628. xv = gsl_matrix_subrow(R, j, j, N - j);
  629. yv = gsl_matrix_subrow(R, j + 1, j, N - j);
  630. }
  631. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  632. if (w->Q)
  633. {
  634. /* accumulate Q: Q -> QG */
  635. xv = gsl_matrix_column(w->Q, top + j);
  636. yv = gsl_matrix_column(w->Q, top + j + 1);
  637. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  638. }
  639. temp = gsl_matrix_get(R, j + 1, j + 1);
  640. temp2 = gsl_matrix_get(R, j + 1, j);
  641. create_givens(temp, temp2, &cs, &sn);
  642. rows = GSL_MIN(j + 3, N);
  643. if (w->compute_s)
  644. {
  645. xv = gsl_matrix_subcolumn(w->H, top + j, 0, top + rows);
  646. yv = gsl_matrix_subcolumn(w->H, top + j + 1, 0, top + rows);
  647. }
  648. else
  649. {
  650. xv = gsl_matrix_subcolumn(H, j, 0, rows);
  651. yv = gsl_matrix_subcolumn(H, j + 1, 0, rows);
  652. }
  653. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  654. rows = GSL_MIN(j + 2, N);
  655. if (w->compute_t)
  656. {
  657. xv = gsl_matrix_subcolumn(w->R, top + j, 0, top + rows);
  658. yv = gsl_matrix_subcolumn(w->R, top + j + 1, 0, top + rows);
  659. }
  660. else
  661. {
  662. xv = gsl_matrix_subcolumn(R, j, 0, rows);
  663. yv = gsl_matrix_subcolumn(R, j + 1, 0, rows);
  664. }
  665. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  666. if (w->Z)
  667. {
  668. /* accumulate Z: Z -> ZG */
  669. xv = gsl_matrix_column(w->Z, top + j);
  670. yv = gsl_matrix_column(w->Z, top + j + 1);
  671. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  672. }
  673. } /* for (j = 0; j < N - 1; ++j) */
  674. return GSL_SUCCESS;
  675. } /* gen_qzstep() */
  676. /*
  677. gen_qzstep_d()
  678. Perform an implicit double shift QZ step.
  679. See Golub & Van Loan, "Matrix Computations" (3rd ed), algorithm 7.7.2
  680. Inputs: H - upper Hessenberg matrix (at least 3-by-3)
  681. R - upper triangular matrix (at least 3-by-3)
  682. w - workspace
  683. */
  684. static inline void
  685. gen_qzstep_d(gsl_matrix *H, gsl_matrix *R, gsl_eigen_gen_workspace *w)
  686. {
  687. const size_t N = H->size1;
  688. size_t j; /* looping */
  689. double dat[3]; /* householder vector */
  690. double tau; /* householder coefficient */
  691. gsl_vector_view v2, v3; /* views into 'dat' */
  692. gsl_matrix_view m; /* temporary view */
  693. double tmp;
  694. size_t q, r;
  695. size_t top; /* location of H in original matrix */
  696. double scale;
  697. double AB11, /* various matrix element ratios */
  698. AB22,
  699. ABNN,
  700. ABMM,
  701. AMNBNN,
  702. ANMBMM,
  703. A21B11,
  704. A12B22,
  705. A32B22,
  706. B12B22,
  707. BMNBNN;
  708. v2 = gsl_vector_view_array(dat, 2);
  709. v3 = gsl_vector_view_array(dat, 3);
  710. if (w->needtop)
  711. {
  712. /* get absolute index of this matrix relative to original matrix */
  713. top = gen_get_submatrix(w->H, H);
  714. }
  715. /*
  716. * Similar to the QR method, we take the shifts to be the two
  717. * zeros of the problem
  718. *
  719. * det[H(n-1:n,n-1:n) - s*R(n-1:n,n-1:n)] = 0
  720. *
  721. * The initial householder vector elements are then given by
  722. * Eq. 4.1 of [1], which are designed to reduce errors when
  723. * off diagonal elements are small.
  724. */
  725. ABMM = (w->ascale * gsl_matrix_get(H, N - 2, N - 2)) /
  726. (w->bscale * gsl_matrix_get(R, N - 2, N - 2));
  727. ABNN = (w->ascale * gsl_matrix_get(H, N - 1, N - 1)) /
  728. (w->bscale * gsl_matrix_get(R, N - 1, N - 1));
  729. AB11 = (w->ascale * gsl_matrix_get(H, 0, 0)) /
  730. (w->bscale * gsl_matrix_get(R, 0, 0));
  731. AB22 = (w->ascale * gsl_matrix_get(H, 1, 1)) /
  732. (w->bscale * gsl_matrix_get(R, 1, 1));
  733. AMNBNN = (w->ascale * gsl_matrix_get(H, N - 2, N - 1)) /
  734. (w->bscale * gsl_matrix_get(R, N - 1, N - 1));
  735. ANMBMM = (w->ascale * gsl_matrix_get(H, N - 1, N - 2)) /
  736. (w->bscale * gsl_matrix_get(R, N - 2, N - 2));
  737. BMNBNN = gsl_matrix_get(R, N - 2, N - 1) /
  738. gsl_matrix_get(R, N - 1, N - 1);
  739. A21B11 = (w->ascale * gsl_matrix_get(H, 1, 0)) /
  740. (w->bscale * gsl_matrix_get(R, 0, 0));
  741. A12B22 = (w->ascale * gsl_matrix_get(H, 0, 1)) /
  742. (w->bscale * gsl_matrix_get(R, 1, 1));
  743. A32B22 = (w->ascale * gsl_matrix_get(H, 2, 1)) /
  744. (w->bscale * gsl_matrix_get(R, 1, 1));
  745. B12B22 = gsl_matrix_get(R, 0, 1) / gsl_matrix_get(R, 1, 1);
  746. /*
  747. * These are the Eqs (4.1) of [1], just multiplied by the factor
  748. * (A_{21} / B_{11})
  749. */
  750. dat[0] = (ABMM - AB11) * (ABNN - AB11) - (AMNBNN * ANMBMM) +
  751. (ANMBMM * BMNBNN * AB11) + (A12B22 - (AB11 * B12B22)) * A21B11;
  752. dat[1] = ((AB22 - AB11) - (A21B11 * B12B22) - (ABMM - AB11) -
  753. (ABNN - AB11) + (ANMBMM * BMNBNN)) * A21B11;
  754. dat[2] = A32B22 * A21B11;
  755. scale = fabs(dat[0]) + fabs(dat[1]) + fabs(dat[2]);
  756. if (scale != 0.0)
  757. {
  758. dat[0] /= scale;
  759. dat[1] /= scale;
  760. dat[2] /= scale;
  761. }
  762. for (j = 0; j < N - 2; ++j)
  763. {
  764. r = GSL_MIN(j + 4, N);
  765. /*
  766. * Find householder Q so that
  767. *
  768. * Q [x y z]^t = [ * 0 0 ]^t
  769. */
  770. tau = gsl_linalg_householder_transform(&v3.vector);
  771. if (tau != 0.0)
  772. {
  773. /*
  774. * q is the initial column to start applying the householder
  775. * transformation. The GSL_MAX() simply ensures we don't
  776. * try to apply it to column (-1), since we are zeroing out
  777. * column (j - 1) except for the first iteration which
  778. * introduces the bulge.
  779. */
  780. q = (size_t) GSL_MAX(0, (int)j - 1);
  781. /* H -> QH, R -> QR */
  782. if (w->compute_s)
  783. {
  784. /*
  785. * We are computing the Schur form S, so we need to
  786. * transform the whole matrix H
  787. */
  788. m = gsl_matrix_submatrix(w->H,
  789. top + j,
  790. top + q,
  791. 3,
  792. w->size - top - q);
  793. gsl_linalg_householder_hm(tau, &v3.vector, &m.matrix);
  794. }
  795. else
  796. {
  797. /* just transform the active block */
  798. m = gsl_matrix_submatrix(H, j, q, 3, N - q);
  799. gsl_linalg_householder_hm(tau, &v3.vector, &m.matrix);
  800. }
  801. if (w->compute_t)
  802. {
  803. /*
  804. * We are computing the Schur form T, so we need to
  805. * transform the whole matrix R
  806. */
  807. m = gsl_matrix_submatrix(w->R,
  808. top + j,
  809. top + j,
  810. 3,
  811. w->size - top - j);
  812. gsl_linalg_householder_hm(tau, &v3.vector, &m.matrix);
  813. }
  814. else
  815. {
  816. /* just transform the active block */
  817. m = gsl_matrix_submatrix(R, j, j, 3, N - j);
  818. gsl_linalg_householder_hm(tau, &v3.vector, &m.matrix);
  819. }
  820. if (w->Q)
  821. {
  822. /* accumulate the transformation into Q */
  823. m = gsl_matrix_submatrix(w->Q, 0, top + j, w->size, 3);
  824. gsl_linalg_householder_mh(tau, &v3.vector, &m.matrix);
  825. }
  826. } /* if (tau != 0.0) */
  827. /*
  828. * Find householder Z so that
  829. *
  830. * [ r_{j+2,j} r_{j+2, j+1}, r_{j+2, j+2} ] Z = [ 0 0 * ]
  831. *
  832. * This isn't exactly what gsl_linalg_householder_transform
  833. * does, so we need to rotate the input vector so it preserves
  834. * the last element, and then rotate it back afterwards.
  835. *
  836. * So instead of transforming [x y z], we transform [z x y],
  837. * and the resulting HH vector [1 v2 v3] -> [v2 v3 1] but
  838. * then needs to be scaled to have the first element = 1, so
  839. * it becomes [1 v3/v2 1/v2] (tau must also be scaled accordingly).
  840. */
  841. dat[0] = gsl_matrix_get(R, j + 2, j + 2);
  842. dat[1] = gsl_matrix_get(R, j + 2, j);
  843. dat[2] = gsl_matrix_get(R, j + 2, j + 1);
  844. scale = fabs(dat[0]) + fabs(dat[1]) + fabs(dat[2]);
  845. if (scale != 0.0)
  846. {
  847. dat[0] /= scale;
  848. dat[1] /= scale;
  849. dat[2] /= scale;
  850. }
  851. tau = gsl_linalg_householder_transform(&v3.vector);
  852. if (tau != 0.0)
  853. {
  854. /* rotate back */
  855. tmp = gsl_vector_get(&v3.vector, 1);
  856. gsl_vector_set(&v3.vector, 1, gsl_vector_get(&v3.vector, 2)/tmp);
  857. gsl_vector_set(&v3.vector, 2, 1.0 / tmp);
  858. tau *= tmp * tmp;
  859. /* H -> HZ, R -> RZ */
  860. if (w->compute_s)
  861. {
  862. m = gsl_matrix_submatrix(w->H, 0, top + j, top + r, 3);
  863. gsl_linalg_householder_mh(tau, &v3.vector, &m.matrix);
  864. }
  865. else
  866. {
  867. m = gsl_matrix_submatrix(H, 0, j, r, 3);
  868. gsl_linalg_householder_mh(tau, &v3.vector, &m.matrix);
  869. }
  870. if (w->compute_t)
  871. {
  872. m = gsl_matrix_submatrix(w->R, 0, top + j, top + j + 3, 3);
  873. gsl_linalg_householder_mh(tau, &v3.vector, &m.matrix);
  874. }
  875. else
  876. {
  877. m = gsl_matrix_submatrix(R, 0, j, j + 3, 3);
  878. gsl_linalg_householder_mh(tau, &v3.vector, &m.matrix);
  879. }
  880. if (w->Z)
  881. {
  882. /* accumulate transformation into Z */
  883. m = gsl_matrix_submatrix(w->Z, 0, top + j, w->size, 3);
  884. gsl_linalg_householder_mh(tau, &v3.vector, &m.matrix);
  885. }
  886. } /* if (tau != 0.0) */
  887. /*
  888. * Find householder Z so that
  889. *
  890. * [ r_{j+1,j} r_{j+1, j+1} ] Z = [ 0 * ]
  891. */
  892. dat[0] = gsl_matrix_get(R, j + 1, j + 1);
  893. dat[1] = gsl_matrix_get(R, j + 1, j);
  894. scale = fabs(dat[0]) + fabs(dat[1]);
  895. if (scale != 0.0)
  896. {
  897. dat[0] /= scale;
  898. dat[1] /= scale;
  899. }
  900. tau = gsl_linalg_householder_transform(&v2.vector);
  901. if (tau != 0.0)
  902. {
  903. /* rotate back */
  904. tmp = gsl_vector_get(&v2.vector, 1);
  905. gsl_vector_set(&v2.vector, 1, 1.0 / tmp);
  906. tau *= tmp * tmp;
  907. /* H -> HZ, R -> RZ */
  908. if (w->compute_s)
  909. {
  910. m = gsl_matrix_submatrix(w->H, 0, top + j, top + r, 2);
  911. gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
  912. }
  913. else
  914. {
  915. m = gsl_matrix_submatrix(H, 0, j, r, 2);
  916. gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
  917. }
  918. if (w->compute_t)
  919. {
  920. m = gsl_matrix_submatrix(w->R, 0, top + j, top + j + 3, 2);
  921. gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
  922. }
  923. else
  924. {
  925. m = gsl_matrix_submatrix(R, 0, j, j + 3, 2);
  926. gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
  927. }
  928. if (w->Z)
  929. {
  930. /* accumulate transformation into Z */
  931. m = gsl_matrix_submatrix(w->Z, 0, top + j, w->size, 2);
  932. gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
  933. }
  934. } /* if (tau != 0.0) */
  935. dat[0] = gsl_matrix_get(H, j + 1, j);
  936. dat[1] = gsl_matrix_get(H, j + 2, j);
  937. if (j < N - 3)
  938. dat[2] = gsl_matrix_get(H, j + 3, j);
  939. scale = fabs(dat[0]) + fabs(dat[1]) + fabs(dat[2]);
  940. if (scale != 0.0)
  941. {
  942. dat[0] /= scale;
  943. dat[1] /= scale;
  944. dat[2] /= scale;
  945. }
  946. } /* for (j = 0; j < N - 2; ++j) */
  947. /*
  948. * Find Householder Q so that
  949. *
  950. * Q [ x y ]^t = [ * 0 ]^t
  951. */
  952. scale = fabs(dat[0]) + fabs(dat[1]);
  953. if (scale != 0.0)
  954. {
  955. dat[0] /= scale;
  956. dat[1] /= scale;
  957. }
  958. tau = gsl_linalg_householder_transform(&v2.vector);
  959. if (w->compute_s)
  960. {
  961. m = gsl_matrix_submatrix(w->H,
  962. top + N - 2,
  963. top + N - 3,
  964. 2,
  965. w->size - top - N + 3);
  966. gsl_linalg_householder_hm(tau, &v2.vector, &m.matrix);
  967. }
  968. else
  969. {
  970. m = gsl_matrix_submatrix(H, N - 2, N - 3, 2, 3);
  971. gsl_linalg_householder_hm(tau, &v2.vector, &m.matrix);
  972. }
  973. if (w->compute_t)
  974. {
  975. m = gsl_matrix_submatrix(w->R,
  976. top + N - 2,
  977. top + N - 2,
  978. 2,
  979. w->size - top - N + 2);
  980. gsl_linalg_householder_hm(tau, &v2.vector, &m.matrix);
  981. }
  982. else
  983. {
  984. m = gsl_matrix_submatrix(R, N - 2, N - 2, 2, 2);
  985. gsl_linalg_householder_hm(tau, &v2.vector, &m.matrix);
  986. }
  987. if (w->Q)
  988. {
  989. /* accumulate the transformation into Q */
  990. m = gsl_matrix_submatrix(w->Q, 0, top + N - 2, w->size, 2);
  991. gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
  992. }
  993. /*
  994. * Find Householder Z so that
  995. *
  996. * [ b_{n,n-1} b_{nn} ] Z = [ 0 * ]
  997. */
  998. dat[0] = gsl_matrix_get(R, N - 1, N - 1);
  999. dat[1] = gsl_matrix_get(R, N - 1, N - 2);
  1000. scale = fabs(dat[0]) + fabs(dat[1]);
  1001. if (scale != 0.0)
  1002. {
  1003. dat[0] /= scale;
  1004. dat[1] /= scale;
  1005. }
  1006. tau = gsl_linalg_householder_transform(&v2.vector);
  1007. /* rotate back */
  1008. tmp = gsl_vector_get(&v2.vector, 1);
  1009. gsl_vector_set(&v2.vector, 1, 1.0 / tmp);
  1010. tau *= tmp * tmp;
  1011. if (w->compute_s)
  1012. {
  1013. m = gsl_matrix_submatrix(w->H, 0, top + N - 2, top + N, 2);
  1014. gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
  1015. }
  1016. else
  1017. {
  1018. m = gsl_matrix_submatrix(H, 0, N - 2, N, 2);
  1019. gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
  1020. }
  1021. if (w->compute_t)
  1022. {
  1023. m = gsl_matrix_submatrix(w->R, 0, top + N - 2, top + N, 2);
  1024. gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
  1025. }
  1026. else
  1027. {
  1028. m = gsl_matrix_submatrix(R, 0, N - 2, N, 2);
  1029. gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
  1030. }
  1031. if (w->Z)
  1032. {
  1033. /* accumulate the transformation into Z */
  1034. m = gsl_matrix_submatrix(w->Z, 0, top + N - 2, w->size, 2);
  1035. gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
  1036. }
  1037. } /* gen_qzstep_d() */
  1038. /*
  1039. gen_tri_split_top()
  1040. This routine is called when the leading element on the diagonal of R
  1041. has become negligible. Split off a 1-by-1 block at the top.
  1042. Inputs: H - upper hessenberg matrix
  1043. R - upper triangular matrix
  1044. w - workspace
  1045. */
  1046. static void
  1047. gen_tri_split_top(gsl_matrix *H, gsl_matrix *R, gsl_eigen_gen_workspace *w)
  1048. {
  1049. const size_t N = H->size1;
  1050. size_t j, top;
  1051. double cs, sn;
  1052. gsl_vector_view xv, yv;
  1053. if (w->needtop)
  1054. top = gen_get_submatrix(w->H, H);
  1055. j = 0;
  1056. create_givens(gsl_matrix_get(H, j, j),
  1057. gsl_matrix_get(H, j + 1, j),
  1058. &cs,
  1059. &sn);
  1060. sn = -sn;
  1061. if (w->compute_s)
  1062. {
  1063. xv = gsl_matrix_subrow(w->H, top + j, top, w->size - top);
  1064. yv = gsl_matrix_subrow(w->H, top + j + 1, top, w->size - top);
  1065. }
  1066. else
  1067. {
  1068. xv = gsl_matrix_row(H, j);
  1069. yv = gsl_matrix_row(H, j + 1);
  1070. }
  1071. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  1072. gsl_matrix_set(H, j + 1, j, 0.0);
  1073. if (w->compute_t)
  1074. {
  1075. xv = gsl_matrix_subrow(w->R, top + j, top + 1, w->size - top - 1);
  1076. yv = gsl_matrix_subrow(w->R, top + j + 1, top + 1, w->size - top - 1);
  1077. }
  1078. else
  1079. {
  1080. xv = gsl_matrix_subrow(R, j, 1, N - 1);
  1081. yv = gsl_matrix_subrow(R, j + 1, 1, N - 1);
  1082. }
  1083. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  1084. if (w->Q)
  1085. {
  1086. xv = gsl_matrix_column(w->Q, top + j);
  1087. yv = gsl_matrix_column(w->Q, top + j + 1);
  1088. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  1089. }
  1090. } /* gen_tri_split_top() */
  1091. /*
  1092. gen_tri_chase_zero()
  1093. This routine is called when an element on the diagonal of R
  1094. has become negligible. Chase the zero to the bottom of the active
  1095. block so we can split off a 1-by-1 block.
  1096. Inputs: H - upper hessenberg matrix
  1097. R - upper triangular matrix
  1098. q - index such that R(q,q) = 0 (q must be > 0)
  1099. w - workspace
  1100. */
  1101. static inline void
  1102. gen_tri_chase_zero(gsl_matrix *H, gsl_matrix *R, size_t q,
  1103. gsl_eigen_gen_workspace *w)
  1104. {
  1105. const size_t N = H->size1;
  1106. size_t j, top;
  1107. double cs, sn;
  1108. gsl_vector_view xv, yv;
  1109. if (w->needtop)
  1110. top = gen_get_submatrix(w->H, H);
  1111. for (j = q; j < N - 1; ++j)
  1112. {
  1113. create_givens(gsl_matrix_get(R, j, j + 1),
  1114. gsl_matrix_get(R, j + 1, j + 1),
  1115. &cs,
  1116. &sn);
  1117. sn = -sn;
  1118. if (w->compute_t)
  1119. {
  1120. xv = gsl_matrix_subrow(w->R, top + j, top + j + 1, w->size - top - j - 1);
  1121. yv = gsl_matrix_subrow(w->R, top + j + 1, top + j + 1, w->size - top - j - 1);
  1122. }
  1123. else
  1124. {
  1125. xv = gsl_matrix_subrow(R, j, j + 1, N - j - 1);
  1126. yv = gsl_matrix_subrow(R, j + 1, j + 1, N - j - 1);
  1127. }
  1128. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  1129. gsl_matrix_set(R, j + 1, j + 1, 0.0);
  1130. if (w->compute_s)
  1131. {
  1132. xv = gsl_matrix_subrow(w->H, top + j, top + j - 1, w->size - top - j + 1);
  1133. yv = gsl_matrix_subrow(w->H, top + j + 1, top + j - 1, w->size - top - j + 1);
  1134. }
  1135. else
  1136. {
  1137. xv = gsl_matrix_subrow(H, j, j - 1, N - j + 1);
  1138. yv = gsl_matrix_subrow(H, j + 1, j - 1, N - j + 1);
  1139. }
  1140. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  1141. if (w->Q)
  1142. {
  1143. /* accumulate Q */
  1144. xv = gsl_matrix_column(w->Q, top + j);
  1145. yv = gsl_matrix_column(w->Q, top + j + 1);
  1146. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  1147. }
  1148. create_givens(gsl_matrix_get(H, j + 1, j),
  1149. gsl_matrix_get(H, j + 1, j - 1),
  1150. &cs,
  1151. &sn);
  1152. sn = -sn;
  1153. if (w->compute_s)
  1154. {
  1155. xv = gsl_matrix_subcolumn(w->H, top + j, 0, top + j + 2);
  1156. yv = gsl_matrix_subcolumn(w->H, top + j - 1, 0, top + j + 2);
  1157. }
  1158. else
  1159. {
  1160. xv = gsl_matrix_subcolumn(H, j, 0, j + 2);
  1161. yv = gsl_matrix_subcolumn(H, j - 1, 0, j + 2);
  1162. }
  1163. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  1164. gsl_matrix_set(H, j + 1, j - 1, 0.0);
  1165. if (w->compute_t)
  1166. {
  1167. xv = gsl_matrix_subcolumn(w->R, top + j, 0, top + j + 1);
  1168. yv = gsl_matrix_subcolumn(w->R, top + j - 1, 0, top + j + 1);
  1169. }
  1170. else
  1171. {
  1172. xv = gsl_matrix_subcolumn(R, j, 0, j + 1);
  1173. yv = gsl_matrix_subcolumn(R, j - 1, 0, j + 1);
  1174. }
  1175. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  1176. if (w->Z)
  1177. {
  1178. /* accumulate Z */
  1179. xv = gsl_matrix_column(w->Z, top + j);
  1180. yv = gsl_matrix_column(w->Z, top + j - 1);
  1181. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  1182. }
  1183. }
  1184. } /* gen_tri_chase_zero() */
  1185. /*
  1186. gen_tri_zero_H()
  1187. Companion function to get_tri_chase_zero(). After the zero on
  1188. the diagonal of R has been chased to the bottom, we zero the element
  1189. H(n, n - 1) in order to split off a 1-by-1 block.
  1190. */
  1191. static inline void
  1192. gen_tri_zero_H(gsl_matrix *H, gsl_matrix *R, gsl_eigen_gen_workspace *w)
  1193. {
  1194. const size_t N = H->size1;
  1195. size_t top;
  1196. double cs, sn;
  1197. gsl_vector_view xv, yv;
  1198. if (w->needtop)
  1199. top = gen_get_submatrix(w->H, H);
  1200. create_givens(gsl_matrix_get(H, N - 1, N - 1),
  1201. gsl_matrix_get(H, N - 1, N - 2),
  1202. &cs,
  1203. &sn);
  1204. sn = -sn;
  1205. if (w->compute_s)
  1206. {
  1207. xv = gsl_matrix_subcolumn(w->H, top + N - 1, 0, top + N);
  1208. yv = gsl_matrix_subcolumn(w->H, top + N - 2, 0, top + N);
  1209. }
  1210. else
  1211. {
  1212. xv = gsl_matrix_column(H, N - 1);
  1213. yv = gsl_matrix_column(H, N - 2);
  1214. }
  1215. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  1216. gsl_matrix_set(H, N - 1, N - 2, 0.0);
  1217. if (w->compute_t)
  1218. {
  1219. xv = gsl_matrix_subcolumn(w->R, top + N - 1, 0, top + N - 1);
  1220. yv = gsl_matrix_subcolumn(w->R, top + N - 2, 0, top + N - 1);
  1221. }
  1222. else
  1223. {
  1224. xv = gsl_matrix_subcolumn(R, N - 1, 0, N - 1);
  1225. yv = gsl_matrix_subcolumn(R, N - 2, 0, N - 1);
  1226. }
  1227. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  1228. if (w->Z)
  1229. {
  1230. /* accumulate Z */
  1231. xv = gsl_matrix_column(w->Z, top + N - 1);
  1232. yv = gsl_matrix_column(w->Z, top + N - 2);
  1233. gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
  1234. }
  1235. } /* gen_tri_zero_H() */
  1236. /*
  1237. gen_search_small_elements()
  1238. This routine searches for small elements in the matrix pencil
  1239. (H, R) to determine if any eigenvalues have converged.
  1240. Tests:
  1241. 1. Test if the Hessenberg matrix has a small subdiagonal element:
  1242. H(i, i - 1) < tolerance
  1243. 2. Test if the Triangular matrix has a small diagonal element:
  1244. R(i, i) < tolerance
  1245. Possible outcomes:
  1246. (A) Neither test passed: in this case 'flag' is set to 0 and the
  1247. function returns 0
  1248. (B) Test 1 passes and 2 does not: in this case 'flag' is set to 1
  1249. and we return the row index i such that H(i, i - 1) < tol
  1250. (C) Test 2 passes and 1 does not: in this case 'flag' is set to 2
  1251. and we return the index i such that R(i, i) < tol
  1252. (D) Tests 1 and 2 both pass: in this case 'flag' is set to 3 and
  1253. we return the index i such that H(i, i - 1) < tol and R(i, i) < tol
  1254. Inputs: H - upper Hessenberg matrix
  1255. R - upper Triangular matrix
  1256. flag - (output) flag set on output (see above)
  1257. w - workspace
  1258. Return: see above
  1259. */
  1260. static inline size_t
  1261. gen_search_small_elements(gsl_matrix *H, gsl_matrix *R,
  1262. int *flag, gsl_eigen_gen_workspace *w)
  1263. {
  1264. const size_t N = H->size1;
  1265. int k;
  1266. size_t i;
  1267. int pass1 = 0;
  1268. int pass2 = 0;
  1269. for (k = (int) N - 1; k >= 0; --k)
  1270. {
  1271. i = (size_t) k;
  1272. if (i != 0 && fabs(gsl_matrix_get(H, i, i - 1)) <= w->atol)
  1273. {
  1274. gsl_matrix_set(H, i, i - 1, 0.0);
  1275. pass1 = 1;
  1276. }
  1277. if (fabs(gsl_matrix_get(R, i, i)) < w->btol)
  1278. {
  1279. gsl_matrix_set(R, i, i, 0.0);
  1280. pass2 = 1;
  1281. }
  1282. if (pass1 && !pass2) /* case B */
  1283. {
  1284. *flag = 1;
  1285. return (i);
  1286. }
  1287. else if (!pass1 && pass2) /* case C */
  1288. {
  1289. *flag = 2;
  1290. return (i);
  1291. }
  1292. else if (pass1 && pass2) /* case D */
  1293. {
  1294. *flag = 3;
  1295. return (i);
  1296. }
  1297. }
  1298. /* neither test passed: case A */
  1299. *flag = 0;
  1300. return (0);
  1301. } /* gen_search_subdiag_small_elements() */
  1302. /*
  1303. gen_schur_standardize1()
  1304. This function is called when a 1-by-1 block has converged -
  1305. convert the block to standard form and update the Schur forms and
  1306. vectors if required. Standard form here means that the diagonal
  1307. element of B is positive.
  1308. Inputs: A - 1-by-1 matrix in Schur form S
  1309. B - 1-by-1 matrix in Schur form T
  1310. alphar - where to store real part of eigenvalue numerator
  1311. beta - where to store eigenvalue denominator
  1312. w - workspace
  1313. Return: success
  1314. */
  1315. static int
  1316. gen_schur_standardize1(gsl_matrix *A, gsl_matrix *B, double *alphar,
  1317. double *beta, gsl_eigen_gen_workspace *w)
  1318. {
  1319. size_t i;
  1320. size_t top;
  1321. /*
  1322. * it is a 1-by-1 block - the only requirement is that
  1323. * B_{00} is > 0, so if it isn't apply a -I transformation
  1324. */
  1325. if (gsl_matrix_get(B, 0, 0) < 0.0)
  1326. {
  1327. if (w->needtop)
  1328. top = gen_get_submatrix(w->H, A);
  1329. if (w->compute_t)
  1330. {
  1331. for (i = 0; i <= top; ++i)
  1332. gsl_matrix_set(w->R, i, top, -gsl_matrix_get(w->R, i, top));
  1333. }
  1334. else
  1335. gsl_matrix_set(B, 0, 0, -gsl_matrix_get(B, 0, 0));
  1336. if (w->compute_s)
  1337. {
  1338. for (i = 0; i <= top; ++i)
  1339. gsl_matrix_set(w->H, i, top, -gsl_matrix_get(w->H, i, top));
  1340. }
  1341. else
  1342. gsl_matrix_set(A, 0, 0, -gsl_matrix_get(A, 0, 0));
  1343. if (w->Z)
  1344. {
  1345. for (i = 0; i < w->size; ++i)
  1346. gsl_matrix_set(w->Z, i, top, -gsl_matrix_get(w->Z, i, top));
  1347. }
  1348. }
  1349. *alphar = gsl_matrix_get(A, 0, 0);
  1350. *beta = gsl_matrix_get(B, 0, 0);
  1351. return GSL_SUCCESS;
  1352. } /* gen_schur_standardize1() */
  1353. /*
  1354. gen_schur_standardize2()
  1355. This function is called when a 2-by-2 generalized block has
  1356. converged. Convert the block to standard form, which means B
  1357. is rotated so that
  1358. B = [ B11 0 ] with B11, B22 non-negative
  1359. [ 0 B22 ]
  1360. If the resulting block (A, B) has complex eigenvalues, they are
  1361. computed. Otherwise, the function will return GSL_CONTINUE to
  1362. notify caller that we need to do more single shift sweeps to
  1363. convert the 2-by-2 block into two 1-by-1 blocks.
  1364. Inputs: A - 2-by-2 submatrix of schur form S
  1365. B - 2-by-2 submatrix of schur form T
  1366. alpha1 - (output) where to store eigenvalue 1 numerator
  1367. alpha2 - (output) where to store eigenvalue 2 numerator
  1368. beta1 - (output) where to store eigenvalue 1 denominator
  1369. beta2 - (output) where to store eigenvalue 2 denominator
  1370. w - workspace
  1371. Return: GSL_SUCCESS if block has complex eigenvalues (they are computed)
  1372. GSL_CONTINUE if block has real eigenvalues (they are not computed)
  1373. */
  1374. static int
  1375. gen_schur_standardize2(gsl_matrix *A, gsl_matrix *B, gsl_complex *alpha1,
  1376. gsl_complex *alpha2, double *beta1, double *beta2,
  1377. gsl_eigen_gen_workspace *w)
  1378. {
  1379. double datB[4],
  1380. datV[4],
  1381. datS[2],
  1382. work[2];
  1383. gsl_matrix_view uv = gsl_matrix_view_array(datB, 2, 2);
  1384. gsl_matrix_view vv = gsl_matrix_view_array(datV, 2, 2);
  1385. gsl_vector_view sv = gsl_vector_view_array(datS, 2);
  1386. gsl_vector_view wv = gsl_vector_view_array(work, 2);
  1387. double B11, B22;
  1388. size_t top;
  1389. double det;
  1390. double cr, sr, cl, sl;
  1391. gsl_vector_view xv, yv;
  1392. int s;
  1393. if (w->needtop)
  1394. top = gen_get_submatrix(w->H, A);
  1395. /*
  1396. * Rotate B so that
  1397. *
  1398. * B = [ B11 0 ]
  1399. * [ 0 B22 ]
  1400. *
  1401. * with B11 non-negative
  1402. */
  1403. gsl_matrix_memcpy(&uv.matrix, B);
  1404. gsl_linalg_SV_decomp(&uv.matrix, &vv.matrix, &sv.vector, &wv.vector);
  1405. /*
  1406. * Right now, B = U S V^t, where S = diag(s)
  1407. *
  1408. * The SVD routine may have computed reflection matrices U and V,
  1409. * but it would be much nicer to have rotations since we won't have
  1410. * to use BLAS mat-mat multiplications to update our matrices,
  1411. * and can instead use drot. So convert them to rotations if
  1412. * necessary
  1413. */
  1414. det = gsl_matrix_get(&vv.matrix, 0, 0) * gsl_matrix_get(&vv.matrix, 1, 1) -
  1415. gsl_matrix_get(&vv.matrix, 0, 1) * gsl_matrix_get(&vv.matrix, 1, 0);
  1416. if (det < 0.0)
  1417. {
  1418. /* V is a reflection, convert it to a rotation by inserting
  1419. * F = [1 0; 0 -1] so that:
  1420. *
  1421. * B = U S [1 0] [1 0] V^t
  1422. * [0 -1] [0 -1]
  1423. *
  1424. * so S -> S F and V -> V F where F is the reflection matrix
  1425. * We just need to invert S22 since the first column of V
  1426. * will remain unchanged and we can just read off the CS and SN
  1427. * parameters.
  1428. */
  1429. datS[1] = -datS[1];
  1430. }
  1431. cr = gsl_matrix_get(&vv.matrix, 0, 0);
  1432. sr = gsl_matrix_get(&vv.matrix, 1, 0);
  1433. /* same for U */
  1434. det = gsl_matrix_get(&uv.matrix, 0, 0) * gsl_matrix_get(&uv.matrix, 1, 1) -
  1435. gsl_matrix_get(&uv.matrix, 0, 1) * gsl_matrix_get(&uv.matrix, 1, 0);
  1436. if (det < 0.0)
  1437. datS[1] = -datS[1];
  1438. cl = gsl_matrix_get(&uv.matrix, 0, 0);
  1439. sl = gsl_matrix_get(&uv.matrix, 1, 0);
  1440. B11 = gsl_vector_get(&sv.vector, 0);
  1441. B22 = gsl_vector_get(&sv.vector, 1);
  1442. /* make sure B11 is positive */
  1443. if (B11 < 0.0)
  1444. {
  1445. B11 = -B11;
  1446. B22 = -B22;
  1447. cr = -cr;
  1448. sr = -sr;
  1449. }
  1450. /*
  1451. * At this point,
  1452. *
  1453. * [ S11 0 ] = [ CSL SNL ] B [ CSR -SNR ]
  1454. * [ 0 S22 ] [-SNL CSL ] [ SNR CSR ]
  1455. *
  1456. * apply rotations to H and rest of R
  1457. */
  1458. if (w->compute_s)
  1459. {
  1460. xv = gsl_matrix_subrow(w->H, top, top, w->size - top);
  1461. yv = gsl_matrix_subrow(w->H, top + 1, top, w->size - top);
  1462. gsl_blas_drot(&xv.vector, &yv.vector, cl, sl);
  1463. xv = gsl_matrix_subcolumn(w->H, top, 0, top + 2);
  1464. yv = gsl_matrix_subcolumn(w->H, top + 1, 0, top + 2);
  1465. gsl_blas_drot(&xv.vector, &yv.vector, cr, sr);
  1466. }
  1467. else
  1468. {
  1469. xv = gsl_matrix_row(A, 0);
  1470. yv = gsl_matrix_row(A, 1);
  1471. gsl_blas_drot(&xv.vector, &yv.vector, cl, sl);
  1472. xv = gsl_matrix_column(A, 0);
  1473. yv = gsl_matrix_column(A, 1);
  1474. gsl_blas_drot(&xv.vector, &yv.vector, cr, sr);
  1475. }
  1476. if (w->compute_t)
  1477. {
  1478. if (top != (w->size - 2))
  1479. {
  1480. xv = gsl_matrix_subrow(w->R, top, top + 2, w->size - top - 2);
  1481. yv = gsl_matrix_subrow(w->R, top + 1, top + 2, w->size - top - 2);
  1482. gsl_blas_drot(&xv.vector, &yv.vector, cl, sl);
  1483. }
  1484. if (top != 0)
  1485. {
  1486. xv = gsl_matrix_subcolumn(w->R, top, 0, top);
  1487. yv = gsl_matrix_subcolumn(w->R, top + 1, 0, top);
  1488. gsl_blas_drot(&xv.vector, &yv.vector, cr, sr);
  1489. }
  1490. }
  1491. if (w->Q)
  1492. {
  1493. xv = gsl_matrix_column(w->Q, top);
  1494. yv = gsl_matrix_column(w->Q, top + 1);
  1495. gsl_blas_drot(&xv.vector, &yv.vector, cl, sl);
  1496. }
  1497. if (w->Z)
  1498. {
  1499. xv = gsl_matrix_column(w->Z, top);
  1500. yv = gsl_matrix_column(w->Z, top + 1);
  1501. gsl_blas_drot(&xv.vector, &yv.vector, cr, sr);
  1502. }
  1503. gsl_matrix_set(B, 0, 0, B11);
  1504. gsl_matrix_set(B, 0, 1, 0.0);
  1505. gsl_matrix_set(B, 1, 0, 0.0);
  1506. gsl_matrix_set(B, 1, 1, B22);
  1507. /* if B22 is < 0, make it positive by negating its column */
  1508. if (B22 < 0.0)
  1509. {
  1510. size_t i;
  1511. if (w->compute_s)
  1512. {
  1513. for (i = 0; i < top + 2; ++i)
  1514. gsl_matrix_set(w->H, i, top + 1, -gsl_matrix_get(w->H, i, top + 1));
  1515. }
  1516. else
  1517. {
  1518. gsl_matrix_set(A, 0, 1, -gsl_matrix_get(A, 0, 1));
  1519. gsl_matrix_set(A, 1, 1, -gsl_matrix_get(A, 1, 1));
  1520. }
  1521. if (w->compute_t)
  1522. {
  1523. for (i = 0; i < top + 2; ++i)
  1524. gsl_matrix_set(w->R, i, top + 1, -gsl_matrix_get(w->R, i, top + 1));
  1525. }
  1526. else
  1527. {
  1528. gsl_matrix_set(B, 0, 1, -gsl_matrix_get(B, 0, 1));
  1529. gsl_matrix_set(B, 1, 1, -gsl_matrix_get(B, 1, 1));
  1530. }
  1531. if (w->Z)
  1532. {
  1533. xv = gsl_matrix_column(w->Z, top + 1);
  1534. gsl_vector_scale(&xv.vector, -1.0);
  1535. }
  1536. }
  1537. /* our block is now in standard form - compute eigenvalues */
  1538. s = gen_compute_eigenvals(A, B, alpha1, alpha2, beta1, beta2);
  1539. return s;
  1540. } /* gen_schur_standardize2() */
  1541. /*
  1542. gen_compute_eigenvals()
  1543. Compute the complex eigenvalues of a 2-by-2 block
  1544. Return: GSL_CONTINUE if block contains real eigenvalues (they are not
  1545. computed)
  1546. GSL_SUCCESS on normal completion
  1547. */
  1548. static int
  1549. gen_compute_eigenvals(gsl_matrix *A, gsl_matrix *B, gsl_complex *alpha1,
  1550. gsl_complex *alpha2, double *beta1, double *beta2)
  1551. {
  1552. double wr1, wr2, wi, scale1, scale2;
  1553. double s1inv;
  1554. double A11, A12, A21, A22;
  1555. double B11, B22;
  1556. double c11r, c11i, c12, c21, c22r, c22i;
  1557. double cz, cq;
  1558. double szr, szi, sqr, sqi;
  1559. double a1r, a1i, a2r, a2i, b1r, b1i, b1a, b2r, b2i, b2a;
  1560. double alphar, alphai;
  1561. double t1, an, bn, tempr, tempi, wabs;
  1562. /*
  1563. * This function is called from gen_schur_standardize2() and
  1564. * its possible the standardization has perturbed the eigenvalues
  1565. * onto the real line - so check for this before computing them
  1566. */
  1567. gsl_schur_gen_eigvals(A, B, &wr1, &wr2, &wi, &scale1, &scale2);
  1568. if (wi == 0.0)
  1569. return GSL_CONTINUE; /* real eigenvalues - continue QZ iteration */
  1570. /* complex eigenvalues - compute alpha and beta */
  1571. s1inv = 1.0 / scale1;
  1572. A11 = gsl_matrix_get(A, 0, 0);
  1573. A12 = gsl_matrix_get(A, 0, 1);
  1574. A21 = gsl_matrix_get(A, 1, 0);
  1575. A22 = gsl_matrix_get(A, 1, 1);
  1576. B11 = gsl_matrix_get(B, 0, 0);
  1577. B22 = gsl_matrix_get(B, 1, 1);
  1578. c11r = scale1 * A11 - wr1 * B11;
  1579. c11i = -wi * B11;
  1580. c12 = scale1 * A12;
  1581. c21 = scale1 * A21;
  1582. c22r = scale1 * A22 - wr1 * B22;
  1583. c22i = -wi * B22;
  1584. if (fabs(c11r) + fabs(c11i) + fabs(c12) >
  1585. fabs(c21) + fabs(c22r) + fabs(c22i))
  1586. {
  1587. t1 = gsl_hypot3(c12, c11r, c11i);
  1588. if (t1 != 0.0)
  1589. {
  1590. cz = c12 / t1;
  1591. szr = -c11r / t1;
  1592. szi = -c11i / t1;
  1593. }
  1594. else
  1595. {
  1596. cz = 0.0;
  1597. szr = 1.0;
  1598. szi = 0.0;
  1599. }
  1600. }
  1601. else
  1602. {
  1603. cz = hypot(c22r, c22i);
  1604. if (cz <= GSL_DBL_MIN)
  1605. {
  1606. cz = 0.0;
  1607. szr = 1.0;
  1608. szi = 0.0;
  1609. }
  1610. else
  1611. {
  1612. tempr = c22r / cz;
  1613. tempi = c22i / cz;
  1614. t1 = hypot(cz, c21);
  1615. cz /= t1;
  1616. szr = -c21*tempr / t1;
  1617. szi = c21*tempi / t1;
  1618. }
  1619. }
  1620. an = fabs(A11) + fabs(A12) + fabs(A21) + fabs(A22);
  1621. bn = fabs(B11) + fabs(B22);
  1622. wabs = fabs(wr1) + fabs(wi);
  1623. if (scale1*an > wabs*bn)
  1624. {
  1625. cq = cz * B11;
  1626. if (cq <= GSL_DBL_MIN)
  1627. {
  1628. cq = 0.0;
  1629. sqr = 1.0;
  1630. sqi = 0.0;
  1631. }
  1632. else
  1633. {
  1634. sqr = szr * B22;
  1635. sqi = -szi * B22;
  1636. }
  1637. }
  1638. else
  1639. {
  1640. a1r = cz * A11 + szr * A12;
  1641. a1i = szi * A12;
  1642. a2r = cz * A21 + szr * A22;
  1643. a2i = szi * A22;
  1644. cq = hypot(a1r, a1i);
  1645. if (cq <= GSL_DBL_MIN)
  1646. {
  1647. cq = 0.0;
  1648. sqr = 1.0;
  1649. sqi = 0.0;
  1650. }
  1651. else
  1652. {
  1653. tempr = a1r / cq;
  1654. tempi = a1i / cq;
  1655. sqr = tempr * a2r + tempi * a2i;
  1656. sqi = tempi * a2r - tempr * a2i;
  1657. }
  1658. }
  1659. t1 = gsl_hypot3(cq, sqr, sqi);
  1660. cq /= t1;
  1661. sqr /= t1;
  1662. sqi /= t1;
  1663. tempr = sqr*szr - sqi*szi;
  1664. tempi = sqr*szi + sqi*szr;
  1665. b1r = cq*cz*B11 + tempr*B22;
  1666. b1i = tempi*B22;
  1667. b1a = hypot(b1r, b1i);
  1668. b2r = cq*cz*B22 + tempr*B11;
  1669. b2i = -tempi*B11;
  1670. b2a = hypot(b2r, b2i);
  1671. *beta1 = b1a;
  1672. *beta2 = b2a;
  1673. alphar = (wr1 * b1a) * s1inv;
  1674. alphai = (wi * b1a) * s1inv;
  1675. GSL_SET_COMPLEX(alpha1, alphar, alphai);
  1676. alphar = (wr1 * b2a) * s1inv;
  1677. alphai = -(wi * b2a) * s1inv;
  1678. GSL_SET_COMPLEX(alpha2, alphar, alphai);
  1679. return GSL_SUCCESS;
  1680. } /* gen_compute_eigenvals() */
  1681. /*
  1682. gen_store_eigval1()
  1683. Store eigenvalue of a 1-by-1 block into the alpha and beta
  1684. output vectors. This routine ensures that eigenvalues are stored
  1685. in the same order as they appear in the Schur form and updates
  1686. various internal workspace quantities.
  1687. */
  1688. static void
  1689. gen_store_eigval1(const gsl_matrix *H, const double a, const double b,
  1690. gsl_vector_complex *alpha,
  1691. gsl_vector *beta, gsl_eigen_gen_workspace *w)
  1692. {
  1693. size_t top = gen_get_submatrix(w->H, H);
  1694. gsl_complex z;
  1695. GSL_SET_COMPLEX(&z, a, 0.0);
  1696. gsl_vector_complex_set(alpha, top, z);
  1697. gsl_vector_set(beta, top, b);
  1698. w->n_evals += 1;
  1699. w->n_iter = 0;
  1700. w->eshift = 0.0;
  1701. } /* gen_store_eigval1() */
  1702. /*
  1703. gen_store_eigval2()
  1704. Store eigenvalues of a 2-by-2 block into the alpha and beta
  1705. output vectors. This routine ensures that eigenvalues are stored
  1706. in the same order as they appear in the Schur form and updates
  1707. various internal workspace quantities.
  1708. */
  1709. static void
  1710. gen_store_eigval2(const gsl_matrix *H, const gsl_complex *alpha1,
  1711. const double beta1, const gsl_complex *alpha2,
  1712. const double beta2, gsl_vector_complex *alpha,
  1713. gsl_vector *beta, gsl_eigen_gen_workspace *w)
  1714. {
  1715. size_t top = gen_get_submatrix(w->H, H);
  1716. gsl_vector_complex_set(alpha, top, *alpha1);
  1717. gsl_vector_set(beta, top, beta1);
  1718. gsl_vector_complex_set(alpha, top + 1, *alpha2);
  1719. gsl_vector_set(beta, top + 1, beta2);
  1720. w->n_evals += 2;
  1721. w->n_iter = 0;
  1722. w->eshift = 0.0;
  1723. } /* gen_store_eigval2() */
  1724. /*
  1725. gen_get_submatrix()
  1726. B is a submatrix of A. The goal of this function is to
  1727. compute the indices in A of where the matrix B resides
  1728. */
  1729. static inline size_t
  1730. gen_get_submatrix(const gsl_matrix *A, const gsl_matrix *B)
  1731. {
  1732. size_t diff;
  1733. double ratio;
  1734. size_t top;
  1735. diff = (size_t) (B->data - A->data);
  1736. /* B is on the diagonal of A, so measure distance in units of
  1737. tda+1 */
  1738. ratio = (double)diff / ((double) (A->tda + 1));
  1739. top = (size_t) floor(ratio);
  1740. return top;
  1741. } /* gen_get_submatrix() */
  1742. /* Frobenius norm */
  1743. inline static double
  1744. normF (gsl_matrix * A)
  1745. {
  1746. size_t i, j, M = A->size1, N = A->size2;
  1747. double sum = 0.0, scale = 0.0, ssq = 1.0;
  1748. for (i = 0; i < M; i++)
  1749. {
  1750. for (j = 0; j < N; j++)
  1751. {
  1752. double Aij = gsl_matrix_get (A, i, j);
  1753. if (Aij != 0.0)
  1754. {
  1755. double ax = fabs (Aij);
  1756. if (scale < ax)
  1757. {
  1758. ssq = 1.0 + ssq * (scale / ax) * (scale / ax);
  1759. scale = ax;
  1760. }
  1761. else
  1762. {
  1763. ssq += (ax / scale) * (ax / scale);
  1764. }
  1765. }
  1766. }
  1767. }
  1768. sum = scale * sqrt (ssq);
  1769. return sum;
  1770. }
  1771. /* Generate a Givens rotation (cos,sin) which takes v=(x,y) to (|v|,0)
  1772. From Golub and Van Loan, "Matrix Computations", Section 5.1.8 */
  1773. inline static void
  1774. create_givens (const double a, const double b, double *c, double *s)
  1775. {
  1776. if (b == 0)
  1777. {
  1778. *c = 1;
  1779. *s = 0;
  1780. }
  1781. else if (fabs (b) > fabs (a))
  1782. {
  1783. double t = -a / b;
  1784. double s1 = 1.0 / sqrt (1 + t * t);
  1785. *s = s1;
  1786. *c = s1 * t;
  1787. }
  1788. else
  1789. {
  1790. double t = -b / a;
  1791. double c1 = 1.0 / sqrt (1 + t * t);
  1792. *c = c1;
  1793. *s = c1 * t;
  1794. }
  1795. }