30 #ifndef math_eigenLapack_hpp
31 #define math_eigenLapack_hpp
33 #pragma GCC system_header
34 #include <Eigen/Dense>
42 #include "../sys/timeUtils.hpp"
46 #include "../math/plot/gnuPlot.hpp"
64 template<
typename eigenT1,
typename eigenT2>
69 cv.resize(ims.cols(), ims.cols());
71 math::syrk<typename eigenT1::Scalar>( CblasColMajor, CblasLower,
72 CblasTrans, ims.cols(), ims.rows(),
73 1.0, ims.data(), ims.rows(),
74 0., cv.data(), cv.rows());
83 template<
typename floatT>
86 MXLAPACK_INT sizeISuppZ;
87 MXLAPACK_INT sizeWork;
88 MXLAPACK_INT sizeIWork;
109 if(iSuppZ) ::free(iSuppZ);
110 if(work) ::free(work);
111 if(iWork) ::free(iWork);
117 if(iSuppZ) ::free(iSuppZ);
120 if(work) ::free(work);
123 if(iWork) ::free(iWork);
140 template<
typename cvT,
typename calcT>
141 MXLAPACK_INT
eigenSYEVR( Eigen::Array<calcT, Eigen::Dynamic, Eigen::Dynamic> &eigvec,
142 Eigen::Array<calcT, Eigen::Dynamic, Eigen::Dynamic> &eigval,
143 Eigen::Array<cvT, Eigen::Dynamic, Eigen::Dynamic> &X,
150 MXLAPACK_INT numeig, info;
153 MXLAPACK_INT localMem = 0;
161 MXLAPACK_INT n = X.rows();
165 if(ev0 >= 0 && ev1 >= ev0)
172 eigvec.resize(n,IU-IL+1);
176 Eigen::Array<calcT, Eigen::Dynamic, Eigen::Dynamic> Xc = X.template cast<calcT>();
178 if( mem->sizeISuppZ < 2*n)
180 if(mem->iSuppZ) free(mem->iSuppZ);
182 mem->sizeISuppZ = 2*n;
183 mem->iSuppZ = (MXLAPACK_INT *) malloc (mem->sizeISuppZ*
sizeof(MXLAPACK_INT));
185 if ( mem->iSuppZ==NULL )
187 mxError(
"eigenSYEVR", MXE_ALLOCERR,
"malloc failed in eigenSYEVR.");
188 if(localMem)
delete mem;
194 MXLAPACK_INT sizeWork = 26*n;
195 calcT * work = (calcT *) malloc (sizeWork*
sizeof(calcT));
198 MXLAPACK_INT sizeIWork = 10*n;
199 MXLAPACK_INT * iWork = (MXLAPACK_INT *) malloc (sizeIWork*
sizeof(MXLAPACK_INT));
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);
206 mxError(
"eigenSYEVR", MXE_LAPACKERR,
"error from SYEVR");
207 if(localMem)
delete mem;
209 if(iWork) free(iWork);
219 if( mem->sizeWork < ((MXLAPACK_INT) work[0])*(1))
221 if(mem->work) free(mem->work);
223 mem->sizeWork = ((MXLAPACK_INT) work[0])*1;
224 mem->work = (calcT *) malloc ((mem->sizeWork)*
sizeof(calcT));
228 if(mem->sizeIWork < iWork[0]*1)
230 if(mem->iWork) free(mem->iWork);
232 mem->sizeIWork = iWork[0]*1;
233 mem->iWork = (MXLAPACK_INT *) malloc ((mem->sizeIWork)*
sizeof(MXLAPACK_INT));
237 if ((mem->work==NULL)||(mem->iWork==NULL))
239 mxError(
"eigenSYEVR", MXE_ALLOCERR,
"malloc failed in eigenSYEVR.");
240 if(localMem)
delete mem;
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);
249 if(localMem)
delete mem;
263 template<
typename _evCalcT =
double,
typename eigenT,
typename eigenT1>
266 const eigenT1 & Rims,
269 double * t_eigenv =
nullptr,
270 double * t_klim =
nullptr
273 typedef _evCalcT evCalcT;
274 typedef typename eigenT::Scalar realT;
278 Eigen::Array<evCalcT, Eigen::Dynamic, Eigen::Dynamic> evecsd, evalsd;
280 if(cv.rows() != cv.cols())
282 std::cerr <<
"Non-square covariance matrix input to calcKLModes\n";
286 if(cv.rows() != Rims.cols())
288 std::cerr <<
"Covariance matrix - reference image size mismatch in calcKLModes\n";
293 MXLAPACK_INT tNims = cv.rows();
294 MXLAPACK_INT tNpix = Rims.rows();
296 if(n_modes <= 0 || n_modes > tNims) n_modes = tNims;
303 MXLAPACK_INT info = eigenSYEVR<realT, evCalcT>(evecsd, evalsd, cv, tNims - n_modes, tNims,
'L', mem);
309 std::cerr <<
"calckKLModes: eigenSYEVR returned an error (info = " << info <<
")\n";
313 evecs = evecsd.template cast<realT>();
314 evals = evalsd.template cast<realT>();
317 for(MXLAPACK_INT i=0;i< n_modes; ++i)
321 std::cerr <<
"got 0 eigenvalue (# " << i <<
")\n";
324 else if(evals(i) < 0)
326 std::cerr <<
"got < 0 eigenvalue (# " << i <<
")\n";
329 else if( !std::isnormal(evals(i)) )
331 std::cerr <<
"got not-normal eigenvalue (# " << i <<
")\n";
336 evecs.col(i) = evecs.col(i)/sqrt(evals(i));
339 for(
int r=0; r < evecs.rows(); ++r)
341 if( !std::isnormal(evecs.col(i)(r)))
343 std::cerr <<
"got not-normal eigenvector entry (# " << i <<
"," << r <<
")\n";
350 klModes.resize(n_modes, tNpix);
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());
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 )
391 MXLAPACK_INT M = A.rows();
392 MXLAPACK_INT N = A.cols();
393 MXLAPACK_INT LDA = M;
396 MXLAPACK_INT LDU = M;
398 MXLAPACK_INT LDVT = N;
401 MXLAPACK_INT LWORK = -1;
403 MXLAPACK_INT * IWORK =
new MXLAPACK_INT[8*M];
406 math::gesdd<dataT>(JOBZ, M, N, A.data(), LDA, S.data(), U.data(), LDU, VT.data(), LDVT, &wkOpt, LWORK, IWORK, INFO);
410 dataT *WORK =
new dataT[LWORK];
412 INFO = math::gesdd<dataT>(JOBZ, M, N, A.data(), LDA, S.data(), U.data(), LDU, VT.data(), LDVT, WORK, LWORK, IWORK, INFO);
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
438 template<
typename dataT>
442 Eigen::Array<dataT, -1, -1> & U,
443 Eigen::Array<dataT, -1, -1> & S,
444 Eigen::Array<dataT, -1, -1> & VT,
445 Eigen::Array<dataT, -1, -1> & A,
446 dataT & maxCondition,
455 int interact = MX_PINV_NO_INTERACT
459 int minMN = std::min(A.rows(), A.cols());
464 if(info != 0)
return info;
466 dataT Smax=S.maxCoeff();
470 for(MXLAPACK_INT i=0; i< S.rows(); ++i)
472 S(i) = (pow(S(i),2) + pow(alpha*Smax,2)) / S(i);
478 for(MXLAPACK_INT i=0; i< S.rows(); ++i)
480 S(i) = S(i) + -alpha*Smax;
484 int modesToReject = S.rows();
487 modesToReject = -maxCondition;
489 if(modesToReject-1 < S.rows())
491 maxCondition = Smax/S(modesToReject-1,0);
493 else maxCondition = 0;
496 if(interact & MX_PINV_PLOT)
499 gp.
command(
"set title \"SVD Singular Values\"");
501 gp.
plot( S.data(), S.rows(),
" w lp",
"singular values");
504 if(interact & MX_PINV_ASK && ! (interact & MX_PINV_ASK_NMODES))
507 std::cout <<
"Maximum singular value: " << Smax <<
"\n";
508 std::cout <<
"Minimum singular value: " << S.minCoeff() <<
"\n";
509 std::cout <<
"Enter singular value threshold: ";
514 maxCondition = Smax/mine;
516 else maxCondition = 0;
518 else if( interact & MX_PINV_ASK_NMODES)
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: ";
525 modesToReject = mine;
526 if(modesToReject > 0 && modesToReject < S.rows()-1)
528 maxCondition = Smax/S(modesToReject-1,0);
530 else maxCondition = 0;
536 threshold = Smax/maxCondition;
539 Eigen::Array<dataT, -1,-1>
sigma;
540 sigma.resize(S.rows(), S.rows());
545 for(MXLAPACK_INT i=0; i< S.rows(); ++i)
548 if( S(i) >= threshold && i < modesToReject )
550 sigma(i,i) = 1./S(i);
551 if(Smax/S(i) > condition) condition = Smax/S(i);
560 if(interact & MX_PINV_ASK || interact & MX_PINV_ASK_NMODES)
563 std::cout <<
"Modes Rejected: " << nRejected <<
"\n";
564 std::cout <<
"Condition Number: " << condition <<
"\n";
567 PInv = (VT.matrix().transpose()*
sigma.matrix().transpose() ) * U.block(0,0, U.rows(),minMN).matrix().transpose();
590 template<
typename dataT>
594 Eigen::Array<dataT, -1, -1> & A,
595 dataT & maxCondition,
604 int interact = MX_PINV_NO_INTERACT
607 Eigen::Array<dataT,-1,-1> S, U, VT;
609 return eigenPseudoInverse(PInv, condition, nRejected, U, S, VT, A, maxCondition, alpha, interact);
An interactive c++ interface to gnuplot.
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.
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.
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.
A struct to hold the working memory for eigenSYEVR and maintain it between calls if desired.
Declares and defines templatized wrappers for the BLAS.
Declares and defines templatized wrappers for the Lapack library.