SLIP  1.4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
linear_algebra_qr.hpp
Go to the documentation of this file.
1 /*
2  * Copyright(c):
3  * Signal Image and Communications (SIC) Department
4  * http://www.sic.sp2mi.univ-poitiers.fr/
5  * - University of Poitiers, France http://www.univ-poitiers.fr
6  * - XLIM Institute UMR CNRS 7252 http://www.xlim.fr/
7  *
8  * and
9  *
10  * D2 Fluid, Thermic and Combustion
11  * - University of Poitiers, France http://www.univ-poitiers.fr
12  * - PPRIME Institute - UPR CNRS 3346 http://www.pprime.fr
13  * - ISAE-ENSMA http://www.ensma.fr
14  *
15  * Contributor(s):
16  * The SLIP team,
17  * Benoit Tremblais <tremblais_AT_sic.univ-poitiers.fr>,
18  * Laurent David <laurent.david_AT_lea.univ-poitiers.fr>,
19  * Ludovic Chatellier <ludovic.chatellier_AT_univ-poitiers.fr>,
20  * Lionel Thomas <lionel.thomas_AT_univ-poitiers.fr>,
21  * Denis Arrivault <arrivault_AT_sic.univ-poitiers.fr>,
22  * Julien Dombre <julien.dombre_AT_univ-poitiers.fr>.
23  *
24  * Description:
25  * The Simple Library of Image Processing (SLIP) is a new image processing
26  * library. It is written in the C++ language following as much as possible
27  * the ISO/ANSI C++ standard. It is consequently compatible with any system
28  * satisfying the ANSI C++ complience. It works on different Unix , Linux ,
29  * Mircrosoft Windows and Mac OS X plateforms. SLIP is a research library that
30  * was created by the Signal, Image and Communications (SIC) departement of
31  * the XLIM, UMR 7252 CNRS Institute in collaboration with the Fluids, Thermic
32  * and Combustion departement of the P', UPR 3346 CNRS Institute of the
33  * University of Poitiers.
34  *
35  * The SLIP Library source code has been registered to the APP (French Agency
36  * for the Protection of Programs) by the University of Poitiers and CNRS,
37  * under registration number IDDN.FR.001.300034.000.S.P.2010.000.21000.
38 
39  * http://www.sic.sp2mi.univ-poitiers.fr/slip/
40  *
41  * This software is governed by the CeCILL-C license under French law and
42  * abiding by the rules of distribution of free software. You can use,
43  * modify and/ or redistribute the software under the terms of the CeCILL-C
44  * license as circulated by CEA, CNRS and INRIA at the following URL
45  * http://www.cecill.info.
46  * As a counterpart to the access to the source code and rights to copy,
47  * modify and redistribute granted by the license, users are provided only
48  * with a limited warranty and the software's author, the holder of the
49  * economic rights, and the successive licensors have only limited
50  * liability.
51  *
52  * In this respect, the user's attention is drawn to the risks associated
53  * with loading, using, modifying and/or developing or reproducing the
54  * software by the user in light of its specific status of free software,
55  * that may mean that it is complicated to manipulate, and that also
56  * therefore means that it is reserved for developers and experienced
57  * professionals having in-depth computer knowledge. Users are therefore
58  * encouraged to load and test the software's suitability as regards their
59  * requirements in conditions enabling the security of their systems and/or
60  * data to be ensured and, more generally, to use and operate it in the
61  * same conditions as regards security.
62  *
63  * The fact that you are presently reading this means that you have had
64  * knowledge of the CeCILL-C license and that you accept its terms.
65  */
66 
67 
68 
75 #ifndef SLIP_LINEAR_ALGEBRA_QR_HPP
76 #define SLIP_LINEAR_ALGEBRA_QR_HPP
77 
78 #include "linear_algebra.hpp"
80 #include "linear_algebra_svd.hpp"
81 #include "macros.hpp"
82 #include "gram_schmidt.hpp"
83 #include "compare.hpp"
84 //#include "Matrix.hpp"
85 #include <limits>
86 #include <vector>
87 
88 
89 
90 namespace slip
91 {
92 
108  template <class Matrix1, class Matrix2>
109  inline
110  void balance(Matrix1 & A, Matrix2 & D)
111  {
112  assert(A.rows() == A.cols());
113  assert(D.rows() == D.cols());
114  assert(A.rows() == D.cols());
115  typedef typename Matrix1::value_type _T;
116  std::size_t dim = A.rows();
117 
118  _T row_norm, col_norm;
119  bool stop = 0;
120 
121  // initialize D to the identity matrix
122  slip::identity(D);
123 
124  while(!stop)
125  {
126  double g, f, s;
127  stop = 1;
128  for (std::size_t i = 0; i < dim; ++i)
129  {
130  row_norm = 0.0;
131  col_norm = 0.0;
132  for (std::size_t j = 0; j < dim; ++j)
133  {
134  if (j != i)
135  {
136  col_norm += std::abs(A[j][i]);
137  row_norm += std::abs(A[i][j]);
138  }
139  }
140 
141  if ((col_norm == 0.0) || (row_norm == 0.0))
142  {
143  continue;
144  }
145  g = row_norm / 2.0;
146  f = 1.0;
147  s = col_norm + row_norm;
148 
149  // find the integer power of two which
150  // comes closest to balancing the matrix
151 
152  while (col_norm < g)
153  {
154  f *= 2.0;
155  col_norm *= 4.0;
156  }
157 
158  g = row_norm * 2.0;
159 
160  while (col_norm > g)
161  {
162  f /= 2.0;
163  col_norm /= 4.0;
164  }
165 
166  if ((row_norm + col_norm) < 0.95 * s * f)
167  {
168  stop = 0;
169 
170  g = 1.0 / f;
171 
172  // apply similarity transformation D, where
173  // D[i][i] = f
174  D[i][i] *= f;
175  // std::cout << "g : " << g << " - f : " << f << std::endl;
176  // multiply by D on the right and D^{-1} on the left
177  std::transform(A.row_begin(i),A.row_end(i),A.row_begin(i),std::bind2nd(std::multiplies<_T>(),g));
178  std::transform(A.col_begin(i),A.col_end(i),A.col_begin(i),std::bind2nd(std::multiplies<_T>(),f));
179  }
180  }
181  }
182 
183  }
184 
206  template <typename MatrixIterator1,
207  typename MatrixIterator2,
208  typename MatrixIterator3>
209  inline
210  void
211  gram_schmidt_qr(MatrixIterator1 A_up, MatrixIterator1 A_bot,
212  MatrixIterator2 Q_up, MatrixIterator2 Q_bot,
213  MatrixIterator3 R_up, MatrixIterator3 R_bot,
215  {
216  assert((A_up - A_bot)[0] == (Q_up - Q_bot)[0]);
217  assert((A_up - A_bot)[1] == (Q_up - Q_bot)[1]);
218  assert((A_up - A_bot)[1] == (R_up - R_bot)[0]);
219  assert((A_up - A_bot)[1] == (R_up - R_bot)[1]);
220  assert((A_up - A_bot)[0] == (A_up - A_bot)[1]);
221  typedef typename MatrixIterator1::value_type value_type;
222  typedef typename MatrixIterator1::size_type size_type;
223  typename MatrixIterator1::difference_type sizeA = A_bot - A_up;
224  typename MatrixIterator2::difference_type sizeQ = Q_bot - Q_up;
225  typename MatrixIterator3::difference_type sizeR = R_bot - R_up;
226  size_type A_rows = sizeA[0];
227  size_type A_cols = sizeA[1];
228 
229  //init T with A
230  slip::Array2d<value_type> T(A_rows,A_cols,A_up,A_bot);
231 
232  while(!is_upper_triangular(T.upper_left(),T.bottom_right(),tol))
233  {
234  //orthogonalization of T = QR
236  Q_up,Q_bot,
237  R_up,R_bot);
238  //T = RQ
240  Q_up,Q_bot,
241  T.upper_left(),T.bottom_right());
242 
243  }
244  }
245 
246 
265  template <typename Matrix1,
266  typename Matrix2,
267  typename Matrix3>
268  inline
269  void
270  gram_schmidt_qr(const Matrix1& A,
271  Matrix2& Q,
272  Matrix3& R,
274  {
275  slip::gram_schmidt_qr(A.upper_left(),A.bottom_right(),
276  Q.upper_left(),Q.bottom_right(),
277  R.upper_left(),R.bottom_right(),
278  tol);
279  }
280 
281 
298  template <typename Matrix1, typename Vector>
299  inline
300  void
301  householder_qr(Matrix1& M, Vector& V0)
302 
303  {
304  assert(M.rows() == M.cols());
305  assert(V0.size() == M.rows());
306  typedef typename Matrix1::value_type value_type;
307 
308  std::size_t M_rows = M.rows();
309  std::size_t M_cols = M.cols();
310 
311  slip::Vector<value_type> V(M_rows);
312  slip::Box2d<int> box;
313 
314  for(std::size_t j = 0; j < M_cols; ++j)
315  {
316  //computes the householder vector from jth column of M
317  box.set_coord(int(j),int(j),int(M_rows-1),int(M_cols-1));
318  value_type nu = value_type(0);
319 
320  slip::housegen(M.upper_left(box).col_begin(0),
321  M.upper_left(box).col_end(0),
322  V.begin()+j,V.end(),
323  nu);
324  V0[j] = *(V.begin()+j);
325  //computes M = (I-betaVV^*)M(j:M_rows-1,j:M_cols-1)
327  M.upper_left(box),M.bottom_right(box));
328  if(j < M.rows())
329  {
330  //copy householder vector in the jth column of the
331  //lower-triangular part of M
332  std::copy(V.begin()+(j+1),V.end(),
333  M.upper_left(box).col_begin(0)+1);
334  }
335 
336  }
337  }
338 
375  template <typename Matrix1,typename Matrix2, typename Matrix3>
376  inline
377  void
378  householder_qr(const Matrix1& M, Matrix2& Q, Matrix3& R)
379 
380  {
381  assert(Q.rows() == Q.cols());
382  assert(M.rows() == Q.rows());
383  assert(R.rows() == M.rows());
384  assert(R.cols() == M.cols());
385 
386  typedef typename Matrix1::value_type value_type;
387 
388  std::size_t M_rows = M.rows();
389 
390  slip::Vector<value_type> V0(M_rows);
391 
392  //copy R = M
393  std::copy(M.begin(),M.end(),R.begin());
394  slip::householder_qr(R,V0);
396  //fill the lower part of R with zero
397  for(std::size_t i = 0; i < M_rows; ++i)
398  {
399  std::fill(R.row_begin(i),R.row_begin(i)+i,value_type(0.0));
400  }
401  }
402 
403 
417  template <typename MatrixIterator>
418  inline
419  std::size_t subdiag_smaller_elem(MatrixIterator A_up, MatrixIterator A_bot,
420  typename slip::lin_alg_traits<typename std::iterator_traits<MatrixIterator>::value_type>::value_type precision)
421  {
422  slip::DPoint2d<int> d(0,1);
423  typedef typename std::iterator_traits<MatrixIterator>::value_type _T;
424  MatrixIterator A_diag = A_bot;
425  MatrixIterator A_sub = A_bot;
426  A_sub -= d;
427  d.set_coord(1,1);
428  A_diag-=d;
429  A_sub -= d;
430  std::size_t pos = 1;
431  while(A_diag != A_up)
432  {
433  if(((*A_sub) == _T(0)) ||
434  (std::abs(*A_sub) < precision*(std::abs(*A_diag) + std::abs(*(A_diag-d)))))
435  {
436  *A_sub = _T(0);
437  return pos;
438  }
439  pos++;
440  A_sub-=d;
441  A_diag-=d;
442  }
443  return 0;
444  }
445 
446 
496  template <typename MatrixIterator1, typename MatrixIterator2, typename MatrixIterator3>
497  void Schur_factorization_2by2(MatrixIterator1 A_up, MatrixIterator1 A_bot,
498  MatrixIterator2 Z_up, MatrixIterator2 Z_bot,
499  MatrixIterator3 D_up, MatrixIterator3 D_bot)
500  {
501  typedef typename std::iterator_traits<MatrixIterator1>::value_type _T;
502  typename MatrixIterator1::difference_type sizeA= A_bot - A_up;
503  typename MatrixIterator2::difference_type sizeZ= Z_bot - Z_up;
504  typename MatrixIterator3::difference_type sizeD= D_bot - D_up;
505 
506  assert(sizeA[0] == sizeA[1]);
507  assert(sizeZ[0] == sizeZ[1]);
508  assert(sizeD[0] == sizeD[1]);
509  assert(sizeA[1] == 2);
510  assert(sizeZ[1] == 2);
511  assert(sizeD[1] == 2);
512 
513  slip::DPoint2d<int> d10(1,0);
514  slip::DPoint2d<int> d01(0,1);
515  slip::DPoint2d<int> d11(1,1);
516  _T a = *A_up;
517  _T b = *(A_up+d01);
518  _T c = *(A_up+d10);
519  _T d = *(A_up+d11);
520  _T cs,sn;
521  _T tmp;
522  _T p, z;
523  _T bcmax, bcmis, scale;
524  _T tau, sigma;
525  _T cs1, sn1;
526  _T aa, bb, cc, dd;
527  _T sab, sac;
528 
530  {
531  // A is already upper triangular
532  // rotation matrix is the identity
533  cs = _T(1.0);
534  sn = _T(0.0);
535  }
537  {
538  // A is lower triangular
539  // swap rows and columns to make it upper triangular
540 
541  cs = _T(0.0);
542  sn = _T(1.0);
543 
544  tmp = d;
545  d = a;
546  a = tmp;
547  b = -c;
548  c = _T(0.0);
549  }
550  else if ((std::abs(a - d) <= std::abs(std::numeric_limits<_T>::epsilon())) && (slip::sign(b) != slip::sign(c)))
551  {
552  // A has complex eigenvalues with a and d as real part (a=d)
553  cs = _T(1.0);
554  sn = _T(0.0);
555  }
556  else
557  {
558  // General case
559  tmp = a - d;
560  p = 0.5 * tmp;
561  bcmax = (std::abs(b) > std::abs(c) ? std::abs(b) : std::abs(c));
562  bcmis = (std::abs(b) < std::abs(c) ? std::abs(b) : std::abs(c)) * slip::sign(b) * slip::sign(c);
563  scale = (std::abs(p) > bcmax ? std::abs(p) : bcmax);
564  z = (p / scale) * p + (bcmax / scale) * bcmis;
565 
566  //if (z >= 4.0 * std::abs(std::numeric_limits< _T>::epsilon()))
567  if (z >= 4.0 * std::abs(slip::epsilon<_T>()))
568  {
569  // real eigenvalues
570  z = p + slip::sign(p) * std::abs(std::sqrt(scale) * std::sqrt(z));
571  a = d + z;
572  d -= (bcmax / z) * bcmis;
573  tau = slip::pythagore(c, z);
574  cs = z / tau;
575  sn = c / tau;
576  b -= c;
577  c = 0.0;
578  }
579  else
580  {
581 
582  // complex eigenvalues, or one double real eigenvalue
583 
584  sigma = b + c;
585  tau = slip::pythagore(sigma, tmp);
586  cs = std::sqrt(0.5 * (1.0 + std::abs(sigma) / tau));
587  sn = -(p / (tau * cs)) * slip::sign(sigma);
588  // [ aa bb ] = [ a b ] [ cs -sn ]
589  // [ cc dd ] [ c d ] [ sn cs ]
590 
591  aa = a * cs + b * sn;
592  bb = -a * sn + b * cs;
593  cc = c * cs + d * sn;
594  dd = -c * sn + d * cs;
595 
596  // [ a b ] = [ cs sn ] [ aa bb ]
597  // [ c d ] [ -sn cs ] [ cc dd ]
598 
599  a = aa * cs + cc * sn;
600  b = bb * cs + dd * sn;
601  c = -aa * sn + cc * cs;
602  d = -bb * sn + dd * cs;
603 
604  tmp = 0.5 * (a + d);
605  a = d = tmp;
606 
607  if (c != 0.0)
608  {
609  if (b != 0.0)
610  {
611  if (slip::sign(b) == slip::sign(c))
612  {
613  // one double real eigenvalue
614 
615  sab = std::sqrt(std::abs(b));
616  sac = std::sqrt(std::abs(c));
617  p = slip::sign(c) * std::abs(sab * sac);
618  tau = 1.0 / std::sqrt(std::abs(b + c));
619  a = tmp + p;
620  d = tmp - p;
621  b -= c;
622  c = 0.0;
623 
624  cs1 = sab * tau;
625  sn1 = sac * tau;
626  tmp = cs * cs1 - sn * sn1;
627  sn = cs * sn1 + sn * cs1;
628  cs = tmp;
629  }
630  }
631  else
632  {
633  b = -c;
634  c = 0.0;
635  tmp = cs;
636  cs = -sn;
637  sn = tmp;
638  }
639  }
640  }
641  }
642 
643  *D_up = a;
644  *(D_up+d11) = d;
645  *(D_up+d01) = b;
646  *(D_up+d10) = c;
647 
648  *Z_up = cs;
649  *(Z_up+d01) = -sn;
650  *(Z_up+d10) = sn;
651  *(Z_up+d11)= cs;
652  }
653 
672  template <class Matrix, typename VectorIterator>
673  inline
674  void MatrixHouseholder(Matrix & H, VectorIterator V_begin, VectorIterator V_end)
675  {
676  assert(H.rows() == H.cols());
677  assert(H.rows() == std::size_t(V_end-V_begin));
678  typedef typename Matrix::value_type _T;
679  std::size_t d = H.rows();
680  for(std::size_t i=0; i< d; i++)
681  {
682  H[i][i] = _T(1);
683  }
684  _T norm = slip::inner_product(V_begin,V_end,V_begin);
685  if(norm != _T(0))
686  {
687 
689  -_T(2)/norm,
690  V_begin,V_end,
691  V_begin,V_end);
692  }
693 
694  }
695 
714  template <class Vector, typename MatrixIterator>
715  inline
716  void VectorHouseholder(Vector & V, MatrixIterator M_up, MatrixIterator M_bot)
717  {
718  typedef typename Vector::value_type _T;
719  typename MatrixIterator::difference_type sizeM = M_bot - M_up;
720  assert(V.size() == std::size_t(sizeM[0]));
721 
722  _T alpha = - _T(slip::sign(*M_up.col_begin(0)) * std::sqrt(slip::inner_product(M_up.col_begin(0),M_up.col_end(0),M_up.col_begin(0))));
723 
724  V[0] = (*M_up.col_begin(0)) - alpha;
725  for(std::size_t i=1; i<V.size(); ++i)
726  V[i] = *(M_up.col_begin(0)+i);
727  }
728 
729 
730 
731 
748  template <typename HessenbergMatrix, typename Matrix>
749  inline
750  bool Francis_QR_Step(HessenbergMatrix & H, Matrix & Z, slip::Box2d<int> box,
751  bool compute_z)
752  {
753  typedef typename HessenbergMatrix::value_type _T;
754  std::size_t Dim = H.rows();
755  //Francis QR step
756  std::size_t n = (box.bottom_right())[0]+1;
757  std::size_t beg = (box.upper_left())[0];
758 
759  _T s = H[n-1][n-1] + H[n-2][n-2];
760  _T t = (H[n-1][n-1] * H[n-2][n-2]) - (H[n-1][n-2] * H[n-2][n-1]);
761 
762  _T x = (H[beg][beg] * H[beg][beg]) + (H[beg][beg+1] * H[beg+1][beg]) - (s * H[beg][beg]) + t;
763  _T y = H[beg+1][beg] * (H[beg][beg] + H[beg+1][beg+1] - s);
764  _T z = H[beg+1][beg] * H[beg+2][beg+1];
765 
766  for(std::size_t k = beg; k < n-2; k++)
767  {
768  Matrix P3(3,3,_T(0));
769  slip::Vector<_T> V3(3);
770  V3[0] = x; V3[1] = y, V3[2] = z;
771 
772  _T alpha = - _T(slip::sign(V3[0]) * std::sqrt(slip::inner_product(V3.begin(),V3.end(),V3.begin())));
773  slip::Vector<_T> Vh(V3);
774  Vh[0] -= alpha;
775  MatrixHouseholder(P3,Vh.begin(),Vh.end());
776 
777  Matrix Pk(slip::identity<Matrix>(Dim,Dim));
778  Matrix T(Dim,Dim,_T(0));
779  slip::Box2d<int> bk(k,k,k+2,k+2);
780  std::copy(P3.upper_left(),P3.bottom_right(),Pk.upper_left(bk));
781 
782  Matrix Pktr(Pk);
783  slip::transpose(Pk,Pktr);
784  //H = Pktr.H.Pk
787  if(compute_z)
788  {
789  //we accumulate P
792  }
793 
794  x = H[k+1][k];
795  y = H[k+2][k];
796  if(k < (n - 3))
797  z = H[k+3][k];
798  }
799 
800  Matrix P2(2,2,_T(0));
801  slip::Vector<_T> V2(2);
802  V2[0] = x; V2[1] = y;
803 
804  _T alpha = - _T(slip::sign(V2[0]) * std::sqrt(slip::inner_product(V2.begin(),V2.end(),V2.begin())));
805  slip::Vector<_T> Vh(V2);
806  Vh[0] -= alpha;
807  slip::MatrixHouseholder(P2,Vh.begin(),Vh.end());
808 
809  Matrix Pk(slip::identity<Matrix>(Dim,Dim));
810  Matrix T(Dim,Dim,_T(0));
811  slip::Box2d<int> bk(n-2,n-2,n-1,n-1);
812  std::copy(P2.upper_left(),P2.bottom_right(),Pk.upper_left(bk));
813 
814  Matrix Pktr(Pk);
815  slip::transpose(Pk,Pktr);
816  //H = Pktr.H.Pk
819  if(compute_z)
820  {
821  //we accumulate P
824  }
825 
826  return 1;
827  }
828 
829 
848  template <class HessenbergMatrix, class Vector, class Matrix>
849  inline
850  void Francis_Schur_standardize(HessenbergMatrix & H, Vector & Eig,
851  Matrix & Z, slip::Box2d<int> b22,
852  bool compute_z)
853  {
854  assert(b22.width() == b22.height());
855  assert(b22.width() == 2);
856  typedef typename HessenbergMatrix::value_type _T;
857  typedef typename Vector::value_type Complex;
858  Complex J(0,1);
859  std::size_t n = H.rows();
860  std::size_t pos = (b22.upper_left())[0];
861  Matrix U(2,2,_T(0));
862  Matrix D(2,2,_T(0));
863  //Schur decomposition of teh 2_by_2 block
864  slip::Schur_factorization_2by2(H.upper_left(b22),H.bottom_right(b22),U.upper_left(),U.bottom_right(),D.upper_left(),D.bottom_right());
865 
866  // set eigenvalues
867  Eig[pos] = Complex(D[0][0]);
868  Eig[pos + 1] = Complex(D[1][1]);
870  {
871  //double tmp = std::sqrt(std::abs(D[0][1]) * std::abs(D[1][0]));
872  typename Complex::value_type tmp = std::sqrt(std::abs(D[0][1]) * std::abs(D[1][0]));
873  Eig[pos] += J*tmp;
874  Eig[pos + 1] -= J*tmp;
875  }
876 
877 
878  // with
879  // U = [ CS -SN ]
880  // [ SN CS ]
881  //
882  // If H was
883  //
884  // H = [ H11 | H12 | H13 ]
885  // [ 0* | H22 | H23 ]
886  // [ 0 | 0* | H33 ]
887  //
888  // we must compute :
889  //
890  // H = P' H P = [ H11 | H12U | H13 ]
891  // [ U'0* | U'H22U | U'H23 ]
892  // [ 0 | 0* U | H33 ]
893  //
894  // Z = Z * P = [ Z11 | Z12 U | Z13 ]
895  // [ Z21 | Z22 U | Z23 ]
896  // [ Z31 | Z32 U | Z33 ]
897  // with
898  //
899  // P = [ I 0 0 ]
900  // [ 0 U 0 ]
901  // [ 0 0 I ]
902 
903 
904  // calculation of H22
905  std::copy(D.upper_left(),D.bottom_right(),H.upper_left(b22));
906  Matrix Ut(U);
907  Ut[0][1] = U[1][0];
908  Ut[1][0] = U[0][1];
909  Matrix R(n,n,_T(0));
910  if (compute_z && (pos < (n - 2)))
911  {
912  slip::Box2d<int> m23 (pos,pos+2,pos+1,n-1);
913  slip::Box2d<int> m32 (pos+2,pos,n-1,pos+1);
914 
915  // calculation of H23
916  slip::matrix_matrix_multiplies(Ut.upper_left(),Ut.bottom_right(),H.upper_left(m23),H.bottom_right(m23),R.upper_left(m23),R.bottom_right(m23));
917  std::copy(R.upper_left(m23),R.bottom_right(m23),H.upper_left(m23));
918 
919  // calculation of Z32
921  std::copy(R.upper_left(m32),R.bottom_right(m32),Z.upper_left(m32));
922  }
923  if (pos > 0)
924  {
925  // calculation of H12
926  slip::Box2d<int> m12 (0,pos,pos-1,pos+1);
927 
928  slip::matrix_matrix_multiplies(H.upper_left(m12),H.bottom_right(m12),U.upper_left(),U.bottom_right(),R.upper_left(m12),R.bottom_right(m12));
929  std::copy(R.upper_left(m12),R.bottom_right(m12),H.upper_left(m12));
930  if(compute_z)
931  {
932  // calculation of Z12
934  std::copy(R.upper_left(m12),R.bottom_right(m12),Z.upper_left(m12));
935  }
936  }
937 
938  // calculation of Z22
940  std::copy(R.upper_left(b22),R.bottom_right(b22),Z.upper_left(b22));
941 
942  }
943 
987  template <class HessenbergMatrix, class Vector, class Matrix>
988  inline
989  bool Francis_Schur_decomp(HessenbergMatrix & H, Vector & Eig, Matrix & Z,
990  slip::Box2d<int> & box,
992  bool compute_Z)
993  {
994  assert(H.rows() == H.cols());
995  assert((Z.rows() == Z.cols()));
996  assert(Eig.size() == H.cols());
997  assert((Z.rows() == H.rows()));
998  assert(box.width() == box.height());
999  assert(box.width() <= (int)H.rows());
1000 
1001  typedef typename HessenbergMatrix::value_type _T;
1002  typedef typename Vector::value_type Complex;
1003 
1004  std::size_t n = box.width();
1005  std::complex<_T> lambda1,lambda2;
1006  std::size_t endbox = (box.bottom_right())[0], begbox = (box.upper_left())[0], it=0, ittot = -1;
1007 
1008  while((n > 2) && (it < 10))
1009  {
1010  ittot++;
1011  std::size_t q = slip::subdiag_smaller_elem(H.upper_left(box),H.bottom_right(box),precision);
1012 
1013  if(q==0)
1014  {
1015  // no small subdiagonal element found - perform a QR
1016  // sweep on the active reduced hessenberg matrix
1017  slip::Francis_QR_Step(H,Z,box,compute_Z);
1018  continue;
1019  }
1020  if (q == 1)
1021  {
1022  // H[endbox][endbox] is a real eigenvalue
1023  //Eig[endbox] = std::complex<_T>(H[endbox][endbox]);
1024  Eig[endbox] = H[endbox][endbox];
1025 
1026  it = 0;
1027  endbox--;
1028  box.set_coord(begbox,begbox,endbox,endbox);
1029  n = box.width();
1030  }
1031  else if (q == 2)
1032  {
1033  // The last 2*2 diagonal matrix is an eigenvalue system
1034  slip::Box2d<int> b22 (endbox-1,endbox-1,endbox,endbox);
1035  slip::Francis_Schur_standardize(H,Eig,Z,b22,compute_Z);
1036  it = 0;
1037  endbox-=2;
1038  box.set_coord(begbox,begbox,endbox,endbox);
1039  n = box.width();
1040  }
1041  else if (q == n-1)
1042  {
1043  // H[begbox][begbox] and H[begbox+1][begbox+1] are real eigenvalues
1044  // Eig[begbox] = std::complex<_T>(H[begbox][begbox]);
1045  // begbox++;
1046  //Eig[begbox] = std::complex<_T>(H[begbox][begbox]);
1047  Eig[begbox] = H[begbox][begbox];
1048  begbox++;
1049  it = 0;
1050  box.set_coord(begbox,begbox,endbox,endbox);
1051  n = box.width();
1052  }
1053  else if (q == n-2)
1054  {
1055  // The first 2*2 diagonal matrix is an eigenvalue system
1056  slip::Box2d<int> b22 (begbox,begbox,begbox+1,begbox+1);
1057  slip::Francis_Schur_standardize(H,Eig,Z,b22,compute_Z);
1058  it = 0;
1059  begbox+=2;
1060  box.set_coord(begbox,begbox,endbox,endbox);
1061  n = box.width();
1062  }
1063  else
1064  {
1065  // There is a zero element on the subdiagonal somewhere
1066  // in the middle of the matrix - we can now operate
1067  // separately on the two submatrices split by this
1068  // element. q is the row index of the zero element.
1069 
1070  // operate on lower right block first
1071  slip::Box2d<int> blr(endbox-q+1,endbox-q+1,endbox,endbox);
1072  slip::Francis_Schur_decomp(H,Eig,Z,blr,precision,compute_Z);
1073  // operate on upper left block
1074  slip::Box2d<int> bul(begbox,begbox,endbox-q,endbox-q);
1075  slip::Francis_Schur_decomp(H,Eig,Z,bul,precision,compute_Z);
1076  n = 0;
1077  }
1078  }
1079 
1080  // special cases of n = 1 or 2
1081 
1082  if (n == 1)
1083  {
1084  Eig[begbox] = H[begbox][begbox];
1085  begbox ++;
1086  box.set_coord(begbox,begbox,endbox,endbox);
1087  n = 0;
1088  }
1089  else if (n == 2)
1090  {
1091  slip::Francis_Schur_standardize(H,Eig,Z,box,compute_Z);
1092  begbox+=2;
1093  box.set_coord(begbox,begbox,endbox,endbox);
1094  n = 0;
1095  }
1096  return 0;
1097  }
1098 
1137  template <class Matrix1, class Matrix2,class Vector, class Matrix3>
1138  inline
1139  bool schur(const Matrix1& M, Matrix2& H, Matrix3 & Z, Vector & Eig,
1141  {
1143  slip::Box2d<int> box(0,0,(M.rows()-1),(M.cols()-1));
1144  return slip::Francis_Schur_decomp(H,Eig,Z,box,precision,compute_Z);
1145 
1146  }
1147 
1148 
1167  template <class Matrix1,class Matrix2>
1168  inline
1169  bool Sylvester_solve(const Matrix1 & S, slip::Box2d<int> & b11, slip::Box2d<int> & b22, double & g, Matrix2 & X)
1170  {
1171  typedef typename Matrix1::value_type _T;
1172  slip::Point2d<std::size_t> b11_up(std::size_t(b11.upper_left()[0]),std::size_t(b11.upper_left()[1]));
1173  slip::Point2d<std::size_t> b11_bot(std::size_t(b11.bottom_right()[0]),std::size_t(b11.bottom_right()[1]));
1174  slip::Point2d<std::size_t> b22_up(std::size_t(b22.upper_left()[0]),std::size_t(b22.upper_left()[1]));
1175  slip::Point2d<std::size_t> b22_bot(std::size_t(b22.bottom_right()[0]),std::size_t(b22.bottom_right()[1]));
1176  int p = int((b11_bot - b11_up)[0]) + 1;
1177  int q = int((b22_bot - b22_up)[0]) + 1;
1178  assert(p == int((b11_bot - b11_up)[1])+1);
1179  assert((p == 1)||(p == 2));
1180  assert(q == int((b22_bot - b22_up)[1])+1);
1181  assert((q == 1) ||(q == 2));
1183  assert((b22_up - b11_bot) == u);
1184  assert(b11_up[0] == b11_up[1]);
1185 
1186 
1187  //first case p==q==1
1188  if((p==1)&&(q==1))
1189  {
1190  assert(X.dim1() == 1);
1191  assert(X.dim2() == 1);
1192 
1193  if(std::abs(S(b11_up) - S(b22_up)) < std::abs(std::numeric_limits<_T>::epsilon()))
1194  {
1195  g = _T(0);
1196  std::cout << "Possible dependance between blocs" << std::endl;
1197  return false;
1198  }
1199  X[0][0] = g * S[b11_up.x1()][b11_up.x2()+1] / (S(b11_up) - S(b22_up));
1200  }
1201 
1202  //second case p==2 && q==1
1203  else if((p==2)&&(q==1))
1204  {
1205  assert(X.dim1() == 1);
1206  assert(X.dim2() == 2);
1207  std::vector<_T> xt(2,_T(0));
1208  std::vector<_T> B;
1209  B.push_back(g * S[b11_up.x1()][b11_up.x2()+2]);
1210  B.push_back(g * S[b11_bot.x1()][b11_bot.x2()+1]);
1211  Matrix1 G(2,2,_T(0));
1212  G[0][0] = S(b11_up) - S(b22_up);
1213  G[0][1] = S[b11_up.x1()][b11_up.x2()+1];
1214  G[1][0] = S[b11_up.x1()+1][b11_up.x2()];
1215  G[1][1] = S(b11_bot) - S(b22_bot);
1216  if(!slip::gauss_solve_with_filling(G,xt,B,slip::Euclidean_norm<_T>(G.begin(),G.end()) * std::abs(std::numeric_limits<_T>::epsilon())))
1217  {
1218  g = _T(0);
1219  std::cout << "Possible dependance between blocs" << std::endl;
1220  }
1221  std::copy(xt.begin(),xt.end(),X.begin());
1222  }
1223 
1224  //third case p==1 && q==2
1225  else if((p==1)&&(q==2))
1226  {
1227  assert(X.dim1() == 2);
1228  assert(X.dim2() == 1);
1229  std::vector<_T> xt(2,_T(0));
1230  std::vector<_T> B;
1231  B.push_back(g * S[b11_up.x1()][b11_up.x2()+1]);
1232  B.push_back(g * S[b11_bot.x1()][b11_bot.x2()+2]);
1233  Matrix1 G(2,2,_T(0));
1234  G[0][0] = S(b11_up) - S(b22_up);
1235  G[0][1] = -S[b22_up.x1()+1][b22_up.x2()];
1236  G[1][0] = -S[b22_up.x1()][b22_up.x2()+1];
1237  G[1][1] = S(b11_bot) - S(b22_bot);
1238  if(!slip::gauss_solve_with_filling(G,xt,B,slip::Euclidean_norm<_T>(G.begin(),G.end()) * std::abs(std::numeric_limits<_T>::epsilon())))
1239  {
1240  g = _T(0);
1241  std::cout << "Possible dependance between blocs" << std::endl;
1242  }
1243  std::copy(xt.begin(),xt.end(),X.begin());
1244  }
1245 
1246  //fourth case p==2 && q==2
1247  else if((p==2)&&(q==2))
1248  {
1249  assert(X.dim1() == 2);
1250  assert(X.dim2() == 2);
1251  std::vector<_T> xt(4,_T(0));
1252  std::vector<_T> B;
1253  B.push_back(g * S[b11_up.x1()][b11_up.x2()+2]);
1254  B.push_back(g * S[b11_up.x1()][b11_up.x2()+3]);
1255  B.push_back(g * S[b11_bot.x1()][b11_bot.x2()+1]);
1256  B.push_back(g * S[b11_bot.x1()][b11_bot.x2()+2]);
1257  Matrix1 G(4,4,_T(0));
1258  G[0][0] = S(b11_up) - S(b22_up);
1259  G[0][1] = -S[b22_up.x1()+1][b22_up.x2()];
1260  G[0][2] = -S[b11_up.x1()][b11_up.x2()+1];
1261 
1262  G[1][0] = -S[b22_up.x1()][b22_up.x2()+1];
1263  G[1][1] = S(b11_up) - S(b22_bot);
1264  G[1][3] = S[b11_up.x1()][b11_up.x2()+1];
1265 
1266  G[2][0] = S[b11_up.x1()+1][b11_up.x2()];
1267  G[2][2] = S(b11_bot) - S(b22_up);
1268  G[2][3] = -S[b22_up.x1()+1][b22_up.x2()];
1269 
1270  G[3][1] = S[b11_up.x1()+1][b11_up.x2()];
1271  G[3][2] = -S[b22_up.x1()][b22_up.x2()+1];
1272  G[3][3] = S(b11_bot) - S(b22_bot);
1273 
1274  if(!slip::gauss_solve_with_filling(G,xt,B,slip::Euclidean_norm<_T>(G.begin(),G.end()) * std::abs(std::numeric_limits<_T>::epsilon())))
1275  {
1276  g = _T(0);
1277  std::cout << "Possible dependance between blocs" << std::endl;
1278  }
1279  std::copy(xt.begin(),xt.end(),X.begin());
1280  }
1281  return true;
1282  }
1283 
1284 
1285 }// end slip
1286 
1287 
1288 
1289 #endif //SLIP_LINEAR_ALGEBRA_QR_HPP
void x1(const CoordType &x)
Accessor of the first coordinate of Point2d.
Definition: Point2d.hpp:250
void set_coord(const CoordType &x11, const CoordType &x12, const CoordType &x21, const CoordType &x22)
Mutator of the coordinates of the Box2d.
Definition: Box2d.hpp:351
iterator2d upper_left()
Returns a read/write iterator2d that points to the first element of the Array2d. It points to the upp...
Definition: Array2d.hpp:2744
CoordType height() const
compute the height of the Box2d.
Definition: Box2d.hpp:378
T sign(T a)
Computes the sign of a.
Definition: macros.hpp:233
iterator2d upper_left()
Returns a read/write iterator2d that points to the first element of the Matrix. It points to the uppe...
Definition: Matrix.hpp:3135
void Schur_factorization_2by2(MatrixIterator1 A_up, MatrixIterator1 A_bot, MatrixIterator2 Z_up, MatrixIterator2 Z_bot, MatrixIterator3 D_up, MatrixIterator3 D_bot)
Computes the Schur factorization of a real 2-by-2 2d container : where :
iterator end()
Returns a read/write iterator that points one past the last element in the Vector. Iteration is done in ordinary element order.
Definition: Vector.hpp:1481
iterator2d bottom_right()
Returns a read/write iterator2d that points to the past the end element of the Matrix. It points to past the end element of the bottom right element of the Matrix.
Definition: Matrix.hpp:3151
void modified_gram_schmidt(MatrixIterator1 A_up, MatrixIterator1 A_bot, MatrixIterator2 Q_up, MatrixIterator2 Q_bot, MatrixIterator3 R_up, MatrixIterator3 R_bot)
Modified Gram-Schmidt orthogonalization algorithm on a matrix.
bool schur(const Matrix1 &M, Matrix2 &H, Matrix3 &Z, Vector &Eig, bool compute_Z, typename slip::lin_alg_traits< typename Matrix1::value_type >::value_type precision=typename slip::lin_alg_traits< typename Matrix1::value_type >::value_type(1.0E-12))
computes the shur decomposition of a square Matrix and copy the eigenvalues in the Eig vector: Algor...
iterator begin()
Returns a read/write iterator that points to the first element in the Matrix. Iteration is done in or...
Definition: Matrix.hpp:2789
slip::lin_alg_traits< T >::value_type epsilon()
Returns the epsilon value of a real or a complex.
iterator2d bottom_right()
Returns a read/write iterator2d that points to the past the end element of the Array2d. It points to past the end element of the bottom right element of the Array2d.
Definition: Array2d.hpp:2759
size_type cols() const
Returns the number of columns (second dimension size) in the Matrix.
Definition: Matrix.hpp:3512
CoordType width() const
compute the width of the Box2d.
Definition: Box2d.hpp:374
bool Sylvester_solve(const Matrix1 &S, slip::Box2d< int > &b11, slip::Box2d< int > &b22, double &g, Matrix2 &X)
Solve the sylvester equation (from Z.Bai and J.W. Demmel article : -On Swapping Diagonal Blocks in Re...
T cc(InputIterator1 first, InputIterator1 last, InputIterator2 first2)
Computes the standard crosscorrelation between two sequences: . Multiplies successive elements from t...
bool is_upper_triangular(MatrixIterator1 A_up, MatrixIterator1 A_bot, const typename slip::lin_alg_traits< typename std::iterator_traits< MatrixIterator1 >::value_type >::value_type tol=slip::epsilon< typename std::iterator_traits< MatrixIterator1 >::value_type >())
Test if a matrix is upper_triangular.
void bottom_right(Point< CoordType, 2 >)
Accessor/Mutator of the bottom_right point (p2) of Box2d.
Definition: Box2d.hpp:338
Provides common linear algebra algorithms.
Provides some algorithms to compare ranges.
HyperVolume< T > abs(const HyperVolume< T > &M)
void left_householder_update(RandomAccessIterator V_first, RandomAccessIterator V_last, MatrixIterator1 M_up, MatrixIterator1 M_bot)
Left multiplies the Householder matrix P with the matrix M: .
Provides some Gram Schmidt orthogonalization and orthonormalization algorithms.
This is a point2d class, a specialized version of Point<CoordType,DIM> with DIM = 2...
Definition: Array2d.hpp:132
void rank1_update(RandomAccessIterator2d1 A_up, RandomAccessIterator2d1 A_bot, const T &alpha, RandomAccessIterator1 X_first, RandomAccessIterator1 X_last, RandomAccessIterator2 Y_first, RandomAccessIterator2 Y_last)
Computes .
bool Francis_Schur_decomp(HessenbergMatrix &H, Vector &Eig, Matrix &Z, slip::Box2d< int > &box, typename slip::lin_alg_traits< typename HessenbergMatrix::value_type >::value_type precision, bool compute_Z)
computes the Schur decomposition of a square Hessenberg Matrix and copy the eigenvalues in the Eig ve...
Real pythagore(const Real &x, const Real &y)
Computes without destructive underflow or overflow.
Definition: macros.hpp:289
void gram_schmidt_qr(MatrixIterator1 A_up, MatrixIterator1 A_bot, MatrixIterator2 Q_up, MatrixIterator2 Q_bot, MatrixIterator3 R_up, MatrixIterator3 R_bot, const typename slip::lin_alg_traits< typename MatrixIterator1::value_type >::value_type tol)
(modified) Gram-Schmidt qr decomposition.
void x2(const CoordType &x)
Accessor of the second coordinate of Point2d.
Definition: Point2d.hpp:262
bool gauss_solve_with_filling(const Matrix &M, Vector1 &X, const Vector2 &B, typename slip::lin_alg_traits< typename Matrix::value_type >::value_type precision)
Solve the linear system M*X=B with the Gauss pivot method, the null pivot are replaced by precision...
size_type size() const
Returns the number of elements in the Vector.
Definition: Vector.hpp:1743
slip::lin_alg_traits< typename std::iterator_traits< RandomAccessIterator2d >::value_type >::value_type row_norm(RandomAccessIterator2d upper_left, RandomAccessIterator2d bottom_right)
Computes the row norm ( ) of a 2d range.
void copy(_II first, _II last, _OI output_first)
Copy algorithm optimized for slip iterators.
Definition: copy_ext.hpp:177
Difference of Point2D class, specialization of DPoint<CoordType,DIM> with DIM = 2.
Definition: Array2d.hpp:129
Numerical Vector class. This container statisfies the RandomAccessContainer concepts of the Standard ...
Definition: Vector.hpp:104
void set_coord(const CoordType &dx1, const CoordType &dx2)
Accessor/Mutator of the coordinates of DPoint2d.
Definition: DPoint2d.hpp:253
void housegen(VectorIterator1 a_begin, VectorIterator1 a_end, VectorIterator2 u_begin, VectorIterator2 u_end, typename std::iterator_traits< VectorIterator1 >::value_type &nu)
Compute the Householder vector u of a vector a.
Provides some mathematical functors and constants.
HyperVolume< T > sqrt(const HyperVolume< T > &M)
Matrix identity(const std::size_t nr, const std::size_t nc)
Returns an identity matrix which dimensions are nr*nc.
void VectorHouseholder(Vector &V, MatrixIterator M_up, MatrixIterator M_bot)
Computes a Householder vector V from a matrix M : with represents the first column of M and ...
void matrix_matrix_multiplies(MatrixIterator1 M1_up, MatrixIterator1 M1_bot, MatrixIterator2 M2_up, MatrixIterator2 M2_bot, MatrixIterator3 R_up, MatrixIterator3 R_bot)
Computes the matrix matrix multiplication of 2 2d ranges.
Numerical matrix class. This container statisfies the BidirectionnalContainer concepts of the STL...
void Francis_Schur_standardize(HessenbergMatrix &H, Vector &Eig, Matrix &Z, slip::Box2d< int > b22, bool compute_z)
Converts a 2-by-2 diagonal block of H in the Schur form, normalizes H and extract the associated eige...
void left_householder_accumulate(const Matrix1 &M, const Vector1 &V0, Matrix2 &Q)
Computes Q = Q1Q2...Qn from the inplace Householder QR decomposition.
void upper_left(Point< CoordType, 2 >)
Accessor/Mutator of the upper_left point (p1) of Box2d.
Definition: Box2d.hpp:325
size_type rows() const
Returns the number of rows (first dimension size) in the Matrix.
Definition: Matrix.hpp:3499
void householder_qr(Matrix1 &M, Vector &V0)
in place Householder QR decomposition M = QR Q is a rotation matrix and R is an upper triangular ma...
void householder_hessenberg(Matrix1 &M)
Householder Hessenberg reduction of the square matrix M. The result is overwritten in M...
std::iterator_traits< RandomAccessIterator1 >::value_type inner_product(RandomAccessIterator1 first1, RandomAccessIterator1 last1, RandomAccessIterator2 first2, typename std::iterator_traits< RandomAccessIterator1 >::value_type init=typename std::iterator_traits< RandomAccessIterator1 >::value_type())
Computes the inner_product of two ranges X and Y: .
void MatrixHouseholder(Matrix &H, VectorIterator V_begin, VectorIterator V_end)
Computes the Householder matrix of a vector V : If V is an householder vector of a matrix M then is...
std::size_t subdiag_smaller_elem(MatrixIterator A_up, MatrixIterator A_bot, typename slip::lin_alg_traits< typename std::iterator_traits< MatrixIterator >::value_type >::value_type precision)
find the smaller non null (according to the precision) subdiagonal element of a matrix ...
void transpose(const Matrix1 &M, const std::size_t nr1, const std::size_t nc1, Matrix2 &TM, const std::size_t nr2, const std::size_t nc2)
Computes the transpose of a matrix .
slip::lin_alg_traits< typename std::iterator_traits< RandomAccessIterator2d >::value_type >::value_type col_norm(RandomAccessIterator2d upper_left, RandomAccessIterator2d bottom_right)
Computes the column norm ( ) of a 2d range.
void balance(Matrix1 &A, Matrix2 &D)
applies a diagonal similarity transform to the square matrix A to make the rows and columns as close ...
bool Francis_QR_Step(HessenbergMatrix &H, Matrix &Z, slip::Box2d< int > box, bool compute_z)
Computes the Francis QR Step used in the Schur decomposition Algorithm 7.5-1 in "Matrix Computations...
Provides some Singular Value Decomposition (SVD) algorithms.
This is a two-dimensional dynamic and generic container. This container statisfies the Bidirectionnal...
Definition: Array2d.hpp:135
iterator begin()
Returns a read/write iterator that points to the first element in the Vector. Iteration is done in or...
Definition: Vector.hpp:1474