You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

805 lines
25 KiB

  1. /* -*- c++ -*- (enables emacs c++ mode) */
  2. /*===========================================================================
  3. Copyright (C) 2003-2017 Yves Renard, Caroline Lecalvez
  4. This file is a part of GetFEM++
  5. GetFEM++ is free software; you can redistribute it and/or modify it
  6. under the terms of the GNU Lesser General Public License as published
  7. by the Free Software Foundation; either version 3 of the License, or
  8. (at your option) any later version along with the GCC Runtime Library
  9. Exception either version 3.1 or (at your option) any later version.
  10. This program is distributed in the hope that it will be useful, but
  11. WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  12. or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  13. License and GCC Runtime Library Exception for more details.
  14. You should have received a copy of the GNU Lesser General Public License
  15. along with this program; if not, write to the Free Software Foundation,
  16. Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  17. As a special exception, you may use this file as it is a part of a free
  18. software library without restriction. Specifically, if other files
  19. instantiate templates or use macros or inline functions from this file,
  20. or you compile this file and link it with other files to produce an
  21. executable, this file does not by itself cause the resulting executable
  22. to be covered by the GNU Lesser General Public License. This exception
  23. does not however invalidate any other reasons why the executable file
  24. might be covered by the GNU Lesser General Public License.
  25. ===========================================================================*/
  26. /**@file gmm_solver_idgmres.h
  27. @author Caroline Lecalvez <Caroline.Lecalvez@gmm.insa-tlse.fr>
  28. @author Yves Renard <Yves.Renard@insa-lyon.fr>
  29. @date October 6, 2003.
  30. @brief Implicitly restarted and deflated Generalized Minimum Residual.
  31. */
  32. #ifndef GMM_IDGMRES_H
  33. #define GMM_IDGMRES_H
  34. #include "gmm_kernel.h"
  35. #include "gmm_iter.h"
  36. #include "gmm_dense_sylvester.h"
  37. namespace gmm {
  38. template <typename T> compare_vp {
  39. bool operator()(const std::pair<T, size_type> &a,
  40. const std::pair<T, size_type> &b) const
  41. { return (gmm::abs(a.first) > gmm::abs(b.first)); }
  42. }
  43. struct idgmres_state {
  44. size_type m, tb_deb, tb_def, p, k, nb_want, nb_unwant;
  45. size_type nb_nolong, tb_deftot, tb_defwant, conv, nb_un, fin;
  46. bool ok;
  47. idgmres_state(size_type mm, size_type pp, size_type kk)
  48. : m(mm), tb_deb(1), tb_def(0), p(pp), k(kk), nb_want(0),
  49. nb_unwant(0), nb_nolong(0), tb_deftot(0), tb_defwant(0),
  50. conv(0), nb_un(0), fin(0), ok(false); {}
  51. }
  52. idgmres_state(size_type mm, size_type pp, size_type kk)
  53. : m(mm), tb_deb(1), tb_def(0), p(pp), k(kk), nb_want(0),
  54. nb_unwant(0), nb_nolong(0), tb_deftot(0), tb_defwant(0),
  55. conv(0), nb_un(0), fin(0), ok(false); {}
  56. template <typename CONT, typename IND>
  57. apply_permutation(CONT &cont, const IND &ind) {
  58. size_type m = ind.end() - ind.begin();
  59. std::vector<bool> sorted(m, false);
  60. for (size_type l = 0; l < m; ++l)
  61. if (!sorted[l] && ind[l] != l) {
  62. typeid(cont[0]) aux = cont[l];
  63. k = ind[l];
  64. cont[l] = cont[k];
  65. sorted[l] = true;
  66. for(k2 = ind[k]; k2 != l; k2 = ind[k]) {
  67. cont[k] = cont[k2];
  68. sorted[k] = true;
  69. k = k2;
  70. }
  71. cont[k] = aux;
  72. }
  73. }
  74. /** Implicitly restarted and deflated Generalized Minimum Residual
  75. See: C. Le Calvez, B. Molina, Implicitly restarted and deflated
  76. FOM and GMRES, numerical applied mathematics,
  77. (30) 2-3 (1999) pp191-212.
  78. @param A Real or complex unsymmetric matrix.
  79. @param x initial guess vector and final result.
  80. @param b right hand side
  81. @param M preconditionner
  82. @param m size of the subspace between two restarts
  83. @param p number of converged ritz values seeked
  84. @param k size of the remaining Krylov subspace when the p ritz values
  85. have not yet converged 0 <= p <= k < m.
  86. @param tol_vp : tolerance on the ritz values.
  87. @param outer
  88. @param KS
  89. */
  90. template < typename Mat, typename Vec, typename VecB, typename Precond,
  91. typename Basis >
  92. void idgmres(const Mat &A, Vec &x, const VecB &b, const Precond &M,
  93. size_type m, size_type p, size_type k, double tol_vp,
  94. iteration &outer, Basis& KS) {
  95. typedef typename linalg_traits<Mat>::value_type T;
  96. typedef typename number_traits<T>::magnitude_type R;
  97. R a, beta;
  98. idgmres_state st(m, p, k);
  99. std::vector<T> w(vect_size(x)), r(vect_size(x)), u(vect_size(x));
  100. std::vector<T> c_rot(m+1), s_rot(m+1), s(m+1);
  101. std::vector<T> y(m+1), ztest(m+1), gam(m+1);
  102. std::vector<T> gamma(m+1);
  103. gmm::dense_matrix<T> H(m+1, m), Hess(m+1, m),
  104. Hobl(m+1, m), W(vect_size(x), m+1);
  105. gmm::clear(H);
  106. outer.set_rhsnorm(gmm::vect_norm2(b));
  107. if (outer.get_rhsnorm() == 0.0) { clear(x); return; }
  108. mult(A, scaled(x, -1.0), b, w);
  109. mult(M, w, r);
  110. beta = gmm::vect_norm2(r);
  111. iteration inner = outer;
  112. inner.reduce_noisy();
  113. inner.set_maxiter(m);
  114. inner.set_name("GMRes inner iter");
  115. while (! outer.finished(beta)) {
  116. gmm::copy(gmm::scaled(r, 1.0/beta), KS[0]);
  117. gmm::clear(s);
  118. s[0] = beta;
  119. gmm::copy(s, gamma);
  120. inner.set_maxiter(m - st.tb_deb + 1);
  121. size_type i = st.tb_deb - 1; inner.init();
  122. do {
  123. mult(A, KS[i], u);
  124. mult(M, u, KS[i+1]);
  125. orthogonalize_with_refinment(KS, mat_col(H, i), i);
  126. H(i+1, i) = a = gmm::vect_norm2(KS[i+1]);
  127. gmm::scale(KS[i+1], R(1) / a);
  128. gmm::copy(mat_col(H, i), mat_col(Hess, i));
  129. gmm::copy(mat_col(H, i), mat_col(Hobl, i));
  130. for (size_type l = 0; l < i; ++l)
  131. Apply_Givens_rotation_left(H(l,i), H(l+1,i), c_rot[l], s_rot[l]);
  132. Givens_rotation(H(i,i), H(i+1,i), c_rot[i], s_rot[i]);
  133. Apply_Givens_rotation_left(H(i,i), H(i+1,i), c_rot[i], s_rot[i]);
  134. H(i+1, i) = T(0);
  135. Apply_Givens_rotation_left(s[i], s[i+1], c_rot[i], s_rot[i]);
  136. ++inner, ++outer, ++i;
  137. } while (! inner.finished(gmm::abs(s[i])));
  138. if (inner.converged()) {
  139. gmm::copy(s, y);
  140. upper_tri_solve(H, y, i, false);
  141. combine(KS, y, x, i);
  142. mult(A, gmm::scaled(x, T(-1)), b, w);
  143. mult(M, w, r);
  144. beta = gmm::vect_norm2(r); // + verif sur beta ... � faire
  145. break;
  146. }
  147. gmm::clear(gam); gam[m] = s[i];
  148. for (size_type l = m; l > 0; --l)
  149. Apply_Givens_rotation_left(gam[l-1], gam[l], gmm::conj(c_rot[l-1]),
  150. -s_rot[l-1]);
  151. mult(KS.mat(), gam, r);
  152. beta = gmm::vect_norm2(r);
  153. mult(Hess, scaled(y, T(-1)), gamma, ztest);
  154. // En fait, d'apr�s Caroline qui s'y connait ztest et gam devrait
  155. // �tre confondus
  156. // Quand on aura v�rifi� que �a marche, il faudra utiliser gam � la
  157. // place de ztest.
  158. if (st.tb_def < p) {
  159. T nss = H(m,m-1) / ztest[m];
  160. nss /= gmm::abs(nss); // ns � calculer plus tard aussi
  161. gmm::copy(KS.mat(), W); gmm::copy(scaled(r, nss /beta), mat_col(W, m));
  162. // Computation of the oblique matrix
  163. sub_interval SUBI(0, m);
  164. add(scaled(sub_vector(ztest, SUBI), -Hobl(m, m-1) / ztest[m]),
  165. sub_vector(mat_col(Hobl, m-1), SUBI));
  166. Hobl(m, m-1) *= nss * beta / ztest[m];
  167. /* **************************************************************** */
  168. /* Locking */
  169. /* **************************************************************** */
  170. // Computation of the Ritz eigenpairs.
  171. std::vector<std::complex<R> > eval(m);
  172. dense_matrix<T> YB(m-st.tb_def, m-st.tb_def);
  173. std::vector<char> pure(m-st.tb_def, 0);
  174. gmm::clear(YB);
  175. select_eval(Hobl, eval, YB, pure, st);
  176. if (st.conv != 0) {
  177. // DEFLATION using the QR Factorization of YB
  178. T alpha = Lock(W, Hobl,
  179. sub_matrix(YB, sub_interval(0, m-st.tb_def)),
  180. sub_interval(st.tb_def, m-st.tb_def),
  181. (st.tb_defwant < p));
  182. // ns *= alpha; // � calculer plus tard ??
  183. // V(:,m+1) = alpha*V(:, m+1); �a devait servir � qlq chose ...
  184. // Clean the portions below the diagonal corresponding
  185. // to the lock Schur vectors
  186. for (size_type j = st.tb_def; j < st.tb_deftot; ++j) {
  187. if ( pure[j-st.tb_def] == 0)
  188. gmm::clear(sub_vector(mat_col(Hobl,j), sub_interval(j+1,m-j)));
  189. else if (pure[j-st.tb_def] == 1) {
  190. gmm::clear(sub_matrix(Hobl, sub_interval(j+2,m-j-1),
  191. sub_interval(j, 2)));
  192. ++j;
  193. }
  194. else GMM_ASSERT3(false, "internal error");
  195. }
  196. if (!st.ok) {
  197. // attention si m = 0;
  198. size_type mm = std::min(k+st.nb_unwant+st.nb_nolong, m-1);
  199. if (eval_sort[m-mm-1].second != R(0)
  200. && eval_sort[m-mm-1].second == -eval_sort[m-mm].second) ++mm;
  201. std::vector<complex<R> > shifts(m-mm);
  202. for (size_type i = 0; i < m-mm; ++i)
  203. shifts[i] = eval_sort[i].second;
  204. apply_shift_to_Arnoldi_factorization(W, Hobl, shifts, mm,
  205. m-mm, true);
  206. st.fin = mm;
  207. }
  208. else
  209. st.fin = st.tb_deftot;
  210. /* ************************************************************** */
  211. /* Purge */
  212. /* ************************************************************** */
  213. if (st.nb_nolong + st.nb_unwant > 0) {
  214. std::vector<std::complex<R> > eval(m);
  215. dense_matrix<T> YB(st.fin, st.tb_deftot);
  216. std::vector<char> pure(st.tb_deftot, 0);
  217. gmm::clear(YB);
  218. st.nb_un = st.nb_nolong + st.nb_unwant;
  219. select_eval_for_purging(Hobl, eval, YB, pure, st);
  220. T alpha = Lock(W, Hobl, YB, sub_interval(0, st.fin), ok);
  221. // Clean the portions below the diagonal corresponding
  222. // to the unwanted lock Schur vectors
  223. for (size_type j = 0; j < st.tb_deftot; ++j) {
  224. if ( pure[j] == 0)
  225. gmm::clear(sub_vector(mat_col(Hobl,j), sub_interval(j+1,m-j)));
  226. else if (pure[j] == 1) {
  227. gmm::clear(sub_matrix(Hobl, sub_interval(j+2,m-j-1),
  228. sub_interval(j, 2)));
  229. ++j;
  230. }
  231. else GMM_ASSERT3(false, "internal error");
  232. }
  233. gmm::dense_matrix<T> z(st.nb_un, st.fin - st.nb_un);
  234. sub_interval SUBI(0, st.nb_un), SUBJ(st.nb_un, st.fin - st.nb_un);
  235. sylvester(sub_matrix(Hobl, SUBI),
  236. sub_matrix(Hobl, SUBJ),
  237. sub_matrix(gmm::scaled(Hobl, -T(1)), SUBI, SUBJ), z);
  238. }
  239. }
  240. }
  241. }
  242. }
  243. template < typename Mat, typename Vec, typename VecB, typename Precond >
  244. void idgmres(const Mat &A, Vec &x, const VecB &b,
  245. const Precond &M, size_type m, iteration& outer) {
  246. typedef typename linalg_traits<Mat>::value_type T;
  247. modified_gram_schmidt<T> orth(m, vect_size(x));
  248. gmres(A, x, b, M, m, outer, orth);
  249. }
  250. // Lock stage of an implicit restarted Arnoldi process.
  251. // 1- QR factorization of YB through Householder matrices
  252. // Q(Rl) = YB
  253. // (0 )
  254. // 2- Update of the Arnoldi factorization.
  255. // H <- Q*HQ, W <- WQ
  256. // 3- Restore the Hessemberg form of H.
  257. template <typename T, typename MATYB>
  258. void Lock(gmm::dense_matrix<T> &W, gmm::dense_matrix<T> &H,
  259. const MATYB &YB, const sub_interval SUB,
  260. bool restore, T &ns) {
  261. size_type n = mat_nrows(W), m = mat_ncols(W) - 1;
  262. size_type ncols = mat_ncols(YB), nrows = mat_nrows(YB);
  263. size_type begin = min(SUB); end = max(SUB) - 1;
  264. sub_interval SUBR(0, nrows), SUBC(0, ncols);
  265. T alpha(1);
  266. GMM_ASSERT2(((end-begin) == ncols) && (m == mat_nrows(H))
  267. && (m+1 == mat_ncols(H)), "dimensions mismatch");
  268. // DEFLATION using the QR Factorization of YB
  269. dense_matrix<T> QR(n_rows, n_rows);
  270. gmmm::copy(YB, sub_matrix(QR, SUBR, SUBC));
  271. gmm::clear(submatrix(QR, SUBR, sub_interval(ncols, nrows-ncols)));
  272. qr_factor(QR);
  273. apply_house_left(QR, sub_matrix(H, SUB));
  274. apply_house_right(QR, sub_matrix(H, SUBR, SUB));
  275. apply_house_right(QR, sub_matrix(W, sub_interval(0, n), SUB));
  276. // Restore to the initial block hessenberg form
  277. if (restore) {
  278. // verifier quand m = 0 ...
  279. gmm::dense_matrix tab_p(end - st.tb_deftot, end - st.tb_deftot);
  280. gmm::copy(identity_matrix(), tab_p);
  281. for (size_type j = end-1; j >= st.tb_deftot+2; --j) {
  282. size_type jm = j-1;
  283. std::vector<T> v(jm - st.tb_deftot);
  284. sub_interval SUBtot(st.tb_deftot, jm - st.tb_deftot);
  285. sub_interval SUBtot2(st.tb_deftot, end - st.tb_deftot);
  286. gmm::copy(sub_vector(mat_row(H, j), SUBtot), v);
  287. house_vector_last(v);
  288. w.resize(end);
  289. col_house_update(sub_matrix(H, SUBI, SUBtot), v, w);
  290. w.resize(end - st.tb_deftot);
  291. row_house_update(sub_matrix(H, SUBtot, SUBtot2), v, w);
  292. gmm::clear(sub_vector(mat_row(H, j),
  293. sub_interval(st.tb_deftot, j-1-st.tb_deftot)));
  294. w.resize(end - st.tb_deftot);
  295. col_house_update(sub_matrix(tab_p, sub_interval(0, end-st.tb_deftot),
  296. sub_interval(0, jm-st.tb_deftot)), v, w);
  297. w.resize(n);
  298. col_house_update(sub_matrix(W, sub_interval(0, n), SUBtot), v, w);
  299. }
  300. // restore positive subdiagonal elements
  301. std::vector<T> d(fin-st.tb_deftot); d[0] = T(1);
  302. // We compute d[i+1] in order
  303. // (d[i+1] * H(st.tb_deftot+i+1,st.tb_deftoti)) / d[i]
  304. // be equal to |H(st.tb_deftot+i+1,st.tb_deftot+i))|.
  305. for (size_type j = 0; j+1 < end-st.tb_deftot; ++j) {
  306. T e = H(st.tb_deftot+j, st.tb_deftot+j-1);
  307. d[j+1] = (e == T(0)) ? T(1) : d[j] * gmm::abs(e) / e;
  308. scale(sub_vector(mat_row(H, st.tb_deftot+j+1),
  309. sub_interval(st.tb_deftot, m-st.tb_deftot)), d[j+1]);
  310. scale(mat_col(H, st.tb_deftot+j+1), T(1) / d[j+1]);
  311. scale(mat_col(W, st.tb_deftot+j+1), T(1) / d[j+1]);
  312. }
  313. alpha = tab_p(end-st.tb_deftot-1, end-st.tb_deftot-1) / d[end-st.tb_deftot-1];
  314. alpha /= gmm::abs(alpha);
  315. scale(mat_col(W, m), alpha);
  316. }
  317. return alpha;
  318. }
  319. // Apply p implicit shifts to the Arnoldi factorization
  320. // AV = VH+H(k+p+1,k+p) V(:,k+p+1) e_{k+p}*
  321. // and produces the following new Arnoldi factorization
  322. // A(VQ) = (VQ)(Q*HQ)+H(k+p+1,k+p) V(:,k+p+1) e_{k+p}* Q
  323. // where only the first k columns are relevant.
  324. //
  325. // Dan Sorensen and Richard J. Radke, 11/95
  326. template<typename T, typename C>
  327. apply_shift_to_Arnoldi_factorization(dense_matrix<T> V, dense_matrix<T> H,
  328. std::vector<C> Lambda, size_type &k,
  329. size_type p, bool true_shift = false) {
  330. size_type k1 = 0, num = 0, kend = k+p, kp1 = k + 1;
  331. bool mark = false;
  332. T c, s, x, y, z;
  333. dense_matrix<T> q(1, kend);
  334. gmm::clear(q); q(0,kend-1) = T(1);
  335. std::vector<T> hv(3), w(std::max(kend, mat_nrows(V)));
  336. for(size_type jj = 0; jj < p; ++jj) {
  337. // compute and apply a bulge chase sweep initiated by the
  338. // implicit shift held in w(jj)
  339. if (abs(Lambda[jj].real()) == 0.0) {
  340. // apply a real shift using 2 by 2 Givens rotations
  341. for (size_type k1 = 0, k2 = 0; k2 != kend-1; k1 = k2+1) {
  342. k2 = k1;
  343. while (h(k2+1, k2) != T(0) && k2 < kend-1) ++k2;
  344. Givens_rotation(H(k1, k1) - Lambda[jj], H(k1+1, k1), c, s);
  345. for (i = k1; i <= k2; ++i) {
  346. if (i > k1) Givens_rotation(H(i, i-1), H(i+1, i-1), c, s);
  347. // Ne pas oublier de nettoyer H(i+1,i-1) (le mettre � z�ro).
  348. // V�rifier qu'au final H(i+1,i) est bien un r�el positif.
  349. // apply rotation from left to rows of H
  350. row_rot(sub_matrix(H, sub_interval(i,2), sub_interval(i, kend-i)),
  351. c, s, 0, 0);
  352. // apply rotation from right to columns of H
  353. size_type ip2 = std::min(i+2, kend);
  354. col_rot(sub_matrix(H, sub_interval(0, ip2), sub_interval(i, 2))
  355. c, s, 0, 0);
  356. // apply rotation from right to columns of V
  357. col_rot(V, c, s, i, i+1);
  358. // accumulate e' Q so residual can be updated k+p
  359. Apply_Givens_rotation_left(q(0,i), q(0,i+1), c, s);
  360. // peut �tre que nous utilisons G au lieu de G* et que
  361. // nous allons trop loin en k2.
  362. }
  363. }
  364. num = num + 1;
  365. }
  366. else {
  367. // Apply a double complex shift using 3 by 3 Householder
  368. // transformations
  369. if (jj == p || mark)
  370. mark = false; // skip application of conjugate shift
  371. else {
  372. num = num + 2; // mark that a complex conjugate
  373. mark = true; // pair has been applied
  374. // Indices de fin de boucle � surveiller... de pr�s !
  375. for (size_type k1 = 0, k3 = 0; k3 != kend-2; k1 = k3+1) {
  376. k3 = k1;
  377. while (h(k3+1, k3) != T(0) && k3 < kend-2) ++k3;
  378. size_type k2 = k1+1;
  379. x = H(k1,k1) * H(k1,k1) + H(k1,k2) * H(k2,k1)
  380. - 2.0*Lambda[jj].real() * H(k1,k1) + gmm::abs_sqr(Lambda[jj]);
  381. y = H(k2,k1) * (H(k1,k1) + H(k2,k2) - 2.0*Lambda[jj].real());
  382. z = H(k2+1,k2) * H(k2,k1);
  383. for (size_type i = k1; i <= k3; ++i) {
  384. if (i > k1) {
  385. x = H(i, i-1);
  386. y = H(i+1, i-1);
  387. z = H(i+2, i-1);
  388. // Ne pas oublier de nettoyer H(i+1,i-1) et H(i+2,i-1)
  389. // (les mettre � z�ro).
  390. }
  391. hv[0] = x; hv[1] = y; hv[2] = z;
  392. house_vector(v);
  393. // V�rifier qu'au final H(i+1,i) est bien un r�el positif
  394. // apply transformation from left to rows of H
  395. w.resize(kend-i);
  396. row_house_update(sub_matrix(H, sub_interval(i, 2),
  397. sub_interval(i, kend-i)), v, w);
  398. // apply transformation from right to columns of H
  399. size_type ip3 = std::min(kend, i + 3);
  400. w.resize(ip3);
  401. col_house_update(sub_matrix(H, sub_interval(0, ip3),
  402. sub_interval(i, 2)), v, w);
  403. // apply transformation from right to columns of V
  404. w.resize(mat_nrows(V));
  405. col_house_update(sub_matrix(V, sub_interval(0, mat_nrows(V)),
  406. sub_interval(i, 2)), v, w);
  407. // accumulate e' Q so residual can be updated k+p
  408. w.resize(1);
  409. col_house_update(sub_matrix(q, sub_interval(0,1),
  410. sub_interval(i,2)), v, w);
  411. }
  412. }
  413. // clean up step with Givens rotation
  414. i = kend-2;
  415. c = x; s = y;
  416. if (i > k1) Givens_rotation(H(i, i-1), H(i+1, i-1), c, s);
  417. // Ne pas oublier de nettoyer H(i+1,i-1) (le mettre � z�ro).
  418. // V�rifier qu'au final H(i+1,i) est bien un r�el positif.
  419. // apply rotation from left to rows of H
  420. row_rot(sub_matrix(H, sub_interval(i,2), sub_interval(i, kend-i)),
  421. c, s, 0, 0);
  422. // apply rotation from right to columns of H
  423. size_type ip2 = std::min(i+2, kend);
  424. col_rot(sub_matrix(H, sub_interval(0, ip2), sub_interval(i, 2))
  425. c, s, 0, 0);
  426. // apply rotation from right to columns of V
  427. col_rot(V, c, s, i, i+1);
  428. // accumulate e' Q so residual can be updated k+p
  429. Apply_Givens_rotation_left(q(0,i), q(0,i+1), c, s);
  430. }
  431. }
  432. }
  433. // update residual and store in the k+1 -st column of v
  434. k = kend - num;
  435. scale(mat_col(V, kend), q(0, k));
  436. if (k < mat_nrows(H)) {
  437. if (true_shift)
  438. gmm::copy(mat_col(V, kend), mat_col(V, k));
  439. else
  440. // v(:,k+1) = v(:,kend+1) + v(:,k+1)*h(k+1,k);
  441. // v(:,k+1) = v(:,kend+1) ;
  442. gmm::add(scaled(mat_col(V, kend), H(kend, kend-1)),
  443. scaled(mat_col(V, k), H(k, k-1)), mat_col(V, k));
  444. }
  445. H(k, k-1) = vect_norm2(mat_col(V, k));
  446. scale(mat_col(V, kend), T(1) / H(k, k-1));
  447. }
  448. template<typename MAT, typename EVAL, typename PURE>
  449. void select_eval(const MAT &Hobl, EVAL &eval, MAT &YB, PURE &pure,
  450. idgmres_state &st) {
  451. typedef typename linalg_traits<MAT>::value_type T;
  452. typedef typename number_traits<T>::magnitude_type R;
  453. size_type m = st.m;
  454. // Computation of the Ritz eigenpairs.
  455. col_matrix< std::vector<T> > evect(m-st.tb_def, m-st.tb_def);
  456. // std::vector<std::complex<R> > eval(m);
  457. std::vector<R> ritznew(m, T(-1));
  458. // dense_matrix<T> evect_lock(st.tb_def, st.tb_def);
  459. sub_interval SUB1(st.tb_def, m-st.tb_def);
  460. implicit_qr_algorithm(sub_matrix(Hobl, SUB1),
  461. sub_vector(eval, SUB1), evect);
  462. sub_interval SUB2(0, st.tb_def);
  463. implicit_qr_algorithm(sub_matrix(Hobl, SUB2),
  464. sub_vector(eval, SUB2), /* evect_lock */);
  465. for (size_type l = st.tb_def; l < m; ++l)
  466. ritznew[l] = gmm::abs(evect(m-st.tb_def-1, l-st.tb_def) * Hobl(m, m-1));
  467. std::vector< std::pair<T, size_type> > eval_sort(m);
  468. for (size_type l = 0; l < m; ++l)
  469. eval_sort[l] = std::pair<T, size_type>(eval[l], l);
  470. std::sort(eval_sort.begin(), eval_sort.end(), compare_vp());
  471. std::vector<size_type> index(m);
  472. for (size_type l = 0; l < m; ++l) index[l] = eval_sort[l].second;
  473. std::vector<bool> kept(m, false);
  474. std::fill(kept.begin(), kept.begin()+st.tb_def, true);
  475. apply_permutation(eval, index);
  476. apply_permutation(evect, index);
  477. apply_permutation(ritznew, index);
  478. apply_permutation(kept, index);
  479. // Which are the eigenvalues that converged ?
  480. //
  481. // nb_want is the number of eigenvalues of
  482. // Hess(tb_def+1:n,tb_def+1:n) that converged and are WANTED
  483. //
  484. // nb_unwant is the number of eigenvalues of
  485. // Hess(tb_def+1:n,tb_def+1:n) that converged and are UNWANTED
  486. //
  487. // nb_nolong is the number of eigenvalues of
  488. // Hess(1:tb_def,1:tb_def) that are NO LONGER WANTED.
  489. //
  490. // tb_deftot is the number of the deflated eigenvalues
  491. // that is tb_def + nb_want + nb_unwant
  492. //
  493. // tb_defwant is the number of the wanted deflated eigenvalues
  494. // that is tb_def + nb_want - nb_nolong
  495. st.nb_want = 0, st.nb_unwant = 0, st.nb_nolong = 0;
  496. size_type j, ind;
  497. for (j = 0, ind = 0; j < m-p; ++j) {
  498. if (ritznew[j] == R(-1)) {
  499. if (std::imag(eval[j]) != R(0)) {
  500. st.nb_nolong += 2; ++j; // � adapter dans le cas complexe ...
  501. }
  502. else st.nb_nolong++;
  503. }
  504. else {
  505. if (ritznew[j]
  506. < tol_vp * gmm::abs(eval[j])) {
  507. for (size_type l = 0, l < m-st.tb_def; ++l)
  508. YB(l, ind) = std::real(evect(l, j));
  509. kept[j] = true;
  510. ++j; ++st.nb_unwant; ind++;
  511. if (std::imag(eval[j]) != R(0)) {
  512. for (size_type l = 0, l < m-st.tb_def; ++l)
  513. YB(l, ind) = std::imag(evect(l, j));
  514. pure[ind-1] = 1;
  515. pure[ind] = 2;
  516. kept[j] = true;
  517. st.nb_unwant++;
  518. ++ind;
  519. }
  520. }
  521. }
  522. }
  523. for (; j < m; ++j) {
  524. if (ritznew[j] != R(-1)) {
  525. for (size_type l = 0, l < m-st.tb_def; ++l)
  526. YB(l, ind) = std::real(evect(l, j));
  527. pure[ind] = 1;
  528. ++ind;
  529. kept[j] = true;
  530. ++st.nb_want;
  531. if (ritznew[j]
  532. < tol_vp * gmm::abs(eval[j])) {
  533. for (size_type l = 0, l < m-st.tb_def; ++l)
  534. YB(l, ind) = std::imag(evect(l, j));
  535. pure[ind] = 2;
  536. j++;
  537. kept[j] = true;
  538. st.nb_want++;
  539. ++ind;
  540. }
  541. }
  542. }
  543. std::vector<T> shift(m - st.tb_def - st.nb_want - st.nb_unwant);
  544. for (size_type j = 0, i = 0; j < m; ++j)
  545. if (!kept[j]) shift[i++] = eval[j];
  546. // st.conv (st.nb_want+st.nb_unwant) is the number of eigenpairs that
  547. // have just converged.
  548. // st.tb_deftot is the total number of eigenpairs that have converged.
  549. size_type st.conv = ind;
  550. size_type st.tb_deftot = st.tb_def + st.conv;
  551. size_type st.tb_defwant = st.tb_def + st.nb_want - st.nb_nolong;
  552. sub_interval SUBYB(0, st.conv);
  553. if ( st.tb_defwant >= p ) { // An invariant subspace has been found.
  554. st.nb_unwant = 0;
  555. st.nb_want = p + st.nb_nolong - st.tb_def;
  556. st.tb_defwant = p;
  557. if ( pure[st.conv - st.nb_want + 1] == 2 ) {
  558. ++st.nb_want; st.tb_defwant = ++p;// il faudrait que ce soit un p local
  559. }
  560. SUBYB = sub_interval(st.conv - st.nb_want, st.nb_want);
  561. // YB = YB(:, st.conv-st.nb_want+1 : st.conv); // On laisse en suspend ..
  562. // pure = pure(st.conv-st.nb_want+1 : st.conv,1); // On laisse suspend ..
  563. st.conv = st.nb_want;
  564. st.tb_deftot = st.tb_def + st.conv;
  565. st.ok = true;
  566. }
  567. }
  568. template<typename MAT, typename EVAL, typename PURE>
  569. void select_eval_for_purging(const MAT &Hobl, EVAL &eval, MAT &YB,
  570. PURE &pure, idgmres_state &st) {
  571. typedef typename linalg_traits<MAT>::value_type T;
  572. typedef typename number_traits<T>::magnitude_type R;
  573. size_type m = st.m;
  574. // Computation of the Ritz eigenpairs.
  575. col_matrix< std::vector<T> > evect(st.tb_deftot, st.tb_deftot);
  576. sub_interval SUB1(0, st.tb_deftot);
  577. implicit_qr_algorithm(sub_matrix(Hobl, SUB1),
  578. sub_vector(eval, SUB1), evect);
  579. std::fill(eval.begin() + st.tb_deftot, eval.end(), std::complex<R>(0));
  580. std::vector< std::pair<T, size_type> > eval_sort(m);
  581. for (size_type l = 0; l < m; ++l)
  582. eval_sort[l] = std::pair<T, size_type>(eval[l], l);
  583. std::sort(eval_sort.begin(), eval_sort.end(), compare_vp());
  584. std::vector<bool> sorted(m);
  585. std::fill(sorted.begin(), sorted.end(), false);
  586. std::vector<size_type> ind(m);
  587. for (size_type l = 0; l < m; ++l) ind[l] = eval_sort[l].second;
  588. std::vector<bool> kept(m, false);
  589. std::fill(kept.begin(), kept.begin()+st.tb_def, true);
  590. apply_permutation(eval, ind);
  591. apply_permutation(evect, ind);
  592. size_type j;
  593. for (j = 0; j < st.tb_deftot; ++j) {
  594. for (size_type l = 0, l < st.tb_deftot; ++l)
  595. YB(l, j) = std::real(evect(l, j));
  596. if (std::imag(eval[j]) != R(0)) {
  597. for (size_type l = 0, l < m-st.tb_def; ++l)
  598. YB(l, j+1) = std::imag(evect(l, j));
  599. pure[j] = 1;
  600. pure[j+1] = 2;
  601. j += 2;
  602. }
  603. else ++j;
  604. }
  605. }
  606. }
  607. #endif