示例#1
0
// 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);
	}
}