mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
eigenLapack.hpp
Go to the documentation of this file.
1 /** \file eigenLapack.hpp
2  * \brief Interfaces to Lapack and BLAS for Eigen-like arrays.
3  *
4  * \author Jared R. Males (jaredmales@gmail.com)
5  *
6  * \ingroup gen_math_files
7  *
8  */
9 
10 //***********************************************************************//
11 // Copyright 2015, 2016, 2017 Jared R. Males (jaredmales@gmail.com)
12 //
13 // This file is part of mxlib.
14 //
15 // mxlib is free software: you can redistribute it and/or modify
16 // it under the terms of the GNU General Public License as published by
17 // the Free Software Foundation, either version 3 of the License, or
18 // (at your option) any later version.
19 //
20 // mxlib is distributed in the hope that it will be useful,
21 // but WITHOUT ANY WARRANTY; without even the implied warranty of
22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 // GNU General Public License for more details.
24 //
25 // You should have received a copy of the GNU General Public License
26 // along with mxlib. If not, see <http://www.gnu.org/licenses/>.
27 //***********************************************************************//
28 
29 
30 #ifndef math_eigenLapack_hpp
31 #define math_eigenLapack_hpp
32 
33 #pragma GCC system_header
34 #include <Eigen/Dense>
35 
36 
37 #include <cmath>
38 
39 #include "templateBLAS.hpp"
40 #include "templateLapack.hpp"
41 
42 #include "../sys/timeUtils.hpp"
43 
44 //#include "vectorUtils.hpp"
45 
46 #include "../math/plot/gnuPlot.hpp"
47 
48 
49 namespace mx
50 {
51 namespace math
52 {
53 
54 /// Calculates the lower triangular part of the covariance matrix of ims.
55 /** Uses cblas_ssyrk. cv is resized to ims.cols() X ims.cols().
56  * Calculates \f$ cv = A^T*A \f$.
57  *
58  *
59  * \tparam eigenT1 is the eigen matrix/array type of cv.
60  * \tparam eigenT2 is the eigen matrix/array type of ims
61  *
62  * \ingroup eigen_lapack
63  */
64 template<typename eigenT1, typename eigenT2>
65 void eigenSYRK( eigenT1 &cv, ///< [out] is the eigen matrix/array where to store the result
66  const eigenT2 &ims ///< [in] is the eigen matrix/array (images as columns) to calculate the covariance of
67  )
68 {
69  cv.resize(ims.cols(), ims.cols());
70 
71  math::syrk<typename eigenT1::Scalar>(/*const enum CBLAS_ORDER Order*/ CblasColMajor, /*const enum CBLAS_UPLO Uplo*/ CblasLower,
72  /*const enum CBLAS_TRANSPOSE Trans*/ CblasTrans, /*const MXLAPACK_INT N*/ims.cols(), /*const MXLAPACK_INT K*/ ims.rows(),
73  /*const float alpha*/ 1.0, /*const float *A*/ims.data(), /*const MXLAPACK_INT lda*/ ims.rows(),
74  /*const float beta*/ 0., /*float *C*/ cv.data(), /*const MXLAPACK_INT ldc*/ cv.rows());
75 
76 }
77 
78 
79 
80 /// A struct to hold the working memory for eigenSYEVR and maintain it between calls if desired.
81 /** \todo this should have the working memory for the first exploratory call to ?syevr as well.
82  */
83 template<typename floatT>
84 struct syevrMem
85 {
86  MXLAPACK_INT sizeISuppZ;
87  MXLAPACK_INT sizeWork;
88  MXLAPACK_INT sizeIWork;
89 
90  MXLAPACK_INT *iSuppZ;
91 
92  floatT *work;
93 
94  MXLAPACK_INT *iWork;
95 
96  syevrMem()
97  {
98  sizeISuppZ = 0;
99  sizeWork = 0;
100  sizeIWork = 0;
101 
102  iSuppZ = 0;
103  work = 0;
104  iWork = 0;
105  }
106 
107  ~syevrMem()
108  {
109  if(iSuppZ) ::free(iSuppZ);
110  if(work) ::free(work);
111  if(iWork) ::free(iWork);
112 
113  }
114 
115  void free()
116  {
117  if(iSuppZ) ::free(iSuppZ);
118  sizeISuppZ = 0;
119 
120  if(work) ::free(work);
121  sizeWork = 0;
122 
123  if(iWork) ::free(iWork);
124  sizeIWork = 0;
125  }
126 
127 };
128 
129 /// Calculate select eigenvalues and eigenvectors of an Eigen Array
130 /** Uses the templateLapack wrapper for syevr.
131  *
132  * \tparam cvT is the scalar type of X (a.k.a. the covariance matrix)
133  * \tparam calcT is the type in which to calculate the eigenvectors/eigenvalues
134  *
135  * \returns -1000 on an malloc allocation error.
136  * \returns the return code from syevr (info) otherwise.
137  *
138  * \ingroup eigen_lapack
139  */
140 template<typename cvT, typename calcT>
141 MXLAPACK_INT eigenSYEVR( Eigen::Array<calcT, Eigen::Dynamic, Eigen::Dynamic> &eigvec, ///< [out] will contain the eigenvectors as columns
142  Eigen::Array<calcT, Eigen::Dynamic, Eigen::Dynamic> &eigval, ///< [out] will contain the eigenvalues
143  Eigen::Array<cvT, Eigen::Dynamic, Eigen::Dynamic> &X, ///< [in] is a square matrix which is either upper or lower (default) triangular
144  int ev0=0, ///< [in] [optional] is the first desired eigenvalue (default = 0)
145  int ev1=-1, ///< [in] [optional] if >= ev0 then this is the last desired eigenvalue. If -1 all eigenvalues are returned.
146  char UPLO = 'L', ///< [in] [optional] specifies whether X is upper ('U') or lower ('L') triangular. Default is ('L').
147  syevrMem<calcT> * mem = 0 ///< [in] [optional] holds the working memory arrays, can be re-passed to avoid unnecessary re-allocations
148  )
149 {
150  MXLAPACK_INT numeig, info;
151  char RANGE = 'A';
152 
153  MXLAPACK_INT localMem = 0;
154 
155  if(mem == 0)
156  {
157  mem = new syevrMem<calcT>;
158  localMem = 1;
159  }
160 
161  MXLAPACK_INT n = X.rows();
162 
163  MXLAPACK_INT IL = 1;
164  MXLAPACK_INT IU = n;
165  if(ev0 >= 0 && ev1 >= ev0)
166  {
167  RANGE = 'I';
168  IL = ev0+1; //This is FORTRAN, after all
169  IU = ev1;
170  }
171 
172  eigvec.resize(n,IU-IL+1);
173  eigval.resize(n, 1);
174 
175  //Copy X, casting to calcT
176  Eigen::Array<calcT, Eigen::Dynamic, Eigen::Dynamic> Xc = X.template cast<calcT>();
177 
178  if( mem->sizeISuppZ < 2*n)
179  {
180  if(mem->iSuppZ) free(mem->iSuppZ);
181 
182  mem->sizeISuppZ = 2*n;
183  mem->iSuppZ = (MXLAPACK_INT *) malloc (mem->sizeISuppZ*sizeof(MXLAPACK_INT));
184 
185  if ( mem->iSuppZ==NULL )
186  {
187  mxError("eigenSYEVR", MXE_ALLOCERR, "malloc failed in eigenSYEVR.");
188  if(localMem) delete mem;
189  return -1000;
190  }
191  }
192 
193  // Allocate minimum allowed sizes for workspace
194  MXLAPACK_INT sizeWork = 26*n;
195  calcT * work = (calcT *) malloc (sizeWork*sizeof(calcT));
196 
197 
198  MXLAPACK_INT sizeIWork = 10*n;
199  MXLAPACK_INT * iWork = (MXLAPACK_INT *) malloc (sizeIWork*sizeof(MXLAPACK_INT));
200 
201  // Query for optimum sizes for workspace
202  info=math::syevr<calcT>('V', RANGE, UPLO, n, Xc.data(), n, 0, 0, IL, IU, math::lamch<calcT>('S'), &numeig, eigval.data(), eigvec.data(), n, mem->iSuppZ, work, -1, iWork, -1);
203 
204  if(info != 0)
205  {
206  mxError("eigenSYEVR", MXE_LAPACKERR, "error from SYEVR");
207  if(localMem) delete mem;
208 
209  if(iWork) free(iWork);
210 
211  if(work) free(work);
212 
213  return info;
214  }
215 
216  // Now allocate optimum sizes
217  /* -- tested increasing by x10, didn't improve performance at all
218  */
219  if( mem->sizeWork < ((MXLAPACK_INT) work[0])*(1))
220  {
221  if(mem->work) free(mem->work);
222 
223  mem->sizeWork = ((MXLAPACK_INT) work[0])*1;
224  mem->work = (calcT *) malloc ((mem->sizeWork)*sizeof(calcT));
225  }
226  free(work);
227 
228  if(mem->sizeIWork < iWork[0]*1)
229  {
230  if(mem->iWork) free(mem->iWork);
231 
232  mem->sizeIWork = iWork[0]*1;
233  mem->iWork = (MXLAPACK_INT *) malloc ((mem->sizeIWork)*sizeof(MXLAPACK_INT));
234  }
235  free(iWork);
236 
237  if ((mem->work==NULL)||(mem->iWork==NULL))
238  {
239  mxError("eigenSYEVR", MXE_ALLOCERR, "malloc failed in eigenSYEVR.");
240  if(localMem) delete mem;
241  return -1000;
242  }
243 
244  // Now actually do the calculationg
245  info=math::syevr<calcT>('V', RANGE, UPLO, n, Xc.data(), n, 0, 0, IL, IU, math::lamch<calcT>('S'), &numeig, eigval.data(), eigvec.data(), n, mem->iSuppZ, mem->work, mem->sizeWork, mem->iWork, mem->sizeIWork);
246 
247  /* Cleanup and exit */
248 
249  if(localMem) delete mem;
250 
251  return info;
252 }
253 
254 ///Calculate the K-L modes, or principle components, given a covariance matrix.
255 /** Eigen-decomposition of the covariance matrix is performed using \ref eigenSYEVR().
256  *
257  * \tparam evCalcT is the type in which to perform eigen-decomposition.
258  * \tparam eigenT is a 2D Eigen-like type
259  * \tparam eigenT1 is a 2D Eigen-like type.
260  *
261  * \ingroup eigen_lapack
262  */
263 template<typename _evCalcT = double, typename eigenT, typename eigenT1>
264 MXLAPACK_INT calcKLModes( eigenT & klModes, ///< [out] on exit contains the K-L modes (or P.C.s)
265  eigenT & cv, ///< [in] a lower-triangle (in the Lapack sense) square covariance matrix.
266  const eigenT1 & Rims, ///< [in] The reference data. cv.rows() == Rims.cols().
267  int n_modes = 0, ///< [in] [optional] Tbe maximum number of modes to solve for. If 0 all modes are solved for.
268  syevrMem<_evCalcT> * mem = 0, ///< [in] [optional] A memory structure which can be re-used by SYEVR for efficiency.
269  double * t_eigenv = nullptr, ///< [out] [optional] if not null, will be filled in with the time taken to calculate eigenvalues.
270  double * t_klim = nullptr ///< [out] [optional] if not null, will be filled in with the time taken to calculate the KL modes.
271  )
272 {
273  typedef _evCalcT evCalcT;
274  typedef typename eigenT::Scalar realT;
275 
276  eigenT evecs, evals;
277 
278  Eigen::Array<evCalcT, Eigen::Dynamic, Eigen::Dynamic> evecsd, evalsd;
279 
280  if(cv.rows() != cv.cols())
281  {
282  std::cerr << "Non-square covariance matrix input to calcKLModes\n";
283  return -1;
284  }
285 
286  if(cv.rows() != Rims.cols())
287  {
288  std::cerr << "Covariance matrix - reference image size mismatch in calcKLModes\n";
289  return -1;
290  }
291 
292 
293  MXLAPACK_INT tNims = cv.rows();
294  MXLAPACK_INT tNpix = Rims.rows();
295 
296  if(n_modes <= 0 || n_modes > tNims) n_modes = tNims;
297 
298  if( t_eigenv) *t_eigenv = sys::get_curr_time();
299 
300  //Calculate eigenvectors and eigenvalues
301  /* SYEVR sorts eigenvalues in ascending order, so we specifiy the top n_modes
302  */
303  MXLAPACK_INT info = eigenSYEVR<realT, evCalcT>(evecsd, evalsd, cv, tNims - n_modes, tNims, 'L', mem);
304 
305  if( t_eigenv) *t_eigenv = sys::get_curr_time() - *t_eigenv;
306 
307  if(info !=0 )
308  {
309  std::cerr << "calckKLModes: eigenSYEVR returned an error (info = " << info << ")\n";
310  return -1;
311  }
312 
313  evecs = evecsd.template cast<realT>();
314  evals = evalsd.template cast<realT>();
315 
316  //Normalize the eigenvectors
317  for(MXLAPACK_INT i=0;i< n_modes; ++i)
318  {
319  if(evals(i) == 0)
320  {
321  std::cerr << "got 0 eigenvalue (# " << i << ")\n";
322  evecs.col(i) *= 0;
323  }
324  else if(evals(i) < 0)
325  {
326  std::cerr << "got < 0 eigenvalue (# " << i << ")\n";
327  evecs.col(i) *= 0;
328  }
329  else if( !std::isnormal(evals(i)) )
330  {
331  std::cerr << "got not-normal eigenvalue (# " << i << ")\n";
332  evecs.col(i) *= 0;
333  }
334  else
335  {
336  evecs.col(i) = evecs.col(i)/sqrt(evals(i));
337  }
338 
339  for(int r=0; r < evecs.rows(); ++r)
340  {
341  if( !std::isnormal(evecs.col(i)(r)))
342  {
343  std::cerr << "got not-normal eigenvector entry (# " << i << "," << r << ")\n";
344  evecs.col(i) *= 0;
345  continue;
346  }
347  }
348  }
349 
350  klModes.resize(n_modes, tNpix);
351 
352  if( t_klim) *t_klim = sys::get_curr_time();
353 
354  //Now calculate KL images
355  /*
356  * KL = E^T * R ==> C = A^T * B
357  */
358  gemm<realT>(CblasColMajor, CblasTrans, CblasTrans, n_modes, tNpix,
359  tNims, 1., evecs.data(), cv.rows(), Rims.data(), Rims.rows(),
360  0., klModes.data(), klModes.rows());
361 
362  if( t_klim) *t_klim = sys::get_curr_time() - *t_klim;
363 
364  return 0;
365 
366 } //calcKLModes
367 
368 ///Compute the SVD of an Eigen::Array using LAPACK's xgesdd
369 /** Computes the SVD of A, \f$ A = U S V^T \f$.
370  *
371  * \param[out] U the A.rows() x A.rows() left matrix
372  * \param[out] S the A.cols() x 1 matrix of singular values
373  * \param[out] VT the A.cols() x A.cols() right matrix, note this is the transpose.
374  * \param[in] A the input matrix to be decomposed
375  *
376  * \returns
377  * \parblock
378  * 0 on success
379  * -i on error in ith parameter (from LAPACK xgesdd)
380  * >0 did not converge (from LAPACK xgesdd)
381  * \endparblock
382  *
383  * \tparam dataT is either float or double.
384  *
385  * \ingroup eigen_lapack
386  */
387 template<typename dataT>
388 MXLAPACK_INT eigenGESDD( Eigen::Array<dataT,-1,-1> & U, Eigen::Array<dataT,-1,-1> & S, Eigen::Array<dataT,-1,-1> & VT, Eigen::Array<dataT,-1,-1> & A )
389 {
390  char JOBZ = 'A';
391  MXLAPACK_INT M = A.rows();
392  MXLAPACK_INT N = A.cols();
393  MXLAPACK_INT LDA = M;
394  S.resize(N,1);
395  U.resize(M,M);
396  MXLAPACK_INT LDU = M;
397  VT.resize(N,N);
398  MXLAPACK_INT LDVT = N;
399 
400  dataT wkOpt;
401  MXLAPACK_INT LWORK = -1;
402 
403  MXLAPACK_INT * IWORK = new MXLAPACK_INT[8*M];
404  MXLAPACK_INT INFO;
405 
406  math::gesdd<dataT>(JOBZ, M, N, A.data(), LDA, S.data(), U.data(), LDU, VT.data(), LDVT, &wkOpt, LWORK, IWORK, INFO);
407 
408  LWORK = wkOpt;
409  //delete WORK;
410  dataT *WORK = new dataT[LWORK];
411 
412  INFO = math::gesdd<dataT>(JOBZ, M, N, A.data(), LDA, S.data(), U.data(), LDU, VT.data(), LDVT, WORK, LWORK, IWORK, INFO);
413 
414  delete[] WORK;
415  delete[] IWORK;
416 
417  return INFO;
418 }
419 
420 #define MX_PINV_NO_INTERACT 0
421 #define MX_PINV_PLOT 1
422 #define MX_PINV_ASK 2
423 #define MX_PINV_ASK_NMODES 4
424 
425 ///Calculate the pseudo-inverse of a patrix using the SVD
426 /** First computes the SVD of A, \f$ A = U S V^T \f$, using eigenGESDD. Then the psuedo-inverse is calculated as \f$ A^+ = V S^+ U^T\f$.
427  *
428  * The parameter \p interact is intepreted as a bitmask. The values can be
429  * - \ref MX_PINV_PLOT which will cause a plot to be displayed of the singular values
430  * - \ref MX_PINV_ASK which will ask the user for a max. condition number using stdin
431  * - \ref MX_PINV_ASK_NMODES which will ask the user for a max number of modes to include using stdin. Overrides MX_PINV_ASK.
432  * If \p interact is 0 then no interaction is used and \p maxCondition controls the inversion.
433  *
434  * \tparam dataT is either float or double.
435  *
436  * \ingroup eigen_lapack
437  */
438 template<typename dataT>
439 int eigenPseudoInverse( Eigen::Array<dataT, -1, -1> & PInv, ///< [out] The pseudo-inverse of A
440  dataT & condition, ///< [out] The final condition number.
441  int & nRejected, ///< [out] The number of eigenvectors rejected
442  Eigen::Array<dataT, -1, -1> & U, ///< [out] the A.rows() x A.rows() left matrix
443  Eigen::Array<dataT, -1, -1> & S, ///< [out] the A.cols() x 1 matrix of singular values
444  Eigen::Array<dataT, -1, -1> & VT, ///< [out] the A.cols() x A.cols() right matrix, note this is the transpose.
445  Eigen::Array<dataT, -1, -1> & A, ///< [in] The matrix to invert. This will be modified!
446  dataT & maxCondition, /**< [in] If > 0, the maximum condition number desired. If <0 the number of modes to keep.
447  * Used to threshold the singular values. Set to 0 to include all eigenvalues/vectors.
448  * Ignored if interactive.
449  */
450  dataT alpha = 0, /**< [in] [optional] the Tikhonov regularization value, as a fraction of the highest singular value.
451  * If alpha < 0, then it is treated as a (positive) floor (as a fraction of highest
452  * singular value) for the singular values,
453  * which is not the same as Tikhonov (alpha > 0).
454  */
455  int interact = MX_PINV_NO_INTERACT ///< [in] [optional] a bitmask controlling interaction. See above.
456  )
457 {
458 
459  int minMN = std::min(A.rows(), A.cols());
460 
461  MXLAPACK_INT info;
462  info = eigenGESDD(U,S,VT,A);
463 
464  if(info != 0) return info;
465 
466  dataT Smax=S.maxCoeff();
467 
468  if(alpha > 0)
469  {
470  for(MXLAPACK_INT i=0; i< S.rows(); ++i)
471  {
472  S(i) = (pow(S(i),2) + pow(alpha*Smax,2)) / S(i);
473  }
474  }
475 
476  if(alpha < 0)
477  {
478  for(MXLAPACK_INT i=0; i< S.rows(); ++i)
479  {
480  S(i) = S(i) + -alpha*Smax;
481  }
482  }
483 
484  int modesToReject = S.rows();
485  if(maxCondition < 0) //Rejecting mode numbers
486  {
487  modesToReject = -maxCondition;
488 
489  if(modesToReject-1 < S.rows())
490  {
491  maxCondition = Smax/S(modesToReject-1,0);
492  }
493  else maxCondition = 0;
494  }
495 
496  if(interact & MX_PINV_PLOT)
497  {
498  gnuPlot gp;
499  gp.command("set title \"SVD Singular Values\"");
500  gp.logy();
501  gp.plot( S.data(), S.rows(), " w lp", "singular values");
502  }
503 
504  if(interact & MX_PINV_ASK && ! (interact & MX_PINV_ASK_NMODES))
505  {
506  dataT mine;
507  std::cout << "Maximum singular value: " << Smax << "\n";
508  std::cout << "Minimum singular value: " << S.minCoeff() << "\n";
509  std::cout << "Enter singular value threshold: ";
510  std::cin >> mine;
511 
512  if(mine > 0)
513  {
514  maxCondition = Smax/mine;
515  }
516  else maxCondition = 0;
517  }
518  else if( interact & MX_PINV_ASK_NMODES)
519  {
520  unsigned mine;
521  std::cout << "Maximum singular value: " << Smax << "\n";
522  std::cout << "Minimum singular value: " << S.minCoeff() << "\n";
523  std::cout << "Enter number of modes to keep: ";
524  std::cin >> mine;
525  modesToReject = mine;
526  if(modesToReject > 0 && modesToReject < S.rows()-1)
527  {
528  maxCondition = Smax/S(modesToReject-1,0);
529  }
530  else maxCondition = 0;
531  }
532 
533  dataT threshold = 0;
534  if(maxCondition > 0)
535  {
536  threshold = Smax/maxCondition;
537  }
538 
539  Eigen::Array<dataT, -1,-1> sigma;
540  sigma.resize(S.rows(), S.rows());
541  sigma.setZero();
542 
543  condition = 1;
544  nRejected = 0;
545  for(MXLAPACK_INT i=0; i< S.rows(); ++i)
546  {
547 
548  if( S(i) >= threshold && i < modesToReject )
549  {
550  sigma(i,i) = 1./S(i);
551  if(Smax/S(i) > condition) condition = Smax/S(i);
552  }
553  else
554  {
555  sigma(i,i) = 0;
556  ++nRejected;
557  }
558  }
559 
560  if(interact & MX_PINV_ASK || interact & MX_PINV_ASK_NMODES)
561  {
562  dataT mine;
563  std::cout << "Modes Rejected: " << nRejected << "\n";
564  std::cout << "Condition Number: " << condition << "\n";
565  }
566 
567  PInv = (VT.matrix().transpose()*sigma.matrix().transpose() ) * U.block(0,0, U.rows(),minMN).matrix().transpose();
568 
569  return 0;
570 }
571 
572 
573 
574 ///Calculate the pseudo-inverse of a matrix using the SVD
575 /** First computes the SVD of A, \f$ A = U S V^T \f$, using eigenGESDD. Then the psuedo-inverse is calculated as \f$ A^+ = V S^+ U^T\f$.
576  * This interface does not provide access to U, S and VT.
577  *
578  * The parameter \p interact is intepreted as a bitmask. The values can be
579  * - \ref MX_PINV_PLOT which will cause a plot to be displayed of the singular values
580  * - \ref MX_PINV_ASK which will ask the user for a max. condition number using stdin
581  * - \ref MX_PINV_ASK_NMODES which will ask the user for a max number of modes to include using stdin. Overrides MX_PINV_ASK.
582  * If \p interact is 0 then no interaction is used and maxCondition controls the inversion.
583  * *
584  * \tparam dataT is either float or double.
585  *
586  * \overload
587  *
588  * \ingroup eigen_lapack
589  */
590 template<typename dataT>
591 int eigenPseudoInverse( Eigen::Array<dataT, -1, -1> & PInv, ///< [out] The pseudo-inverse of A
592  dataT & condition, ///< [out] The final condition number.
593  int & nRejected, ///< [out] The number of eigenvectors rejected
594  Eigen::Array<dataT, -1, -1> & A, ///< [in] The matrix to invert, will be altered!
595  dataT & maxCondition, /**< [in] If > 0, the maximum condition number desired. If <0 the number of modes to keep.
596  * Used to threshold the singular values. Set to 0 to include all eigenvalues/vectors.
597  * Ignored if interactive.
598  */
599  dataT alpha = 0, /**< [in] [optional] the Tikhonov regularization value, as a fraction of the highest singular value.
600  * If alpha < 0, then it is treated as a (positive) floor (as a fraction of highest
601  * singular value) for the singular values,
602  * which is not the same as Tikhonov (alpha > 0).
603  */
604  int interact = MX_PINV_NO_INTERACT ///< [in] [optional] a bitmask controlling interaction. See above.
605  )
606 {
607  Eigen::Array<dataT,-1,-1> S, U, VT;
608 
609  return eigenPseudoInverse(PInv, condition, nRejected, U, S, VT, A, maxCondition, alpha, interact);
610 }
611 
612 
613 
614 
615 
616 
617 
618 } //namespace math
619 }//namespace mx
620 
621 #endif //math_eigenLapack_hpp
An interactive c++ interface to gnuplot.
Definition: gnuPlot.hpp:193
int plot(const std::string &fname, const std::string &modifiers, const std::string &title, const std::string &name)
Plot from a file specifying all curve components.
int logy()
Set the y axis to log scale.
int command(const std::string &com, bool flush=true)
Send a command to gnuplot.
constexpr units::realT sigma()
Stefan-Boltzmann Constant.
Definition: constants.hpp:82
int eigenPseudoInverse(Eigen::Array< dataT, -1, -1 > &PInv, dataT &condition, int &nRejected, Eigen::Array< dataT, -1, -1 > &A, dataT &maxCondition, dataT alpha=0, int interact=MX_PINV_NO_INTERACT)
Calculate the pseudo-inverse of a matrix using the SVD.
MXLAPACK_INT calcKLModes(eigenT &klModes, eigenT &cv, const eigenT1 &Rims, int n_modes=0, syevrMem< _evCalcT > *mem=0, double *t_eigenv=nullptr, double *t_klim=nullptr)
Calculate the K-L modes, or principle components, given a covariance matrix.
void eigenSYRK(eigenT1 &cv, const eigenT2 &ims)
Calculates the lower triangular part of the covariance matrix of ims.
Definition: eigenLapack.hpp:65
MXLAPACK_INT eigenSYEVR(Eigen::Array< calcT, Eigen::Dynamic, Eigen::Dynamic > &eigvec, Eigen::Array< calcT, Eigen::Dynamic, Eigen::Dynamic > &eigval, Eigen::Array< cvT, Eigen::Dynamic, Eigen::Dynamic > &X, int ev0=0, int ev1=-1, char UPLO='L', syevrMem< calcT > *mem=0)
Calculate select eigenvalues and eigenvectors of an Eigen Array.
MXLAPACK_INT eigenGESDD(Eigen::Array< dataT,-1,-1 > &U, Eigen::Array< dataT,-1,-1 > &S, Eigen::Array< dataT,-1,-1 > &VT, Eigen::Array< dataT,-1,-1 > &A)
Compute the SVD of an Eigen::Array using LAPACK's xgesdd.
typeT get_curr_time(timespec &tsp)
Get the current system time in seconds.
Definition: timeUtils.hpp:63
The mxlib c++ namespace.
Definition: mxError.hpp:107
A struct to hold the working memory for eigenSYEVR and maintain it between calls if desired.
Definition: eigenLapack.hpp:85
Declares and defines templatized wrappers for the BLAS.
Declares and defines templatized wrappers for the Lapack library.