37 #ifndef GMM_DENSE_QR_H 
   38 #define GMM_DENSE_QR_H 
   48   template <
typename MAT1>
 
   50     MAT1 &A = 
const_cast<MAT1 &
>(A_);
 
   51     typedef typename linalg_traits<MAT1>::value_type T;
 
   53     const size_type m = mat_nrows(A), n = mat_ncols(A);
 
   54     GMM_ASSERT2(m >= n, 
"dimensions mismatch");
 
   56     std::vector<T> W(m), V(m);
 
   59     const size_type jmax = (m==n && !is_complex(T())) ? m-1
 
   61     for (size_type j = 0; j < jmax; ++j) {
 
   62       sub_interval SUBI(j, m-j), SUBJ(j, n-j);
 
   63       V.resize(m-j); W.resize(n-j);
 
   65       for (size_type i = j; i < m; ++i) V[i-j] = A(i, j);
 
   68       row_house_update(sub_matrix(A, SUBI, SUBJ), V, W);
 
   69       for (size_type i = j+1; i < m; ++i) A(i, j) = V[i-j];
 
   77   template <
typename MAT1, 
typename MAT2>
 
   78   void apply_house_right(
const MAT1 &QR, 
const MAT2 &A_) {
 
   79     MAT2 &A = 
const_cast<MAT2 &
>(A_);
 
   80     typedef typename linalg_traits<MAT1>::value_type T;
 
   81     const size_type m = mat_nrows(QR), n = mat_ncols(QR);
 
   82     GMM_ASSERT2(m == mat_ncols(A), 
"dimensions mismatch");
 
   84     std::vector<T> V(m), W(mat_nrows(A));
 
   87     const size_type jmax = (m==n && !is_complex(T())) ? m-1
 
   93       col_house_update(sub_matrix(A, sub_interval(0, mat_nrows(A)),
 
   94                                      sub_interval(j, m-j)),
 
  102   template <
typename MAT1, 
typename MAT2>
 
  103   void apply_house_left(
const MAT1 &QR, 
const MAT2 &A_) {
 
  104     MAT2 &A = 
const_cast<MAT2 &
>(A_);
 
  105     typedef typename linalg_traits<MAT1>::value_type T;
 
  106     const size_type m = mat_nrows(QR), n = mat_ncols(QR);
 
  107     GMM_ASSERT2(m == mat_nrows(A), 
"dimensions mismatch");
 
  109     std::vector<T> V(m), W(mat_ncols(A));
 
  112     const size_type jmax = (m==n && !is_complex(T())) ? m-1
 
  116       for (
size_type i = j+1; i < m; ++i) V[i-j] = QR(i, j);
 
  117       row_house_update(sub_matrix(A, sub_interval(j, m-j),
 
  118                                      sub_interval(0, mat_ncols(A))),
 
  124   template <
typename MAT1, 
typename MAT2, 
typename MAT3>
 
  125     void qr_factor(
const MAT1 &A, 
const MAT2 &QQ, 
const MAT3 &RR) {
 
  126     MAT2 &Q = 
const_cast<MAT2 &
>(QQ); MAT3 &R = 
const_cast<MAT3 &
>(RR);
 
  127     typedef typename linalg_traits<MAT1>::value_type T;
 
  129     const size_type m = mat_nrows(A), n = mat_ncols(A);
 
  130     GMM_ASSERT2(m >= n, 
"dimensions mismatch");
 
  134     dense_matrix<T> VV(m, n);
 
  137     const size_type jmax = (m==n && !is_complex(T())) ? m-1
 
  139     for (size_type j = 0; j < jmax; ++j) {
 
  140       sub_interval SUBI(j, m-j), SUBJ(j, n-j);
 
  142       for (size_type i = j; i < m; ++i) VV(i,j) = Q(i, j);
 
  143       house_vector(sub_vector(mat_col(VV,j), SUBI));
 
  145       row_house_update(sub_matrix(Q, SUBI, SUBJ),
 
  146                        sub_vector(mat_col(VV,j), SUBI), sub_vector(W, SUBJ));
 
  149     gmm::copy(sub_matrix(Q, sub_interval(0, n), sub_interval(0, n)), R);
 
  152     const size_type jstart = (m==n && !is_complex(T())) ? m-2
 
  154     for (size_type j = jstart; j != 
size_type(-1); --j) {
 
  155       sub_interval SUBI(j, m-j), SUBJ(j, n-j);
 
  156       row_house_update(sub_matrix(Q, SUBI, SUBJ),
 
  157                        sub_vector(mat_col(VV,j), SUBI), sub_vector(W, SUBJ));
 
  162   template <
typename TA, 
typename TV, 
typename Ttol,
 
  163             typename MAT, 
typename VECT>
 
  164   void extract_eig(
const MAT &A, VECT &V, Ttol tol, TA, TV) {
 
  168     Ttol tol_i = tol * gmm::abs(A(0,0)), tol_cplx = tol_i;
 
  171         tol_i = (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol;
 
  172         tol_cplx = std::max(tol_cplx, tol_i);
 
  174       if ((i < n-1) && gmm::abs(A(i+1,i)) >= tol_i) {
 
  175         TA tr = A(i,i) + A(i+1, i+1);
 
  176         TA det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
 
  177         TA delta = tr*tr - TA(4) * det;
 
  178         if (delta < -tol_cplx) {
 
  179           GMM_WARNING1(
"A complex eigenvalue has been detected : " 
  180                       << std::complex<TA>(tr/TA(2), gmm::sqrt(-delta)/TA(2)));
 
  181           V[i] = V[i+1] = tr / TA(2);
 
  184           delta = std::max(TA(0), delta);
 
  185           V[i  ] = TA(tr + gmm::sqrt(delta))/ TA(2);
 
  186           V[i+1] = TA(tr -  gmm::sqrt(delta))/ TA(2);
 
  195   template <
typename TA, 
typename TV, 
typename Ttol,
 
  196             typename MAT, 
typename VECT>
 
  197   void extract_eig(
const MAT &A, VECT &V, Ttol tol, TA, std::complex<TV>) {
 
  202           gmm::abs(A(i+1,i)) < (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol)
 
  203         V[i] = std::complex<TV>(A(i,i));
 
  205         TA tr = A(i,i) + A(i+1, i+1);
 
  206         TA det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
 
  207         TA delta = tr*tr - TA(4) * det;
 
  209           V[i] = std::complex<TV>(tr / TA(2), gmm::sqrt(-delta) / TA(2));
 
  210           V[i+1] = std::complex<TV>(tr / TA(2), -gmm::sqrt(-delta)/ TA(2));
 
  213           V[i  ] = TA(tr + gmm::sqrt(delta)) / TA(2);
 
  214           V[i+1] = TA(tr -  gmm::sqrt(delta)) / TA(2);
 
  220   template <
typename TA, 
typename TV, 
typename Ttol,
 
  221             typename MAT, 
typename VECT>
 
  222   void extract_eig(
const MAT &A, VECT &V, Ttol tol, std::complex<TA>, TV) {
 
  223     typedef std::complex<TA> T;
 
  227     Ttol tol_i = tol * gmm::abs(A(0,0)), tol_cplx = tol_i;
 
  230         tol_i = (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol;
 
  231         tol_cplx = std::max(tol_cplx, tol_i);
 
  233       if ((i == n-1) || gmm::abs(A(i+1,i)) < tol_i) {
 
  234         if (gmm::abs(std::imag(A(i,i))) > tol_cplx)
 
  235           GMM_WARNING1(
"A complex eigenvalue has been detected : " 
  236                       << T(A(i,i)) << 
" : "  << gmm::abs(std::imag(A(i,i)))
 
  237                       / gmm::abs(std::real(A(i,i))) << 
" : " << tol_cplx);
 
  238         V[i] = std::real(A(i,i));
 
  241         T tr = A(i,i) + A(i+1, i+1);
 
  242         T det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
 
  243         T delta = tr*tr - TA(4) * det;
 
  244         T a1 = (tr + gmm::sqrt(delta)) / TA(2);
 
  245         T a2 = (tr - gmm::sqrt(delta)) / TA(2);
 
  246         if (gmm::abs(std::imag(a1)) > tol_cplx)
 
  247           GMM_WARNING1(
"A complex eigenvalue has been detected : " << a1);
 
  248         if (gmm::abs(std::imag(a2)) > tol_cplx)
 
  249           GMM_WARNING1(
"A complex eigenvalue has been detected : " << a2);
 
  251         V[i] = std::real(a1); V[i+1] = std::real(a2);
 
  257   template <
typename TA, 
typename TV, 
typename Ttol,
 
  258             typename MAT, 
typename VECT>
 
  260                    std::complex<TA>, std::complex<TV>) {
 
  265           gmm::abs(A(i+1,i)) < (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol)
 
  266         V[i] = std::complex<TV>(A(i,i));
 
  268         std::complex<TA> tr = A(i,i) + A(i+1, i+1);
 
  269         std::complex<TA> det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
 
  270         std::complex<TA> delta = tr*tr - TA(4) * det;
 
  271         V[i] = (tr + gmm::sqrt(delta)) / TA(2);
 
  272         V[i+1] = (tr - gmm::sqrt(delta)) / TA(2);
 
  281   template <
typename MAT, 
typename Ttol, 
typename VECT> 
inline 
  284                 typename linalg_traits<MAT>::value_type(),
 
  285                 typename linalg_traits<VECT>::value_type());
 
  292   template <
typename MAT, 
typename Ttol>
 
  294     typedef typename linalg_traits<MAT>::value_type T;
 
  295     typedef typename number_traits<T>::magnitude_type R;
 
  296     R rmin = default_min(R()) * R(2);
 
  298     if (n <= 2) { q = n; p = 0; }
 
  301         if (gmm::abs(A(i,i-1)) < (gmm::abs(A(i,i))+ gmm::abs(A(i-1,i-1)))*tol
 
  302             || gmm::abs(A(i,i-1)) < rmin)
 
  305       while ((q < n-1 && A(n-1-q, n-2-q) == T(0)) ||
 
  306              (q < n-2 && A(n-2-q, n-3-q) == T(0))) ++q;
 
  308       p = n-q; 
if (p) --p; 
if (p) --p;
 
  309       while (p > 0 && A(p,p-1) != T(0)) --p;
 
  313   template <
typename MAT, 
typename Ttol> 
inline 
  316     typedef typename linalg_traits<MAT>::value_type T;
 
  317     typedef typename number_traits<T>::magnitude_type R;
 
  318     R rmin = default_min(R()) * R(2);
 
  319     MAT& A = 
const_cast<MAT&
>(AA);
 
  321     if (n <= 1) { q = n; p = 0; }
 
  324         if (gmm::abs(A(i,i-1)) < (gmm::abs(A(i,i))+ gmm::abs(A(i-1,i-1)))*tol
 
  325             || gmm::abs(A(i,i-1)) < rmin)
 
  328       while (q < n-1 && A(n-1-q, n-2-q) == T(0)) ++q;
 
  330       p = n-q; 
if (p) --p; 
if (p) --p;
 
  331       while (p > 0 && A(p,p-1) != T(0)) --p;
 
  335   template <
typename VECT1, 
typename VECT2, 
typename Ttol> 
inline 
  336   void symmetric_qr_stop_criterion(
const VECT1 &diag, 
const VECT2 &sdiag_,
 
  338     typedef typename linalg_traits<VECT2>::value_type T;
 
  339     typedef typename number_traits<T>::magnitude_type R;
 
  340     R rmin = default_min(R()) * R(2);
 
  341     VECT2 &sdiag = 
const_cast<VECT2 &
>(sdiag_);
 
  343     if (n <= 1) { q = n; p = 0; 
return; }
 
  345       if (gmm::abs(sdiag[i-1]) < (gmm::abs(diag[i])+ gmm::abs(diag[i-1]))*tol
 
  346           || gmm::abs(sdiag[i-1]) < rmin)
 
  348     while (q < n-1 && sdiag[n-2-q] == T(0)) ++q;
 
  350     p = n-q; 
if (p) --p; 
if (p) --p;
 
  351     while (p > 0 && sdiag[p-1] != T(0)) --p;
 
  358   template <
typename MATH, 
typename MATQ, 
typename Ttol>
 
  359   void block2x2_reduction(MATH &H, MATQ &Q, Ttol tol) {
 
  360     typedef typename linalg_traits<MATH>::value_type T;
 
  361     typedef typename number_traits<T>::magnitude_type R;
 
  363     size_type n = mat_nrows(H), nq = mat_nrows(Q);
 
  365     sub_interval SUBQ(0, nq), SUBL(0, 2);
 
  366     std::vector<T> v(2), w(std::max(n, nq)); v[0] = T(1);
 
  368     Ttol tol_i = tol * gmm::abs(H(0,0)), tol_cplx = tol_i;
 
  370       tol_i = (gmm::abs(H(i,i))+gmm::abs(H(i+1,i+1)))*tol;
 
  371       tol_cplx = std::max(tol_cplx, tol_i);
 
  373       if (gmm::abs(H(i+1,i)) > tol_i) { 
 
  374         T tr = (H(i+1, i+1) - H(i,i)) / T(2);
 
  375         T delta = tr*tr + H(i,i+1)*H(i+1, i);
 
  377         if (is_complex(T()) || gmm::real(delta) >= R(0)) {
 
  378           sub_interval SUBI(i, 2);
 
  379           T theta = (tr - gmm::sqrt(delta)) / H(i+1,i);
 
  380           R a = gmm::abs(theta);
 
  381           v[1] = (a == R(0)) ? T(-1)
 
  382             : gmm::conj(theta) * (R(1) - gmm::sqrt(a*a + R(1)) / a);
 
  383           row_house_update(sub_matrix(H, SUBI), v, sub_vector(w, SUBL));
 
  384           col_house_update(sub_matrix(H, SUBI), v, sub_vector(w, SUBL));
 
  385           col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
 
  396   #define tol_type_for_qr typename number_traits<typename \ 
  397                           linalg_traits<MAT1>::value_type>::magnitude_type 
  398   #define default_tol_for_qr \ 
  399     (gmm::default_tol(tol_type_for_qr()) *  tol_type_for_qr(3)) 
  404   template <
typename MAT1, 
typename VECT, 
typename MAT2>
 
  405     void rudimentary_qr_algorithm(
const MAT1 &A, 
const VECT &eigval_,
 
  406                                   const MAT2 &eigvect_,
 
  407                                   tol_type_for_qr tol = default_tol_for_qr,
 
  408                                   bool compvect = 
true) {
 
  409     VECT &eigval = 
const_cast<VECT &
>(eigval_);
 
  410     MAT2 &eigvect = 
const_cast<MAT2 &
>(eigvect_);
 
  412     typedef typename linalg_traits<MAT1>::value_type value_type;
 
  414     size_type n = mat_nrows(A), p, q = 0, ite = 0;
 
  415     dense_matrix<value_type> Q(n, n), R(n,n), A1(n,n);
 
  418     Hessenberg_reduction(A1, eigvect, compvect);
 
  419     qr_stop_criterion(A1, p, q, tol);
 
  426       qr_stop_criterion(A1, p, q, tol);
 
  428       GMM_ASSERT1(ite < n*1000, 
"QR algorithm failed");
 
  430     if (compvect) block2x2_reduction(A1, Q, tol);
 
  434   template <
typename MAT1, 
typename VECT>
 
  435     void rudimentary_qr_algorithm(
const MAT1 &a, VECT &eigval,
 
  436                                   tol_type_for_qr tol = default_tol_for_qr) {
 
  437     dense_matrix<typename linalg_traits<MAT1>::value_type> m(0,0);
 
  438     rudimentary_qr_algorithm(a, eigval, m, tol, 
false);
 
  445   template <
typename MAT1, 
typename MAT2>
 
  446     void Francis_qr_step(
const MAT1& HH, 
const MAT2 &QQ, 
bool compute_Q) {
 
  447     MAT1& H = 
const_cast<MAT1&
>(HH); MAT2& Q = 
const_cast<MAT2&
>(QQ);
 
  448     typedef typename linalg_traits<MAT1>::value_type value_type;
 
  449     size_type n = mat_nrows(H), nq = mat_nrows(Q);
 
  451     std::vector<value_type> v(3), w(std::max(n, nq));
 
  453     value_type s = H(n-2, n-2) + H(n-1, n-1);
 
  454     value_type t = H(n-2, n-2) * H(n-1, n-1) - H(n-2, n-1) * H(n-1, n-2);
 
  455     value_type x = H(0, 0) * H(0, 0) + H(0,1) * H(1, 0) - s * H(0,0) + t;
 
  456     value_type y = H(1, 0) * (H(0,0) + H(1,1) - s);
 
  457     value_type z = H(1, 0) * H(2, 1);
 
  459     sub_interval SUBQ(0, nq);
 
  462       v[0] = x; v[1] = y; v[2] = z;
 
  464       size_type r = std::min(k+4, n), q = (k==0) ? 0 : k-1;
 
  465       sub_interval SUBI(k, 3), SUBJ(0, r), SUBK(q, n-q);
 
  467       row_house_update(sub_matrix(H, SUBI, SUBK),  v, sub_vector(w, SUBK));
 
  468       col_house_update(sub_matrix(H, SUBJ, SUBI),  v, sub_vector(w, SUBJ));
 
  471         col_house_update(sub_matrix(Q, SUBQ, SUBI),  v, sub_vector(w, SUBQ));
 
  473       x = H(k+1, k); y = H(k+2, k);
 
  474       if (k < n-3) z = H(k+3, k);
 
  476     sub_interval SUBI(n-2,2), SUBJ(0, n), SUBK(n-3,3), SUBL(0, 3);
 
  480     row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBL));
 
  481     col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
 
  483       col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
 
  490   template <
typename MAT1, 
typename MAT2, 
typename Ttol>
 
  491   void Wilkinson_double_shift_qr_step(
const MAT1& HH, 
const MAT2 &QQ,
 
  492                                       Ttol tol, 
bool exc, 
bool compute_Q) {
 
  493     MAT1& H = 
const_cast<MAT1&
>(HH); MAT2& Q = 
const_cast<MAT2&
>(QQ);
 
  494     typedef typename linalg_traits<MAT1>::value_type T;
 
  495     typedef typename number_traits<T>::magnitude_type R;
 
  497     size_type n = mat_nrows(H), nq = mat_nrows(Q), m;
 
  498     std::vector<T> v(3), w(std::max(n, nq));
 
  499     const R dat1(0.75), dat2(-0.4375);
 
  500     T h33, h44, h43h34, v1(0), v2(0), v3(0);
 
  503       R s = gmm::abs(H(n-1, n-2)) + gmm::abs(H(n-2, n-3));
 
  504       h33 = h44 = dat1 * s;
 
  508       h44 = H(n-1,n-1); h33 = H(n-2, n-2);
 
  509       h43h34 = H(n-1, n-2) * H(n-2, n-1);
 
  515     for (m = n-2; m != 0; --m) {
 
  516       T h11  = H(m-1, m-1), h22  = H(m, m);
 
  517       T h21  = H(m, m-1),   h12  = H(m-1, m);
 
  518       T h44s = h44 - h11,   h33s = h33 - h11;
 
  519       v1 = (h33s*h44s-h43h34) / h21 + h12;
 
  520       v2 = h22 - h11 - h33s - h44s;
 
  522       R s = gmm::abs(v1) + gmm::abs(v2) + gmm::abs(v3);
 
  523       v1 /= s; v2 /= s; v3 /= s;
 
  527       R tst1 = gmm::abs(v1)*(gmm::abs(h00)+gmm::abs(h11)+gmm::abs(h22));
 
  528       if (gmm::abs(h10)*(gmm::abs(v2)+gmm::abs(v3)) <= tol * tst1) 
break;
 
  532     sub_interval SUBQ(0, nq);
 
  533     for (
size_type k = (m == 0) ? 0 : m-1; k < n-2; ++k) {
 
  534       v[0] = v1; v[1] = v2; v[2] = v3;
 
  536       size_type r = std::min(k+4, n), q = (k==0) ? 0 : k-1;
 
  537       sub_interval SUBI(k, 3), SUBJ(0, r), SUBK(q, n-q);
 
  539       row_house_update(sub_matrix(H, SUBI, SUBK),  v, sub_vector(w, SUBK));
 
  540       col_house_update(sub_matrix(H, SUBJ, SUBI),  v, sub_vector(w, SUBJ));
 
  541       if (k > m-1) { H(k+1, k-1) = T(0); 
if (k < n-3) H(k+2, k-1) = T(0); }
 
  544         col_house_update(sub_matrix(Q, SUBQ, SUBI),  v, sub_vector(w, SUBQ));
 
  546       v1 = H(k+1, k); v2 = H(k+2, k);
 
  547       if (k < n-3) v3 = H(k+3, k);
 
  549     sub_interval SUBI(n-2,2), SUBJ(0, n), SUBK(n-3,3), SUBL(0, 3);
 
  550     v.resize(2); v[0] = v1; v[1] = v2;
 
  552     row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBL));
 
  553     col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
 
  555       col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
 
  566   template <
typename MAT1, 
typename VECT, 
typename MAT2>
 
  567   void implicit_qr_algorithm(
const MAT1 &A, 
const VECT &eigval_,
 
  569                              tol_type_for_qr tol = default_tol_for_qr,
 
  570                              bool compvect = 
true) {
 
  571     VECT &eigval = 
const_cast<VECT &
>(eigval_);
 
  572     MAT2 &Q = 
const_cast<MAT2 &
>(Q_);
 
  573     typedef typename linalg_traits<MAT1>::value_type T;
 
  574     typedef typename number_traits<T>::magnitude_type R;
 
  577     dense_matrix<T> H(n,n);
 
  580     Hessenberg_reduction(H, Q, compvect);
 
  581     qr_stop_criterion(H, p, q, tol);
 
  584     sub_interval SUBK(0,0);
 
  586       sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(Q));
 
  587       if (compvect) SUBK = SUBI;
 
  590       Wilkinson_double_shift_qr_step(sub_matrix(H, SUBI),
 
  591                                      sub_matrix(Q, SUBJ, SUBK),
 
  592                                      tol, (its == 10 || its == 20), compvect);
 
  594       qr_stop_criterion(H, p, q, tol*R(2));
 
  595       if (q != q_old) its = 0;
 
  597       GMM_ASSERT1(ite < n*100, 
"QR algorithm failed");
 
  599     if (compvect) block2x2_reduction(H, Q, tol);
 
  603   template <
typename MAT1, 
typename VECT>
 
  604     void implicit_qr_algorithm(
const MAT1 &a, VECT &eigval,
 
  605                                tol_type_for_qr tol = default_tol_for_qr) {
 
  606     dense_matrix<typename linalg_traits<MAT1>::value_type> m(1,1);
 
  607     implicit_qr_algorithm(a, eigval, m, tol, 
false);
 
  614   template <
typename MAT1, 
typename MAT2>
 
  615   void symmetric_Wilkinson_qr_step(
const MAT1& MM, 
const MAT2 &ZZ,
 
  617     MAT1& M = 
const_cast<MAT1&
>(MM); MAT2& Z = 
const_cast<MAT2&
>(ZZ);
 
  618     typedef typename linalg_traits<MAT1>::value_type T;
 
  619     typedef typename number_traits<T>::magnitude_type R;
 
  623       M(i, i) = T(gmm::real(M(i, i)));
 
  625         T a = (M(i, i-1) + gmm::conj(M(i-1, i)))/R(2);
 
  626         M(i, i-1) = a; M(i-1, i) = gmm::conj(a);
 
  630     R d = gmm::real(M(n-2, n-2) - M(n-1, n-1)) / R(2);
 
  631     R e = gmm::abs_sqr(M(n-1, n-2));
 
  632     R nu = d + gmm::sgn(d)*gmm::sqrt(d*d+e);
 
  633     if (nu == R(0)) { M(n-1, n-2) = T(0); 
return; }
 
  634     R mu = gmm::real(M(n-1, n-1)) - e / nu;
 
  635     T x = M(0,0) - T(mu), z = M(1, 0), c, s;
 
  638       Givens_rotation(x, z, c, s);
 
  640       if (k > 1) Apply_Givens_rotation_left(M(k-1,k-2), M(k,k-2), c, s);
 
  641       Apply_Givens_rotation_left(M(k-1,k-1), M(k,k-1), c, s);
 
  642       Apply_Givens_rotation_left(M(k-1,k  ), M(k,k  ), c, s);
 
  643       if (k < n-1) Apply_Givens_rotation_left(M(k-1,k+1), M(k,k+1), c, s);
 
  644       if (k > 1) Apply_Givens_rotation_right(M(k-2,k-1), M(k-2,k), c, s);
 
  645       Apply_Givens_rotation_right(M(k-1,k-1), M(k-1,k), c, s);
 
  646       Apply_Givens_rotation_right(M(k  ,k-1), M(k,k)  , c, s);
 
  647       if (k < n-1) Apply_Givens_rotation_right(M(k+1,k-1), M(k+1,k), c, s);
 
  649       if (compute_z) col_rot(Z, c, s, k-1, k);
 
  650       if (k < n-1) { x = M(k, k-1); z = M(k+1, k-1); }
 
  654   template <
typename VECT1, 
typename VECT2, 
typename MAT>
 
  655   void symmetric_Wilkinson_qr_step(
const VECT1& diag_, 
const VECT2& sdiag_,
 
  656                                    const MAT &ZZ, 
bool compute_z) {
 
  657     VECT1& diag = 
const_cast<VECT1&
>(diag_);
 
  658     VECT2& sdiag = 
const_cast<VECT2&
>(sdiag_);
 
  659     MAT& Z = 
const_cast<MAT&
>(ZZ);
 
  660     typedef typename linalg_traits<VECT2>::value_type T;
 
  661     typedef typename number_traits<T>::magnitude_type R;
 
  664     R d = (diag[n-2] - diag[n-1]) / R(2);
 
  665     R e = gmm::abs_sqr(sdiag[n-2]);
 
  666     R nu = d + gmm::sgn(d)*gmm::sqrt(d*d+e);
 
  667     if (nu == R(0)) { sdiag[n-2] = T(0); 
return; }
 
  668     R mu = diag[n-1] - e / nu;
 
  669     T x = diag[0] - T(mu), z = sdiag[0], c, s;
 
  672     T a10(0), a11(diag[0]), a12(gmm::conj(sdiag[0])), a13(0);
 
  673     T a20(0), a21(sdiag[0]), a22(diag[1]), a23(gmm::conj(sdiag[1]));
 
  674     T a31(0), a32(sdiag[1]);
 
  677       Givens_rotation(x, z, c, s);
 
  679       if (k > 1) Apply_Givens_rotation_left(a10, a20, c, s);
 
  680       Apply_Givens_rotation_left(a11, a21, c, s);
 
  681       Apply_Givens_rotation_left(a12, a22, c, s);
 
  682       if (k < n-1) Apply_Givens_rotation_left(a13, a23, c, s);
 
  684       if (k > 1) Apply_Givens_rotation_right(a01, a02, c, s);
 
  685       Apply_Givens_rotation_right(a11, a12, c, s);
 
  686       Apply_Givens_rotation_right(a21, a22, c, s);
 
  687       if (k < n-1) Apply_Givens_rotation_right(a31, a32, c, s);
 
  689       if (compute_z) col_rot(Z, c, s, k-1, k);
 
  691       diag[k-1] = gmm::real(a11);
 
  692       diag[k] = gmm::real(a22);
 
  693       if (k > 1) sdiag[k-2] = (gmm::conj(a01) + a10) / R(2);
 
  694       sdiag[k-1] = (gmm::conj(a12) + a21) / R(2);
 
  696       x = sdiag[k-1]; z = (gmm::conj(a13) + a31) / R(2);
 
  698       a01 = a12; a02 = a13;
 
  699       a10 = a21; a11 = a22; a12 = a23; a13 = T(0);
 
  700       a20 = a31; a21 = a32; a31 = T(0);
 
  703         sdiag[k] = (gmm::conj(a23) + a32) / R(2);
 
  704         a22 = T(diag[k+1]); a32 = sdiag[k+1]; a23 = gmm::conj(a32);
 
  717   template <
typename MAT1, 
typename VECT, 
typename MAT2>
 
  718   void symmetric_qr_algorithm_old(
const MAT1 &A, 
const VECT &eigval_,
 
  719                                   const MAT2 &eigvect_,
 
  720                                   tol_type_for_qr tol = default_tol_for_qr,
 
  721                                   bool compvect = 
true) {
 
  722     VECT &eigval = 
const_cast<VECT &
>(eigval_);
 
  723     MAT2 &eigvect = 
const_cast<MAT2 &
>(eigvect_);
 
  724     typedef typename linalg_traits<MAT1>::value_type T;
 
  725     typedef typename number_traits<T>::magnitude_type R;
 
  727     size_type n(mat_nrows(A)), q(0), p(0), ite(0);
 
  728     dense_matrix<T> Tri(n, n);
 
  731     if (compvect) 
gmm::copy(identity_matrix(), eigvect);
 
  732     Householder_tridiagonalization(Tri, eigvect, compvect);
 
  733     symmetric_qr_stop_criterion(Tri, p, q, tol);
 
  736       sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(eigvect)), SUBK(p, n-p-q);
 
  737       if (!compvect) SUBK = sub_interval(0,0);
 
  738       symmetric_Wilkinson_qr_step(sub_matrix(Tri, SUBI),
 
  739                                   sub_matrix(eigvect, SUBJ, SUBK), compvect);
 
  741       symmetric_qr_stop_criterion(Tri, p, q, tol*R(2));
 
  743       GMM_ASSERT1(ite < n*100, 
"QR algorithm failed. Probably, your matrix" 
  744                   " is not real symmetric or complex hermitian");
 
  750   template <
typename MAT1, 
typename VECT, 
typename MAT2>
 
  751   void symmetric_qr_algorithm(
const MAT1 &A, 
const VECT &eigval_,
 
  752                               const MAT2 &eigvect_,
 
  753                               tol_type_for_qr tol = default_tol_for_qr,
 
  754                               bool compvect = 
true) {
 
  755     VECT &eigval = 
const_cast<VECT &
>(eigval_);
 
  756     MAT2 &eigvect = 
const_cast<MAT2 &
>(eigvect_);
 
  757     typedef typename linalg_traits<MAT1>::value_type T;
 
  758     typedef typename number_traits<T>::magnitude_type R;
 
  760     size_type n = mat_nrows(A), q = 0, p, ite = 0;
 
  761     if (compvect) 
gmm::copy(identity_matrix(), eigvect);
 
  763     if (n == 1) { eigval[0]=gmm::real(A(0,0)); 
return; }
 
  764     dense_matrix<T> Tri(n, n);
 
  767     Householder_tridiagonalization(Tri, eigvect, compvect);
 
  769     std::vector<R> diag(n);
 
  770     std::vector<T> sdiag(n);
 
  772       { diag[i] = gmm::real(Tri(i, i)); 
if (i+1 < n) sdiag[i] = Tri(i+1, i); }
 
  774     symmetric_qr_stop_criterion(diag, sdiag, p, q, tol);
 
  777       sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(eigvect)), SUBK(p, n-p-q);
 
  778       if (!compvect) SUBK = sub_interval(0,0);
 
  780       symmetric_Wilkinson_qr_step(sub_vector(diag, SUBI),
 
  781                                   sub_vector(sdiag, SUBI),
 
  782                                   sub_matrix(eigvect, SUBJ, SUBK), compvect);
 
  784       symmetric_qr_stop_criterion(diag, sdiag, p, q, tol*R(3));
 
  786       GMM_ASSERT1(ite < n*100, 
"QR algorithm failed.");
 
  793   template <
typename MAT1, 
typename VECT>
 
  794     void symmetric_qr_algorithm(
const MAT1 &a, VECT &eigval,
 
  795                                 tol_type_for_qr tol = default_tol_for_qr) {
 
  796     dense_matrix<typename linalg_traits<MAT1>::value_type> m(0,0);
 
  797     symmetric_qr_algorithm(a, eigval, m, tol, 
false);
 
void copy(const L1 &l1, L2 &l2)
*/
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*/
Householder for dense matrices.
void extract_eig(const MAT &A, const VECT &V, Ttol tol)
Compute eigenvalue vector.
void qr_factor(const MAT1 &A_)
QR factorization using Householder method (complex and real version).
size_t size_type
used as the common size type in the library