SLIP  1.4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
linear_algebra_svd.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 
74 #ifndef SLIP_LINEAR_ALGEBRA_SVD_HPP
75 #define SLIP_LINEAR_ALGEBRA_SVD_HPP
76 #include <cmath>
77 #include <algorithm>
78 #include <limits>
79 #include "Vector.hpp"
80 #include "Array2d.hpp"
81 #include "linear_algebra.hpp"
82 #include "macros.hpp"
83 #include "norms.hpp"
85 #include "complex_cast.hpp"
86 
87 namespace slip
88 {
89 
91  /* @{ */
143 template<typename Matrix1,
144  typename Vector,
145  typename Matrix2,
146  typename Matrix3>
147 
148 void BiReduce( Matrix1 &X,
149  Vector &d,
150  Vector &e,
151  Matrix2 &U,
152  Matrix3 &V)
153 
154  {
155  assert(X.rows() >= X.rows());
156  assert(U.rows() == X.rows());
157  assert(U.cols() == X.cols());
158  assert(V.rows() == V.cols());
159  assert(V.rows() == X.cols());
160  assert(d.size() == X.cols());
161  assert((e.size() + 1) == X.cols());
162 
163  typedef typename Matrix1::value_type value_type;
165  std::size_t X_rows = X.rows();
166  std::size_t X_cols = X.cols();
167 
168  std::fill(U.begin(),U.end(),value_type(0));
169  std::fill(V.begin(),V.end(),value_type(0));
170 
171  // temporary variables used for householder methode
172  slip::Vector<value_type > a(X_rows,value_type(0));//a
173  slip::Vector<value_type > b(X_cols-1,value_type(0));//b
174 
175  slip::Box2d<int> box;
176  slip::Box2d<int> box2;
177 
178  for(std::size_t k=0;k<X_cols;++k)
179  {
180  if((k<X_cols-1)||(X_rows>X_cols))
181  {
182  slip::housegen(X.col_begin(k)+k,X.col_end(k),a.begin()+(k),a.end(),d[k]);
183  //X[k:n,k]=a
184  std::copy(a.begin()+(k),a.end(),X.col_begin(k)+k);
185  box.set_coord(int(k),int(k+1),int(X_rows-1),int(X_cols-1));
186  //X[k:n,k+1:p]
187  slip::left_householder_update(a.begin()+k,a.end(),
188  X.upper_left(box),X.bottom_right(box));
189 
190  }
191 
192  if(k<X_cols-2)
193  {
194  //housgen(X[k,k+1:p],b^T,e[k])
195  slip::housegen(X.row_begin(k)+(k+1),X.row_end(k),b.begin()+(k),b.end(),e[k]);
196  //X[k,k+1:p]=b^T
197  std::copy(b.begin()+(k),b.end(),X.row_begin(k)+(k+1));
198  box2.set_coord(int(k+1),int(k+1),int(X_rows-1),int(X_cols-1));
199  //M=X[k+1:n,k+1:p]
201  X.upper_left(box2),X.bottom_right(box2));
202 
203 
204  }
205 
206  }
207 
208  e[X_cols-2]=X[X_cols-2][X_cols-1];
209 
210  if((X_rows)==(X_cols))
211  {
212  d[X_cols-1]=X[X_cols-1][X_cols-1];
213  }
214 
215  //Accumulate U
216  // U=( I_p )
217  // ( 0_n-p,p)
218  U.fill(value_type(0));
219  std::size_t U_cols = X.cols();
220  for (std::size_t i = 0; i < U_cols; ++i)
221  {
222  U[i][i] = value_type(1);
223  }
224 
225  std::size_t min_np=std::min(X_cols-1,X_rows-2);
226  for(int k=min_np;k>=0;k--)
227  {
228  std::copy(X.col_begin(k)+k,X.col_end(k),a.begin()+k);
229  box.set_coord(int(k),int(k),int(X.rows()-1),int(X.cols()-1));//U[k:n,k:p]
230  slip::left_householder_update(a.begin()+k,a.end(),
231  U.upper_left(box),U.bottom_right(box));
232  }
233  //Accumulate V
234  //V=I_p()
235 
236  V.fill(value_type(0.0));
237  std::size_t V_cols = X.cols();
238  for (std::size_t i = 0; i < V_cols; ++i)
239  {
240  V[i][i] = value_type(1.0);
241  }
242 
243  for(int k=int((X_cols-3));k>=0;k--)
244  {
245  std::copy(X.row_begin(k)+(k+1),X.row_end(k),b.begin()+k);
246  box2.set_coord(int(k+1),int(k+1),int(X_cols-1),int(X_cols-1));
248  V.upper_left(box2),V.bottom_right(box2));
249 
250  }
251 
252 }
253 
276 template<typename Matrix,typename Vector>
278  Matrix &U,
279  Matrix &V)
280 {
281  assert(d.size() == U.cols());
282  assert((d.size()-1) == e.size());
283  assert(V.rows() == V.cols());
284  assert(U.cols() == V.rows());
285 
286  typedef typename Matrix::value_type value_type;
287  std::size_t d_size = d.size();//d and X have the same size : d.size()=X.cols();
288  value_type mu;
289  double a;
290  for(std::size_t k=0;k<d_size;k++)
291  {
292  a=std::abs(d[k]);
293  if(a!=0.0)
294  {
295  mu=slip::conj(d[k])/a;
296  d[k]=a;
297  if(k!=d_size-1)
298  {
299  e[k]=mu*e[k];
300  }
301  slip::vector_scalar_multiplies(U.col_begin(k),U.col_end(k),slip::conj(mu),U.col_begin(k));//U[:,k]=conj(mu)*U[:,k];
302  }
303  if(k==(d_size-1)) break;
304 
305  a=std::abs(e[k]);
306  if(a!=value_type(0))
307  {
308  mu=slip::conj(e[k])/a;
309  e[k]=a;
310  d[k+1]=mu*d[k+1];
312  }
313 
314  }
315 }
316 
317 
318 
342 template<typename Matrix,typename Vector, typename Real,typename SizeType >
343 void BiQR( Vector &d,
344  Vector &e,
345  Real &sigma,
346  const SizeType& row1,
347  const SizeType& row2,
348  Matrix &U,
349  Matrix &V)
350  {
351  assert(d.size() == U.cols());
352  assert((d.size()-1) == e.size());
353  assert(V.rows() == V.cols());
354  assert(U.cols() == V.rows());
355  typedef typename Vector::value_type value_type;
356  Real scl = std::max(std::abs(d[row1]),std::abs(e[row1]));
357  scl = std::max(std::abs(scl),std::abs(sigma));
358  Real d1 = d[row1]/scl;
359  Real e1 = e[row1]/scl;
360  Real sig = sigma/scl;
361  Real f = (d1+sig) * (d1-sig);
362  Real g = d1 * e1;
363  SizeType row2_m1 = row2 - 1;
364  SizeType V_rows_m1 = V.rows() - 1;
365  SizeType U_rows_m1 = U.rows() - 1;
366 
367  //sinus and cosinus
368  Real s = Real(0);
369  Real c = Real(0);
370  for (SizeType k = row1; k <= row2_m1; ++k)
371  {
372  slip::rotgen(f,g,c,s);
373  if(k != row1)
374  {
375  e[k-1]=f;
376  }
377  f = (c*d[k]) + (s*e[k]);
378  e[k] = (c*e[k]) - (s*d[k]);
379  g = s * d[k+1];
380  d[k+1]=c*d[k+1];
381  slip::right_givens(V,k,k+1,s,c,SizeType(0),V_rows_m1);
382  slip::rotgen(f,g,c,s);
383  d[k] = f;
384  f = (c * e[k]) + (s * d[k+1]);
385  d[k+1] = (c * d[k+1]) - (s * e[k]);
386 
387  if(k < row2_m1)
388  {
389  g = s * e[k+1];
390  e[k+1] = c * e[k+1];
391  }
392  slip::right_givens(U,k,k+1,s,c,SizeType(0),U_rows_m1);
393  }
394  e[row2-1] = f;
395  }
396 
417 template <typename Real >
418 void shift(Real &p,
419  Real &r,
420  Real &q,
421  Real& sigma)
422 {
423  Real ppq = p + q;
424  Real pmq = p - q;
425  Real r2 = r * r;
426  Real a = (ppq * ppq) + r2;
427  Real b = (pmq * pmq) + r2;
428  Real sigma_max = (std::sqrt(a) + std::sqrt(b)) * Real(0.5);
429  if(sigma_max != Real(0.0))
430  {
431  sigma = (std::abs(p*q)) / sigma_max;
432  }
433 
434 }
458 template<typename Vector, typename SizeType>
460  Vector &e,
462  SizeType& l,
463  SizeType& i1,
464  SizeType& i2)
465  {
466  assert(d.size() == (e.size() + 1));
467  assert(l < d.size());
468  assert(i1 < d.size());
469  assert(i2 < d.size());
470 
471  typedef typename Vector::value_type value_type;
472  value_type tau = value_type(0);
473  i1 = i2 = l;
474  while(i1>0)
475  {
476  if(i1 == i2)
477  {
478  tau = d[i1];
479  }
480  else
481  {
482  if(e[i1-1] != value_type(0.0))
483  {
484  tau = d[i1] * (tau/(tau + std::abs(e[i1-1])));
485  }
486  }
487 
488  if(std::abs(e[i1-1]) <= (tol*std::abs(tau)))
489  {
490  e[i1-1] = value_type(0.0);
491 
492  if(i1 == i2)
493  {
494  i2 = i1-1;
495  i1 = i2;
496  }
497  else
498  {
499  return;
500  }
501  }
502  else
503  {
504  i1 = i1 - 1;
505  }
506  }
507  }
508 
509 
510 
511 
512 
513 /* @} */
514 
516  /* @{ */
587 template<typename Matrix1,
588  typename Matrix2,
589  typename RandomAccessIterator,
590  typename Matrix3>
591 void svd(const Matrix1&M,
592  Matrix2 &U,
593  RandomAccessIterator S_first,
594  RandomAccessIterator S_last,
595  Matrix3 &V,
596  const int max_it = 75)
597 {
598 
599  assert(M.rows() >= M.cols());
600  assert(M.rows() == U.rows());
601  assert(M.cols() == U.cols());
602  assert(int(M.cols()) == int((S_last-S_first)));
603  assert(V.rows() == M.cols());
604 
605  typedef typename Matrix1::value_type value_type;
606  //typedef typename Matrix2::value_type real;
608  slip::Array2d<value_type> X(M.rows(),M.cols());
609  std::copy(M.begin(),M.end(),X.begin());
610  std::size_t X_cols = X.cols();
611  std::size_t X_cols_m1 = X_cols - 1;
612 
613  // Reduce X to bidiagonal form, storing the diagonal elements
614  // in d and the super-diagonal elements in e.
615  slip::Vector<value_type> d1(X.cols());
616  slip::Vector<value_type> e1(X.cols()-1);
617  slip::Array2d<value_type> B(X.cols(),X.cols());
618  slip::BiReduce(X,d1,e1,U,V);
619 
620  //if X is complex then apply Bi_complex_to_real
621  if(slip::is_complex(value_type()))
622  {
623  Bi_complex_to_real(d1,e1,U,V);
624  }
625 
626  //copy d1 to d: to work on real data, because the type of d1
627  //by defenition is complex idem for e1
628  slip::Vector<real> d(X_cols);
629  slip::Vector<real> e(X_cols_m1);
630  std::size_t e1_size = e1.size();
631  for(std::size_t i = 0; i < e1_size; ++i)
632  {
633  d[i] = std::real(d1[i]);
634  e[i] = std::real(e1[i]);
635  }
636  //d[d1.size()-1] = std::real(d1[d1.size()-1]);
637  d[e1_size] = std::real(d1[e1_size]);
638 
639  //Main iteration loop for the singular values
640  int iter = 0;
642  std::size_t i1 = 0;
643  std::size_t i2 = X_cols_m1;
644  //std::size_t l = i2;
645  real sigma = real(0);
646  std::size_t oldi2 = 0;
647  bool error = false;
648 
649  while(true)
650  {
651  iter++;
652  if(iter > max_it)
653  {
654  error = true;
655  //std::cout<<"error: no convergence"<<std::endl<<std::endl;
656  break;
657  }
658  oldi2 = i2;
659  slip::BdBacksearch(d,e,tol,i2,i1,i2);
660 
661  if (i2 == 0) break;
662  if(i2 != oldi2)
663  {
664  iter = 0;
665  }
666  slip::shift(d[i2-1],e[i2-1],d[i2],sigma);
667  slip::BiQR(d,e,sigma,i1,i2,U,V);
668 
669  }
670 
671 
672  // Convergence.
673  // Make the singular values positive.
674  //if(i1==i2)
675  for(std::size_t k = 0; k < X_cols; ++k)
676  {
677  if (d[k] <= 0.0)
678  {
679  d[k] = -d[k];
680  slip::vector_scalar_multiplies(V.col_begin(k),V.col_end(k),
681  real(-1),V.col_begin(k));
682  }
683  }
684  // sort the singular values
685  for(std::size_t k = 0; k < X_cols_m1; ++k)
686  {
687 
688  if(d[k] <= d[k+1])
689  {
690  real t = d[k];
691  d[k] = d[k+1];
692  d[k+1] = t;
693  std::swap_ranges(V.col_begin(k),V.col_end(k),V.col_begin(k+1));
694  std::swap_ranges(U.col_begin(k),U.col_end(k),U.col_begin(k+1));
695  }
696 }
697 
698  std::copy(d.begin(),d.end(),S_first);
699 
700 }
701 
773 template<typename Matrix,typename Matrix2>
774 void svd(const Matrix&X,
775  Matrix &U,
776  Matrix2 &S,
777  Matrix &V,
778  const int max_it = 75)
779 {
780  assert(X.rows() >= X.cols());
781  assert(X.rows() == U.rows());
782  assert(X.cols() == U.cols());
783  assert(S.rows() == S.cols());
784  assert(X.cols() == S.cols());
785  assert(V.rows() == X.cols());
786 
788 
789 
790  slip::Vector<real> Svect(X.cols());
791  slip::svd(X,U,Svect.begin(),Svect.end(),V,max_it);
792  std::fill(S.begin(),S.end(),0);
793  slip::set_diagonal(Svect.begin(),Svect.end(),S);
794 }
795 
796 /* @} */
797 
799 /* @{ */
834 template<typename Matrix1,typename RandomAccessIterator, typename Matrix2, typename Matrix3>
835 inline
836 void svd_approx(const Matrix1 &U,
837  RandomAccessIterator S_first,
838  RandomAccessIterator S_last,
839  const Matrix2 &V,
840  const std::size_t K,
841  Matrix3& X)
842 {
843  assert(X.rows() >= X.cols());
844  assert(V.rows() == V.cols());
845  assert(X.rows() == U.rows());
846  assert(X.cols() == U.cols());
847  assert(int(S_last-S_first) == int(U.cols()));
848  assert(int(S_last-S_first) == int(V.rows()));
849  assert(K <= U.cols());
850 
851  std::size_t U_rows = U.rows();
852  //std::size_t U_cols = U.cols();
853  std::size_t V_rows = V.rows();
854  for(std::size_t i = 0; i < U_rows; ++i)
855  {
856  for(std::size_t j = 0; j < V_rows; ++j)
857  {
858  X[i][j] = 0;
859  for(std::size_t k = 0; k < K; ++k)
860  {
861  X[i][j] += S_first[k] * U[i][k] * slip::conj(V[j][k]);
862  }
863  }
864  }
865  }
866 
867 
868 
902  template <class Matrix1,class Matrix2,class Matrix3,class Matrix4>
903  inline
904  void svd_approx(const Matrix1 & U,
905  const Matrix2 & W,
906  const Matrix3 & V,
907  const std::size_t K,
908  Matrix4 & M)
909  {
911  slip::get_diagonal(W,Wvect.begin(),Wvect.end());
912  slip::svd_approx(U,Wvect.begin(),Wvect.end(),V,K,M);
913  }
914 
915 
916 /* @} */
917 
919  /* @{ */
920 
944 template <class Matrix1,
945  typename RandomAccessIterator1,
946  class Matrix2,
947  typename RandomAccessIterator2,
948  typename RandomAccessIterator3>
949  inline
950  void svd_solve(const Matrix1 & U,
951  RandomAccessIterator1 W_first,
952  RandomAccessIterator1 W_last,
953  const Matrix2 & V,
954  RandomAccessIterator2 B_first,
955  RandomAccessIterator2 B_last,
956  RandomAccessIterator3 X_first,
957  RandomAccessIterator3 X_last)
958  {
959  assert(U.rows() >= U.cols());
960  assert(int(X_last - X_first) == int(U.cols()));
961  assert(int(B_last - B_first) == int(U.rows()));
962  assert(int(W_last - W_first) == int(U.cols()));
963  assert(V.rows() == U.cols());
964  typedef typename Matrix1::value_type value_type;
966  //std::size_t U_rows = U.rows();
967  std::size_t U_cols = U.cols();
968 
969  slip::Vector<value_type> tmp(U_cols);
970  // Calculate U^HB.
971  for (std::size_t j = 0; j < U_cols; ++j)
972  {
973 
974  value_type s = value_type(0.0);
975 
976  // Nonzero result only if wj is nonzero.
977  if (W_first[j] != real(0.0))
978  {
979  s = slip::hermitian_inner_product(U.col_begin(j),U.col_end(j),
980  B_first,value_type(0.0));
981  s /= W_first[j];
982  }
983  tmp[j] = s;
984  }
985  // Matrix multiply by V to get answer.
986  slip::matrix_vector_multiplies(V.upper_left(),V.bottom_right(),
987  tmp.begin(),tmp.end(),
988  X_first,X_last);
989  }
990 
1031  template <class Matrix1,
1032  typename RandomAccessIterator1,
1033  typename RandomAccessIterator2>
1034  inline
1035  void svd_solve(const Matrix1 & A,
1036  RandomAccessIterator1 X_first,
1037  RandomAccessIterator1 X_last,
1038  RandomAccessIterator2 B_first,
1039  RandomAccessIterator2 B_last)
1040  {
1041  assert(A.rows() >= A.cols());
1042  assert(int(X_last - X_first) == int(A.cols()));
1043  assert(int(B_last - B_first) == int(A.rows()));
1044 
1045  typedef typename Matrix1::value_type value_type;
1047 
1048 
1049  slip::Vector<real> S(A.cols());
1050  slip::Array2d<value_type> U(A.rows(),A.cols());
1051  slip::Array2d<value_type> V(A.cols(),A.cols());
1052 
1053  //-----------------------------------------------
1054  // svd decomposition.
1055  //-----------------------------------------------
1056  slip::svd(A,U,S.begin(),S.end(),V);
1057  //------------------------------------------------------
1058  // svd truncature (small singular values are put to 0)
1059  //------------------------------------------------------
1060  real Smax = S[0];//*std::max_element(S.begin(),S.end());
1061  real Smin = Smax * slip::epsilon<value_type>();
1062  std::replace_if(S.begin(),S.end(),std::bind2nd(std::less<real>(), Smin),real(0));
1063  //-----------------------------------------------
1064  // svd solve
1065  //-----------------------------------------------
1066  slip::svd_solve(U,
1067  S.begin(),S.end(),
1068  V,
1069  B_first,B_last,
1070  X_first,X_last);
1071  }
1072 
1110  template <class Matrix1,
1111  class Vector1,
1112  class Vector2>
1113  inline
1114  void svd_solve(const Matrix1 & A,
1115  Vector1 & X,
1116  const Vector2 & B)
1117  {
1118 
1119  slip::svd_solve(A,X.begin(),X.end(),B.begin(),B.end());
1120  }
1121 
1122 /* @} */
1123 
1125  /* @{ */
1143 template <class Matrix1,
1144  typename RandomAccessIterator1,
1145  class Matrix2,
1146  class Matrix3>
1147  inline
1148  void svd_inv(const Matrix1 & U,
1149  RandomAccessIterator1 W_first,
1150  RandomAccessIterator1 W_last,
1151  const Matrix2 & V,
1152  Matrix3& Ainv)
1153 
1154  {
1155  typedef typename Matrix1::value_type value_type;
1157  std::size_t U_rows = U.rows();
1158  std::size_t U_cols = U.cols();
1159 
1160  //------------------------------------------------------
1161  // svd truncature (small singular values are put to 0)
1162  //------------------------------------------------------
1163  real Wmax = *W_first;
1164  real Wmin = Wmax * slip::epsilon<value_type>();
1165  std::replace_if(W_first,W_last,std::bind2nd(std::less<real>(), Wmin),real(0));
1166  //------------------------------------------------------
1167  // find the first 0 value
1168  //------------------------------------------------------
1169  RandomAccessIterator1 it = std::find(W_first,W_last,real(0));
1170  std::size_t K = std::size_t(it - W_first);
1171 
1172 
1173  for(std::size_t i = 0; i < U_cols; ++i)
1174  {
1175  for(std::size_t j = 0; j < U_rows; ++j)
1176  {
1177  Ainv[i][j] = 0;
1178 
1179  for(std::size_t k = 0; k < K; ++k)
1180  {
1181 
1182  Ainv[i][j] += (real(1)/W_first[k]) * slip::conj(U[j][k]) * V[i][k];
1183 
1184  }
1185  }
1186  }
1187  }
1188 
1218 template <class Matrix1,
1219  class Matrix2>
1220 inline
1221 void svd_inv(const Matrix1 & A,
1222  Matrix2& Ainv)
1223 {
1224  typedef typename Matrix1::value_type value_type;
1226 
1227 
1228  slip::Vector<real> S(A.cols());
1229  slip::Array2d<value_type> U(A.rows(),A.cols());
1230  slip::Array2d<value_type> V(A.cols(),A.cols());
1231 
1232  //-----------------------------------------------
1233  // svd decomposition.
1234  //-----------------------------------------------
1235  slip::svd(A,U,S.begin(),S.end(),V);
1236  //-----------------------------------------------
1237  // svd inverse
1238  //-----------------------------------------------
1239  slip::svd_inv(U,S.begin(),S.end(),V,Ainv);
1240 }
1241 
1271 template <class Matrix1,
1272  class Matrix2>
1273 inline
1274 void pinv(const Matrix1 & A,
1275  Matrix2& Ainv)
1276 {
1277  slip::svd_inv(A,Ainv);
1278 }
1279 /* @} */
1280 } // end slip
1281 
1282 #endif //SLIP_LINEAR_ALGEBRA_SVD_HPP
Provides a class to manipulate 2d dynamic and generic arrays.
bool is_complex(const T &val)
Test if an element is complex.
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
void right_householder_update(RandomAccessIterator V_first, RandomAccessIterator V_last, MatrixIterator1 M_up, MatrixIterator1 M_bot)
right multiplies the matrix M with the Householder matrix P:
void set_diagonal(RandomAccessIterator1 diag_first, RandomAccessIterator1 diag_last, Container2d &container, const int diag_number=0)
Set the diagonal [diag_first,diag_last) in the diagonal diag_number of a 2d container.
void svd_inv(const Matrix1 &U, RandomAccessIterator1 W_first, RandomAccessIterator1 W_last, const Matrix2 &V, Matrix3 &Ainv)
Singular Value inverse of a matrix from its Singular Value Decomposition given by U...
void pinv(const Matrix1 &A, Matrix2 &Ainv)
Pseudo inverse of a matrix.
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
T & min(const GrayscaleImage< T > &M1)
Returns the min element of a GrayscaleImage.
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.
void rotgen(Real &a, Real &b, Real &cos, Real &sin)
Computes the Givens sinus and cosinus.
void shift(Real &p, Real &r, Real &q, Real &sigma)
Given a matrix compute the smallest singular value of this matrix.
void BiReduce(Matrix1 &X, Vector &d, Vector &e, Matrix2 &U, Matrix3 &V)
BiReduce. Given an n*p matrix X with n>=p Bireduce reduce X to an upper bidiagola form The tranformat...
size_type cols() const
Returns the number of columns (second dimension size) in the Matrix.
Definition: Matrix.hpp:3512
void matrix_vector_multiplies(RandomAccessIterator2d M_upper_left, RandomAccessIterator2d M_bottom_right, RandomAccessIterator1 first1, RandomAccessIterator1 last1, RandomAccessIterator2 result_first, RandomAccessIterator2 result_last)
Computes the multiplication of a Matrix and a Vector: Result=MV.
void svd_solve(const Matrix1 &U, RandomAccessIterator1 W_first, RandomAccessIterator1 W_last, const Matrix2 &V, RandomAccessIterator2 B_first, RandomAccessIterator2 B_last, RandomAccessIterator3 X_first, RandomAccessIterator3 X_last)
Solve Linear (USV^H).X = B where U, S and V are provided by a svd decomposition.
Provides common linear algebra algorithms.
col_iterator col_end(const size_type col)
Returns a read/write iterator that points one past the end element of the column column in the Matrix...
void real(const Matrix1 &C, Matrix2 &R)
Extract the real Matrix of a complex Matrix. .
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: .
void BiQR(Vector &d, Vector &e, Real &sigma, const SizeType &row1, const SizeType &row2, Matrix &U, Matrix &V)
BiQR Given an upper bidiagonal matrix B and a shift sigma, BiQR performs a QR step between rows row1 ...
void right_givens(Matrix &M, const SizeType &col1, const SizeType &col2, const Real &sinus, const Real &cosinus, const SizeType &row1, const SizeType &row2)
Apply right Givens rotation multiplication.
size_type size() const
Returns the number of elements in the Vector.
Definition: Vector.hpp:1743
void fill(const T &value)
Fills the container range [begin(),begin()+size()) with copies of value.
Definition: Vector.hpp:704
void vector_scalar_multiplies(RandomAccessIterator1 V_first, RandomAccessIterator1 V_last, const T &scal, RandomAccessIterator2 result_first)
Computes the multiplication of a vector V by a scalar scal.
void Bi_complex_to_real(Vector &d, Vector &e, Matrix &U, Matrix &V)
BiQR Given an upper bidiagonal matrix B, Bi_complex_to_real transforms the complex bidiagonal form in...
void copy(_II first, _II last, _OI output_first)
Copy algorithm optimized for slip iterators.
Definition: copy_ext.hpp:177
Provides some macros which are used for using complex as real.
Numerical Vector class. This container statisfies the RandomAccessContainer concepts of the Standard ...
Definition: Vector.hpp:104
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)
Numerical matrix class. This container statisfies the BidirectionnalContainer concepts of the STL...
size_type rows() const
Returns the number of rows (first dimension size) in the Matrix.
Definition: Matrix.hpp:3499
std::iterator_traits< RandomAccessIterator1 >::value_type hermitian_inner_product(RandomAccessIterator1 first1, RandomAccessIterator1 last1, RandomAccessIterator2 first2, typename std::iterator_traits< RandomAccessIterator1 >::value_type init)
Computes the hermitian inner-product of two ranges X and Y: .
col_iterator col_begin(const size_type col)
Returns a read/write iterator that points to the first element of the column column in the Matrix...
void svd(const Matrix1 &M, Matrix2 &U, RandomAccessIterator S_first, RandomAccessIterator S_last, Matrix3 &V, const int max_it=75)
(thin) Singular Value Decomposition Given a matrix M, this function computes its singular value decom...
void get_diagonal(const Container2d &container, RandomAccessIterator1 diag_first, RandomAccessIterator1 diag_last, const int diag_number=0)
Get the diagonal diag_number of a 2d container.
void BdBacksearch(Vector &d, Vector &e, const typename slip::lin_alg_traits< typename Vector::value_type >::value_type tol, SizeType &l, SizeType &i1, SizeType &i2)
Back searching a bidiagonal Matrix this algorithm takes a bidiagobal matrix B, a tolerance tol and an...
This is a linear (one-dimensional) dynamic template container. This container statisfies the RandomAc...
Definition: Array.hpp:94
void svd_approx(const Matrix1 &U, RandomAccessIterator S_first, RandomAccessIterator S_last, const Matrix2 &V, const std::size_t K, Matrix3 &X)
Singular Value Approximation of a matrix from its Singular Value Decomposition given by U...
int conj(const int arg)
Provides a class to manipulate numerical vectors.
This is a two-dimensional dynamic and generic container. This container statisfies the Bidirectionnal...
Definition: Array2d.hpp:135
T & max(const GrayscaleImage< T > &M1)
Returns the max element of a GrayscaleImage.
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
Provides some algorithms to compute norms.