gsl_eigen__nonsymmv.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970
  1. /* eigen/nonsymmv.c
  2. *
  3. * Copyright (C) 2006 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_complex.h"
  23. #include "gsl_complex_math.h"
  24. #include "gsl_eigen.h"
  25. #include "gsl_linalg.h"
  26. #include "gsl_math.h"
  27. #include "gsl_blas.h"
  28. #include "gsl_cblas.h"
  29. #include "gsl_vector.h"
  30. #include "gsl_vector_complex.h"
  31. #include "gsl_matrix.h"
  32. /*
  33. * This module computes the eigenvalues and eigenvectors of a real
  34. * nonsymmetric matrix.
  35. *
  36. * This file contains routines based on original code from LAPACK
  37. * which is distributed under the modified BSD license. The LAPACK
  38. * routines used are DTREVC and DLALN2.
  39. */
  40. #define GSL_NONSYMMV_SMLNUM (2.0 * GSL_DBL_MIN)
  41. #define GSL_NONSYMMV_BIGNUM ((1.0 - GSL_DBL_EPSILON) / GSL_NONSYMMV_SMLNUM)
  42. static void nonsymmv_get_right_eigenvectors(gsl_matrix *T, gsl_matrix *Z,
  43. gsl_vector_complex *eval,
  44. gsl_matrix_complex *evec,
  45. gsl_eigen_nonsymmv_workspace *w);
  46. static void nonsymmv_normalize_eigenvectors(gsl_vector_complex *eval,
  47. gsl_matrix_complex *evec);
  48. /*
  49. gsl_eigen_nonsymmv_alloc()
  50. Allocate a workspace for solving the nonsymmetric eigenvalue problem.
  51. The size of this workspace is O(5n).
  52. Inputs: n - size of matrices
  53. Return: pointer to workspace
  54. */
  55. gsl_eigen_nonsymmv_workspace *
  56. gsl_eigen_nonsymmv_alloc(const size_t n)
  57. {
  58. gsl_eigen_nonsymmv_workspace *w;
  59. if (n == 0)
  60. {
  61. GSL_ERROR_NULL ("matrix dimension must be positive integer",
  62. GSL_EINVAL);
  63. }
  64. w = (gsl_eigen_nonsymmv_workspace *)
  65. calloc (1, sizeof (gsl_eigen_nonsymmv_workspace));
  66. if (w == 0)
  67. {
  68. GSL_ERROR_NULL ("failed to allocate space for workspace", GSL_ENOMEM);
  69. }
  70. w->size = n;
  71. w->Z = NULL;
  72. w->nonsymm_workspace_p = gsl_eigen_nonsymm_alloc(n);
  73. if (w->nonsymm_workspace_p == 0)
  74. {
  75. gsl_eigen_nonsymmv_free(w);
  76. GSL_ERROR_NULL ("failed to allocate space for nonsymm workspace", GSL_ENOMEM);
  77. }
  78. /*
  79. * set parameters to compute the full Schur form T and balance
  80. * the matrices
  81. */
  82. gsl_eigen_nonsymm_params(1, 1, w->nonsymm_workspace_p);
  83. w->work = gsl_vector_alloc(n);
  84. w->work2 = gsl_vector_alloc(n);
  85. w->work3 = gsl_vector_alloc(n);
  86. if (w->work == 0 || w->work2 == 0 || w->work3 == 0)
  87. {
  88. gsl_eigen_nonsymmv_free(w);
  89. GSL_ERROR_NULL ("failed to allocate space for nonsymmv additional workspace", GSL_ENOMEM);
  90. }
  91. return (w);
  92. } /* gsl_eigen_nonsymmv_alloc() */
  93. /*
  94. gsl_eigen_nonsymmv_free()
  95. Free workspace w
  96. */
  97. void
  98. gsl_eigen_nonsymmv_free (gsl_eigen_nonsymmv_workspace * w)
  99. {
  100. if (w->nonsymm_workspace_p)
  101. gsl_eigen_nonsymm_free(w->nonsymm_workspace_p);
  102. if (w->work)
  103. gsl_vector_free(w->work);
  104. if (w->work2)
  105. gsl_vector_free(w->work2);
  106. if (w->work3)
  107. gsl_vector_free(w->work3);
  108. free(w);
  109. } /* gsl_eigen_nonsymmv_free() */
  110. /*
  111. gsl_eigen_nonsymmv()
  112. Solve the nonsymmetric eigensystem problem
  113. A x = \lambda x
  114. for the eigenvalues \lambda and right eigenvectors x
  115. Inputs: A - general real matrix
  116. eval - where to store eigenvalues
  117. evec - where to store eigenvectors
  118. w - workspace
  119. Return: success or error
  120. */
  121. int
  122. gsl_eigen_nonsymmv (gsl_matrix * A, gsl_vector_complex * eval,
  123. gsl_matrix_complex * evec,
  124. gsl_eigen_nonsymmv_workspace * w)
  125. {
  126. const size_t N = A->size1;
  127. /* check matrix and vector sizes */
  128. if (N != A->size2)
  129. {
  130. GSL_ERROR ("matrix must be square to compute eigenvalues", GSL_ENOTSQR);
  131. }
  132. else if (eval->size != N)
  133. {
  134. GSL_ERROR ("eigenvalue vector must match matrix size", GSL_EBADLEN);
  135. }
  136. else if (evec->size1 != evec->size2)
  137. {
  138. GSL_ERROR ("eigenvector matrix must be square", GSL_ENOTSQR);
  139. }
  140. else if (evec->size1 != N)
  141. {
  142. GSL_ERROR ("eigenvector matrix has wrong size", GSL_EBADLEN);
  143. }
  144. else
  145. {
  146. int s;
  147. gsl_matrix Z;
  148. /*
  149. * We need a place to store the Schur vectors, so we will
  150. * treat evec as a real matrix and store them in the left
  151. * half - the factor of 2 in the tda corresponds to the
  152. * complex multiplicity
  153. */
  154. Z.size1 = N;
  155. Z.size2 = N;
  156. Z.tda = 2 * N;
  157. Z.data = evec->data;
  158. Z.block = 0;
  159. Z.owner = 0;
  160. /* compute eigenvalues, Schur form, and Schur vectors */
  161. s = gsl_eigen_nonsymm_Z(A, eval, &Z, w->nonsymm_workspace_p);
  162. if (w->Z)
  163. {
  164. /*
  165. * save the Schur vectors in user supplied matrix, since
  166. * they will be destroyed when computing eigenvectors
  167. */
  168. gsl_matrix_memcpy(w->Z, &Z);
  169. }
  170. /* only compute eigenvectors if we found all eigenvalues */
  171. if (s == GSL_SUCCESS)
  172. {
  173. /* compute eigenvectors */
  174. nonsymmv_get_right_eigenvectors(A, &Z, eval, evec, w);
  175. /* normalize so that Euclidean norm is 1 */
  176. nonsymmv_normalize_eigenvectors(eval, evec);
  177. }
  178. return s;
  179. }
  180. } /* gsl_eigen_nonsymmv() */
  181. /*
  182. gsl_eigen_nonsymmv_Z()
  183. Compute eigenvalues and eigenvectors of a real nonsymmetric matrix
  184. and also save the Schur vectors. See comments in gsl_eigen_nonsymm_Z
  185. for more information.
  186. Inputs: A - real nonsymmetric matrix
  187. eval - where to store eigenvalues
  188. evec - where to store eigenvectors
  189. Z - where to store Schur vectors
  190. w - nonsymmv workspace
  191. Return: success or error
  192. */
  193. int
  194. gsl_eigen_nonsymmv_Z (gsl_matrix * A, gsl_vector_complex * eval,
  195. gsl_matrix_complex * evec, gsl_matrix * Z,
  196. gsl_eigen_nonsymmv_workspace * w)
  197. {
  198. /* check matrix and vector sizes */
  199. if (A->size1 != A->size2)
  200. {
  201. GSL_ERROR ("matrix must be square to compute eigenvalues/eigenvectors", GSL_ENOTSQR);
  202. }
  203. else if (eval->size != A->size1)
  204. {
  205. GSL_ERROR ("eigenvalue vector must match matrix size", GSL_EBADLEN);
  206. }
  207. else if (evec->size1 != evec->size2)
  208. {
  209. GSL_ERROR ("eigenvector matrix must be square", GSL_ENOTSQR);
  210. }
  211. else if (evec->size1 != A->size1)
  212. {
  213. GSL_ERROR ("eigenvector matrix has wrong size", GSL_EBADLEN);
  214. }
  215. else if ((Z->size1 != Z->size2) || (Z->size1 != A->size1))
  216. {
  217. GSL_ERROR ("Z matrix has wrong dimensions", GSL_EBADLEN);
  218. }
  219. else
  220. {
  221. int s;
  222. w->Z = Z;
  223. s = gsl_eigen_nonsymmv(A, eval, evec, w);
  224. w->Z = NULL;
  225. return s;
  226. }
  227. } /* gsl_eigen_nonsymmv_Z() */
  228. /********************************************
  229. * INTERNAL ROUTINES *
  230. ********************************************/
  231. /*
  232. nonsymmv_get_right_eigenvectors()
  233. Compute the right eigenvectors of the Schur form T and then
  234. backtransform them using the Schur vectors to get right eigenvectors of
  235. the original matrix.
  236. Inputs: T - Schur form
  237. Z - Schur vectors
  238. eval - where to store eigenvalues (to ensure that the
  239. correct eigenvalue is stored in the same position
  240. as the eigenvectors)
  241. evec - where to store eigenvectors
  242. w - nonsymmv workspace
  243. Return: none
  244. Notes: 1) based on LAPACK routine DTREVC - the algorithm used is
  245. backsubstitution on the upper quasi triangular system T
  246. followed by backtransformation by Z to get vectors of the
  247. original matrix.
  248. 2) The Schur vectors in Z are destroyed and replaced with
  249. eigenvectors stored with the same storage scheme as DTREVC.
  250. The eigenvectors are also stored in 'evec'
  251. 3) The matrix T is unchanged on output
  252. 4) Each eigenvector is normalized so that the element of
  253. largest magnitude has magnitude 1; here the magnitude of
  254. a complex number (x,y) is taken to be |x| + |y|
  255. */
  256. static void
  257. nonsymmv_get_right_eigenvectors(gsl_matrix *T, gsl_matrix *Z,
  258. gsl_vector_complex *eval,
  259. gsl_matrix_complex *evec,
  260. gsl_eigen_nonsymmv_workspace *w)
  261. {
  262. const size_t N = T->size1;
  263. const double smlnum = GSL_DBL_MIN * N / GSL_DBL_EPSILON;
  264. const double bignum = (1.0 - GSL_DBL_EPSILON) / smlnum;
  265. int i; /* looping */
  266. size_t iu, /* looping */
  267. ju,
  268. ii;
  269. gsl_complex lambda; /* current eigenvalue */
  270. double lambda_re, /* Re(lambda) */
  271. lambda_im; /* Im(lambda) */
  272. gsl_matrix_view Tv, /* temporary views */
  273. Zv;
  274. gsl_vector_view y, /* temporary views */
  275. y2,
  276. ev,
  277. ev2;
  278. double dat[4], /* scratch arrays */
  279. dat_X[4];
  280. double scale; /* scale factor */
  281. double xnorm; /* |X| */
  282. gsl_vector_complex_view ecol, /* column of evec */
  283. ecol2;
  284. int complex_pair; /* complex eigenvalue pair? */
  285. double smin;
  286. /*
  287. * Compute 1-norm of each column of upper triangular part of T
  288. * to control overflow in triangular solver
  289. */
  290. gsl_vector_set(w->work3, 0, 0.0);
  291. for (ju = 1; ju < N; ++ju)
  292. {
  293. gsl_vector_set(w->work3, ju, 0.0);
  294. for (iu = 0; iu < ju; ++iu)
  295. {
  296. gsl_vector_set(w->work3, ju,
  297. gsl_vector_get(w->work3, ju) +
  298. fabs(gsl_matrix_get(T, iu, ju)));
  299. }
  300. }
  301. for (i = (int) N - 1; i >= 0; --i)
  302. {
  303. iu = (size_t) i;
  304. /* get current eigenvalue and store it in lambda */
  305. lambda_re = gsl_matrix_get(T, iu, iu);
  306. if (iu != 0 && gsl_matrix_get(T, iu, iu - 1) != 0.0)
  307. {
  308. lambda_im = sqrt(fabs(gsl_matrix_get(T, iu, iu - 1))) *
  309. sqrt(fabs(gsl_matrix_get(T, iu - 1, iu)));
  310. }
  311. else
  312. {
  313. lambda_im = 0.0;
  314. }
  315. GSL_SET_COMPLEX(&lambda, lambda_re, lambda_im);
  316. smin = GSL_MAX(GSL_DBL_EPSILON * (fabs(lambda_re) + fabs(lambda_im)),
  317. smlnum);
  318. smin = GSL_MAX(smin, GSL_NONSYMMV_SMLNUM);
  319. if (lambda_im == 0.0)
  320. {
  321. int k, l;
  322. gsl_vector_view bv, xv;
  323. /* real eigenvector */
  324. /*
  325. * The ordering of eigenvalues in 'eval' is arbitrary and
  326. * does not necessarily follow the Schur form T, so store
  327. * lambda in the right slot in eval to ensure it corresponds
  328. * to the eigenvector we are about to compute
  329. */
  330. gsl_vector_complex_set(eval, iu, lambda);
  331. /*
  332. * We need to solve the system:
  333. *
  334. * (T(1:iu-1, 1:iu-1) - lambda*I)*X = -T(1:iu-1,iu)
  335. */
  336. /* construct right hand side */
  337. for (k = 0; k < i; ++k)
  338. {
  339. gsl_vector_set(w->work,
  340. (size_t) k,
  341. -gsl_matrix_get(T, (size_t) k, iu));
  342. }
  343. gsl_vector_set(w->work, iu, 1.0);
  344. for (l = i - 1; l >= 0; --l)
  345. {
  346. size_t lu = (size_t) l;
  347. if (lu == 0)
  348. complex_pair = 0;
  349. else
  350. complex_pair = gsl_matrix_get(T, lu, lu - 1) != 0.0;
  351. if (!complex_pair)
  352. {
  353. double x;
  354. /*
  355. * 1-by-1 diagonal block - solve the system:
  356. *
  357. * (T_{ll} - lambda)*x = -T_{l(iu)}
  358. */
  359. Tv = gsl_matrix_submatrix(T, lu, lu, 1, 1);
  360. bv = gsl_vector_view_array(dat, 1);
  361. gsl_vector_set(&bv.vector, 0,
  362. gsl_vector_get(w->work, lu));
  363. xv = gsl_vector_view_array(dat_X, 1);
  364. gsl_schur_solve_equation(1.0,
  365. &Tv.matrix,
  366. lambda_re,
  367. 1.0,
  368. 1.0,
  369. &bv.vector,
  370. &xv.vector,
  371. &scale,
  372. &xnorm,
  373. smin);
  374. /* scale x to avoid overflow */
  375. x = gsl_vector_get(&xv.vector, 0);
  376. if (xnorm > 1.0)
  377. {
  378. if (gsl_vector_get(w->work3, lu) > bignum / xnorm)
  379. {
  380. x /= xnorm;
  381. scale /= xnorm;
  382. }
  383. }
  384. if (scale != 1.0)
  385. {
  386. gsl_vector_view wv;
  387. wv = gsl_vector_subvector(w->work, 0, iu + 1);
  388. gsl_blas_dscal(scale, &wv.vector);
  389. }
  390. gsl_vector_set(w->work, lu, x);
  391. if (lu > 0)
  392. {
  393. gsl_vector_view v1, v2;
  394. /* update right hand side */
  395. v1 = gsl_matrix_subcolumn(T, lu, 0, lu);
  396. v2 = gsl_vector_subvector(w->work, 0, lu);
  397. gsl_blas_daxpy(-x, &v1.vector, &v2.vector);
  398. } /* if (l > 0) */
  399. } /* if (!complex_pair) */
  400. else
  401. {
  402. double x11, x21;
  403. /*
  404. * 2-by-2 diagonal block
  405. */
  406. Tv = gsl_matrix_submatrix(T, lu - 1, lu - 1, 2, 2);
  407. bv = gsl_vector_view_array(dat, 2);
  408. gsl_vector_set(&bv.vector, 0,
  409. gsl_vector_get(w->work, lu - 1));
  410. gsl_vector_set(&bv.vector, 1,
  411. gsl_vector_get(w->work, lu));
  412. xv = gsl_vector_view_array(dat_X, 2);
  413. gsl_schur_solve_equation(1.0,
  414. &Tv.matrix,
  415. lambda_re,
  416. 1.0,
  417. 1.0,
  418. &bv.vector,
  419. &xv.vector,
  420. &scale,
  421. &xnorm,
  422. smin);
  423. /* scale X(1,1) and X(2,1) to avoid overflow */
  424. x11 = gsl_vector_get(&xv.vector, 0);
  425. x21 = gsl_vector_get(&xv.vector, 1);
  426. if (xnorm > 1.0)
  427. {
  428. double beta;
  429. beta = GSL_MAX(gsl_vector_get(w->work3, lu - 1),
  430. gsl_vector_get(w->work3, lu));
  431. if (beta > bignum / xnorm)
  432. {
  433. x11 /= xnorm;
  434. x21 /= xnorm;
  435. scale /= xnorm;
  436. }
  437. }
  438. /* scale if necessary */
  439. if (scale != 1.0)
  440. {
  441. gsl_vector_view wv;
  442. wv = gsl_vector_subvector(w->work, 0, iu + 1);
  443. gsl_blas_dscal(scale, &wv.vector);
  444. }
  445. gsl_vector_set(w->work, lu - 1, x11);
  446. gsl_vector_set(w->work, lu, x21);
  447. /* update right hand side */
  448. if (lu > 1)
  449. {
  450. gsl_vector_view v1, v2;
  451. v1 = gsl_matrix_subcolumn(T, lu - 1, 0, lu - 1);
  452. v2 = gsl_vector_subvector(w->work, 0, lu - 1);
  453. gsl_blas_daxpy(-x11, &v1.vector, &v2.vector);
  454. v1 = gsl_matrix_subcolumn(T, lu, 0, lu - 1);
  455. gsl_blas_daxpy(-x21, &v1.vector, &v2.vector);
  456. }
  457. --l;
  458. } /* if (complex_pair) */
  459. } /* for (l = i - 1; l >= 0; --l) */
  460. /*
  461. * At this point, w->work is an eigenvector of the
  462. * Schur form T. To get an eigenvector of the original
  463. * matrix, we multiply on the left by Z, the matrix of
  464. * Schur vectors
  465. */
  466. ecol = gsl_matrix_complex_column(evec, iu);
  467. y = gsl_matrix_column(Z, iu);
  468. if (iu > 0)
  469. {
  470. gsl_vector_view x;
  471. Zv = gsl_matrix_submatrix(Z, 0, 0, N, iu);
  472. x = gsl_vector_subvector(w->work, 0, iu);
  473. /* compute Z * w->work and store it in Z(:,iu) */
  474. gsl_blas_dgemv(CblasNoTrans,
  475. 1.0,
  476. &Zv.matrix,
  477. &x.vector,
  478. gsl_vector_get(w->work, iu),
  479. &y.vector);
  480. } /* if (iu > 0) */
  481. /* store eigenvector into evec */
  482. ev = gsl_vector_complex_real(&ecol.vector);
  483. ev2 = gsl_vector_complex_imag(&ecol.vector);
  484. scale = 0.0;
  485. for (ii = 0; ii < N; ++ii)
  486. {
  487. double a = gsl_vector_get(&y.vector, ii);
  488. /* store real part of eigenvector */
  489. gsl_vector_set(&ev.vector, ii, a);
  490. /* set imaginary part to 0 */
  491. gsl_vector_set(&ev2.vector, ii, 0.0);
  492. if (fabs(a) > scale)
  493. scale = fabs(a);
  494. }
  495. if (scale != 0.0)
  496. scale = 1.0 / scale;
  497. /* scale by magnitude of largest element */
  498. gsl_blas_dscal(scale, &ev.vector);
  499. } /* if (GSL_IMAG(lambda) == 0.0) */
  500. else
  501. {
  502. gsl_vector_complex_view bv, xv;
  503. size_t k;
  504. int l;
  505. gsl_complex lambda2;
  506. /* complex eigenvector */
  507. /*
  508. * Store the complex conjugate eigenvalues in the right
  509. * slots in eval
  510. */
  511. GSL_SET_REAL(&lambda2, GSL_REAL(lambda));
  512. GSL_SET_IMAG(&lambda2, -GSL_IMAG(lambda));
  513. gsl_vector_complex_set(eval, iu - 1, lambda);
  514. gsl_vector_complex_set(eval, iu, lambda2);
  515. /*
  516. * First solve:
  517. *
  518. * [ T(i:i+1,i:i+1) - lambda*I ] * X = 0
  519. */
  520. if (fabs(gsl_matrix_get(T, iu - 1, iu)) >=
  521. fabs(gsl_matrix_get(T, iu, iu - 1)))
  522. {
  523. gsl_vector_set(w->work, iu - 1, 1.0);
  524. gsl_vector_set(w->work2, iu,
  525. lambda_im / gsl_matrix_get(T, iu - 1, iu));
  526. }
  527. else
  528. {
  529. gsl_vector_set(w->work, iu - 1,
  530. -lambda_im / gsl_matrix_get(T, iu, iu - 1));
  531. gsl_vector_set(w->work2, iu, 1.0);
  532. }
  533. gsl_vector_set(w->work, iu, 0.0);
  534. gsl_vector_set(w->work2, iu - 1, 0.0);
  535. /* construct right hand side */
  536. for (k = 0; k < iu - 1; ++k)
  537. {
  538. gsl_vector_set(w->work, k,
  539. -gsl_vector_get(w->work, iu - 1) *
  540. gsl_matrix_get(T, k, iu - 1));
  541. gsl_vector_set(w->work2, k,
  542. -gsl_vector_get(w->work2, iu) *
  543. gsl_matrix_get(T, k, iu));
  544. }
  545. /*
  546. * We must solve the upper quasi-triangular system:
  547. *
  548. * [ T(1:i-2,1:i-2) - lambda*I ] * X = s*(work + i*work2)
  549. */
  550. for (l = i - 2; l >= 0; --l)
  551. {
  552. size_t lu = (size_t) l;
  553. if (lu == 0)
  554. complex_pair = 0;
  555. else
  556. complex_pair = gsl_matrix_get(T, lu, lu - 1) != 0.0;
  557. if (!complex_pair)
  558. {
  559. gsl_complex bval;
  560. gsl_complex x;
  561. /*
  562. * 1-by-1 diagonal block - solve the system:
  563. *
  564. * (T_{ll} - lambda)*x = work + i*work2
  565. */
  566. Tv = gsl_matrix_submatrix(T, lu, lu, 1, 1);
  567. bv = gsl_vector_complex_view_array(dat, 1);
  568. xv = gsl_vector_complex_view_array(dat_X, 1);
  569. GSL_SET_COMPLEX(&bval,
  570. gsl_vector_get(w->work, lu),
  571. gsl_vector_get(w->work2, lu));
  572. gsl_vector_complex_set(&bv.vector, 0, bval);
  573. gsl_schur_solve_equation_z(1.0,
  574. &Tv.matrix,
  575. &lambda,
  576. 1.0,
  577. 1.0,
  578. &bv.vector,
  579. &xv.vector,
  580. &scale,
  581. &xnorm,
  582. smin);
  583. if (xnorm > 1.0)
  584. {
  585. if (gsl_vector_get(w->work3, lu) > bignum / xnorm)
  586. {
  587. gsl_blas_zdscal(1.0/xnorm, &xv.vector);
  588. scale /= xnorm;
  589. }
  590. }
  591. /* scale if necessary */
  592. if (scale != 1.0)
  593. {
  594. gsl_vector_view wv;
  595. wv = gsl_vector_subvector(w->work, 0, iu + 1);
  596. gsl_blas_dscal(scale, &wv.vector);
  597. wv = gsl_vector_subvector(w->work2, 0, iu + 1);
  598. gsl_blas_dscal(scale, &wv.vector);
  599. }
  600. x = gsl_vector_complex_get(&xv.vector, 0);
  601. gsl_vector_set(w->work, lu, GSL_REAL(x));
  602. gsl_vector_set(w->work2, lu, GSL_IMAG(x));
  603. /* update the right hand side */
  604. if (lu > 0)
  605. {
  606. gsl_vector_view v1, v2;
  607. v1 = gsl_matrix_subcolumn(T, lu, 0, lu);
  608. v2 = gsl_vector_subvector(w->work, 0, lu);
  609. gsl_blas_daxpy(-GSL_REAL(x), &v1.vector, &v2.vector);
  610. v2 = gsl_vector_subvector(w->work2, 0, lu);
  611. gsl_blas_daxpy(-GSL_IMAG(x), &v1.vector, &v2.vector);
  612. } /* if (lu > 0) */
  613. } /* if (!complex_pair) */
  614. else
  615. {
  616. gsl_complex b1, b2, x1, x2;
  617. /*
  618. * 2-by-2 diagonal block - solve the system
  619. */
  620. Tv = gsl_matrix_submatrix(T, lu - 1, lu - 1, 2, 2);
  621. bv = gsl_vector_complex_view_array(dat, 2);
  622. xv = gsl_vector_complex_view_array(dat_X, 2);
  623. GSL_SET_COMPLEX(&b1,
  624. gsl_vector_get(w->work, lu - 1),
  625. gsl_vector_get(w->work2, lu - 1));
  626. GSL_SET_COMPLEX(&b2,
  627. gsl_vector_get(w->work, lu),
  628. gsl_vector_get(w->work2, lu));
  629. gsl_vector_complex_set(&bv.vector, 0, b1);
  630. gsl_vector_complex_set(&bv.vector, 1, b2);
  631. gsl_schur_solve_equation_z(1.0,
  632. &Tv.matrix,
  633. &lambda,
  634. 1.0,
  635. 1.0,
  636. &bv.vector,
  637. &xv.vector,
  638. &scale,
  639. &xnorm,
  640. smin);
  641. x1 = gsl_vector_complex_get(&xv.vector, 0);
  642. x2 = gsl_vector_complex_get(&xv.vector, 1);
  643. if (xnorm > 1.0)
  644. {
  645. double beta;
  646. beta = GSL_MAX(gsl_vector_get(w->work3, lu - 1),
  647. gsl_vector_get(w->work3, lu));
  648. if (beta > bignum / xnorm)
  649. {
  650. gsl_blas_zdscal(1.0/xnorm, &xv.vector);
  651. scale /= xnorm;
  652. }
  653. }
  654. /* scale if necessary */
  655. if (scale != 1.0)
  656. {
  657. gsl_vector_view wv;
  658. wv = gsl_vector_subvector(w->work, 0, iu + 1);
  659. gsl_blas_dscal(scale, &wv.vector);
  660. wv = gsl_vector_subvector(w->work2, 0, iu + 1);
  661. gsl_blas_dscal(scale, &wv.vector);
  662. }
  663. gsl_vector_set(w->work, lu - 1, GSL_REAL(x1));
  664. gsl_vector_set(w->work, lu, GSL_REAL(x2));
  665. gsl_vector_set(w->work2, lu - 1, GSL_IMAG(x1));
  666. gsl_vector_set(w->work2, lu, GSL_IMAG(x2));
  667. /* update right hand side */
  668. if (lu > 1)
  669. {
  670. gsl_vector_view v1, v2, v3, v4;
  671. v1 = gsl_matrix_subcolumn(T, lu - 1, 0, lu - 1);
  672. v4 = gsl_matrix_subcolumn(T, lu, 0, lu - 1);
  673. v2 = gsl_vector_subvector(w->work, 0, lu - 1);
  674. v3 = gsl_vector_subvector(w->work2, 0, lu - 1);
  675. gsl_blas_daxpy(-GSL_REAL(x1), &v1.vector, &v2.vector);
  676. gsl_blas_daxpy(-GSL_REAL(x2), &v4.vector, &v2.vector);
  677. gsl_blas_daxpy(-GSL_IMAG(x1), &v1.vector, &v3.vector);
  678. gsl_blas_daxpy(-GSL_IMAG(x2), &v4.vector, &v3.vector);
  679. } /* if (lu > 1) */
  680. --l;
  681. } /* if (complex_pair) */
  682. } /* for (l = i - 2; l >= 0; --l) */
  683. /*
  684. * At this point, work + i*work2 is an eigenvector
  685. * of T - backtransform to get an eigenvector of the
  686. * original matrix
  687. */
  688. y = gsl_matrix_column(Z, iu - 1);
  689. y2 = gsl_matrix_column(Z, iu);
  690. if (iu > 1)
  691. {
  692. gsl_vector_view x;
  693. /* compute real part of eigenvectors */
  694. Zv = gsl_matrix_submatrix(Z, 0, 0, N, iu - 1);
  695. x = gsl_vector_subvector(w->work, 0, iu - 1);
  696. gsl_blas_dgemv(CblasNoTrans,
  697. 1.0,
  698. &Zv.matrix,
  699. &x.vector,
  700. gsl_vector_get(w->work, iu - 1),
  701. &y.vector);
  702. /* now compute the imaginary part */
  703. x = gsl_vector_subvector(w->work2, 0, iu - 1);
  704. gsl_blas_dgemv(CblasNoTrans,
  705. 1.0,
  706. &Zv.matrix,
  707. &x.vector,
  708. gsl_vector_get(w->work2, iu),
  709. &y2.vector);
  710. }
  711. else
  712. {
  713. gsl_blas_dscal(gsl_vector_get(w->work, iu - 1), &y.vector);
  714. gsl_blas_dscal(gsl_vector_get(w->work2, iu), &y2.vector);
  715. }
  716. /*
  717. * Now store the eigenvectors into evec - the real parts
  718. * are Z(:,iu - 1) and the imaginary parts are
  719. * +/- Z(:,iu)
  720. */
  721. /* get views of the two eigenvector slots */
  722. ecol = gsl_matrix_complex_column(evec, iu - 1);
  723. ecol2 = gsl_matrix_complex_column(evec, iu);
  724. /*
  725. * save imaginary part first as it may get overwritten
  726. * when copying the real part due to our storage scheme
  727. * in Z/evec
  728. */
  729. ev = gsl_vector_complex_imag(&ecol.vector);
  730. ev2 = gsl_vector_complex_imag(&ecol2.vector);
  731. scale = 0.0;
  732. for (ii = 0; ii < N; ++ii)
  733. {
  734. double a = gsl_vector_get(&y2.vector, ii);
  735. scale = GSL_MAX(scale,
  736. fabs(a) + fabs(gsl_vector_get(&y.vector, ii)));
  737. gsl_vector_set(&ev.vector, ii, a);
  738. gsl_vector_set(&ev2.vector, ii, -a);
  739. }
  740. /* now save the real part */
  741. ev = gsl_vector_complex_real(&ecol.vector);
  742. ev2 = gsl_vector_complex_real(&ecol2.vector);
  743. for (ii = 0; ii < N; ++ii)
  744. {
  745. double a = gsl_vector_get(&y.vector, ii);
  746. gsl_vector_set(&ev.vector, ii, a);
  747. gsl_vector_set(&ev2.vector, ii, a);
  748. }
  749. if (scale != 0.0)
  750. scale = 1.0 / scale;
  751. /* scale by largest element magnitude */
  752. gsl_blas_zdscal(scale, &ecol.vector);
  753. gsl_blas_zdscal(scale, &ecol2.vector);
  754. /*
  755. * decrement i since we took care of two eigenvalues at
  756. * the same time
  757. */
  758. --i;
  759. } /* if (GSL_IMAG(lambda) != 0.0) */
  760. } /* for (i = (int) N - 1; i >= 0; --i) */
  761. } /* nonsymmv_get_right_eigenvectors() */
  762. /*
  763. nonsymmv_normalize_eigenvectors()
  764. Normalize eigenvectors so that their Euclidean norm is 1
  765. Inputs: eval - eigenvalues
  766. evec - eigenvectors
  767. */
  768. static void
  769. nonsymmv_normalize_eigenvectors(gsl_vector_complex *eval,
  770. gsl_matrix_complex *evec)
  771. {
  772. const size_t N = evec->size1;
  773. size_t i; /* looping */
  774. gsl_complex ei;
  775. gsl_vector_complex_view vi;
  776. gsl_vector_view re, im;
  777. double scale; /* scaling factor */
  778. for (i = 0; i < N; ++i)
  779. {
  780. ei = gsl_vector_complex_get(eval, i);
  781. vi = gsl_matrix_complex_column(evec, i);
  782. re = gsl_vector_complex_real(&vi.vector);
  783. if (GSL_IMAG(ei) == 0.0)
  784. {
  785. scale = 1.0 / gsl_blas_dnrm2(&re.vector);
  786. gsl_blas_dscal(scale, &re.vector);
  787. }
  788. else if (GSL_IMAG(ei) > 0.0)
  789. {
  790. im = gsl_vector_complex_imag(&vi.vector);
  791. scale = 1.0 / gsl_hypot(gsl_blas_dnrm2(&re.vector),
  792. gsl_blas_dnrm2(&im.vector));
  793. gsl_blas_zdscal(scale, &vi.vector);
  794. vi = gsl_matrix_complex_column(evec, i + 1);
  795. gsl_blas_zdscal(scale, &vi.vector);
  796. }
  797. }
  798. } /* nonsymmv_normalize_eigenvectors() */