// compute eigensystem of a real symmetric matrix //--------------------------------------------------------- void eig_sym(const DMat& A, DVec& ev, DMat& Q, bool bDoEVecs) //--------------------------------------------------------- { if (!A.is_square()) { umERROR("eig_sym(A)", "matrix is not square."); } int N = A.num_rows(); int LDA=N, LDVL=N, LDVR=N, ldwork=10*N, info=0; DVec work(ldwork, 0.0, OBJ_temp, "work_TMP"); Q = A; // Calculate eigenvectors in Q (optional) ev.resize(N); // Calculate eigenvalues in ev char jobV = bDoEVecs ? 'V' : 'N'; SYEV (jobV,'U', N, Q.data(), LDA, ev.data(), work.data(), ldwork, info); if (info < 0) { umERROR("eig_sym(A, Re,Im)", "Error in input argument (%d)\nNo solution computed.", -info); } else if (info > 0) { umLOG(1, "eig_sym(A, W): ...\n" "\nthe algorithm failed to converge;" "\n%d off-diagonal elements of an intermediate" "\ntridiagonal form did not converge to zero.\n", info); } }
void nuclear_psd_hard_thresholding(DOUBLE *X, DOUBLE *norm, INT rank, INT M, DOUBLE *eigv, \ DOUBLE *eigvec, DOUBLE *work, INT lwork) { CHAR jobz = 'V'; CHAR uplo = 'U'; INT SYEVN = M; INT SYEVLDA = M; INT info; if (lwork == - 1) { SYEV(&jobz, &uplo, &SYEVN, eigvec, &SYEVLDA, eigv, work, &lwork, &info); return; } INT eigvFlag = 0; if (eigv == NULL) { eigv = (DOUBLE *) MALLOC(M * 1 * sizeof(DOUBLE)); eigvFlag = 1; } INT eigvecFlag = 0; if (eigvec == NULL) { eigvec = (DOUBLE *) MALLOC(M * M * sizeof(DOUBLE)); eigvecFlag = 1; } datacpy(eigvec, X, M * M); INT workFlag = 0; if (lwork == 0) { DOUBLE workTemp; lwork = -1; SYEV(&jobz, &uplo, &SYEVN, eigvec, &SYEVLDA, eigv, &workTemp, &lwork, &info); if (info != 0) { PRINTF("Error, INFO = %d. ", info); ERROR("LAPACK error."); } lwork = (INT) workTemp; work = (DOUBLE *) MALLOC(lwork * 1 * sizeof(DOUBLE)); workFlag = 1; } // TODO: Perhaps replace with SYEVR? SYEV(&jobz, &uplo, &SYEVN, eigvec, &SYEVLDA, eigv, work, &lwork, &info); if (info != 0) { PRINTF("Error, INFO = %d. ", info); ERROR("LAPACK error."); } INT iterM; DOUBLE normtemp = 0; DOUBLE alpha; INT SCALN = M; INT incx = 1; for (iterM = 0; iterM < M; ++iterM) { if ((eigv[iterM] < 0) || (iterM < M - rank)){ eigv[iterM] = 0; } else { normtemp += eigv[iterM]; alpha = SQRT(eigv[iterM]); SCAL(&SCALN, &alpha, &eigvec[iterM * M], &incx); } } if (norm != NULL) { *norm = normtemp; } uplo = 'U'; CHAR trans = 'N'; INT SYRKN = M; INT SYRKK = rank; alpha = 1; INT SYRKLDA = M; DOUBLE beta = 0; INT SYRKLDC = M; SYRK(&uplo, &trans, &SYRKN, &SYRKK, &alpha, &eigvec[(M - rank) * M], &SYRKLDA, &beta, X, &SYRKLDC); /* NOTE: alternative 1, somewhat slower than version above. INT iterM; DOUBLE normtemp = 0; memset((void *) X, 0, M * M * sizeof(DOUBLE)); uplo = 'U'; INT SYRN = M; DOUBLE alpha; INT SYRLDA = M; INT incx = 1; for (iterM = 0; iterM < M; ++iterM) { eigv[iterM] = eigv[iterM] - tau; if (eigv[iterM] < 0) { eigv[iterM] = 0; } else { normtemp += eigv[iterM]; alpha = eigv[iterM]; SYR(&uplo, &SYRN, &alpha, &eigvec[iterM * M], &incx, X, &SYRLDA); } } *norm = normtemp; */ INT iterN; for (iterM = 0; iterM < M; ++iterM) { for (iterN = iterM + 1; iterN < M; ++iterN) { X[iterM * M + iterN] = X[iterN * M + iterM]; } } if (eigvFlag == 1) { FREE(eigv); } if (eigvecFlag == 1) { FREE(eigvec); } if (workFlag == 1) { FREE(work); } }