47 #include <Eigen/Eigenvalues>
54 using namespace Eigen;
55 using namespace FIFFLIB;
56 using namespace MNELIB;
66 #define MALLOC_30(x,t) (t *)malloc((x)*sizeof(t))
67 #define REALLOC_30(x,y,t) (t *)((x == NULL) ? malloc((y)*sizeof(t)) : realloc((x),(y)*sizeof(t)))
69 #define FREE_30(x) if ((char *)(x) != NULL) free((char *)(x))
71 #define FREE_CMATRIX_30(m) mne_free_cmatrix_30((m))
72 #define FREE_DCMATRIX_30(m) mne_free_dcmatrix_30((m))
74 void mne_free_cmatrix_30 (
float **m)
82 void mne_free_dcmatrix_30 (
double **m)
91 #define ALLOC_CMATRIX_30(x,y) mne_cmatrix_30((x),(y))
93 #define ALLOC_DCMATRIX_30(x,y) mne_dmatrix_30((x),(y))
95 static void matrix_error_30(
int kind,
int nr,
int nc)
99 printf(
"Failed to allocate memory pointers for a %d x %d matrix\n",nr,nc);
101 printf(
"Failed to allocate memory for a %d x %d matrix\n",nr,nc);
103 printf(
"Allocation error for a %d x %d matrix\n",nr,nc);
104 if (
sizeof(
void *) == 4) {
105 printf(
"This is probably because you seem to be using a computer with 32-bit architecture.\n");
106 printf(
"Please consider moving to a 64-bit platform.");
108 printf(
"Cannot continue. Sorry.\n");
112 float **mne_cmatrix_30(
int nr,
int nc)
119 m = MALLOC_30(nr,
float *);
121 matrix_error_30(1,nr,nc);
123 whole = MALLOC_30(nr*nc,
float);
125 matrix_error_30(2,nr,nc);
133 double **mne_dmatrix_30(
int nr,
int nc)
140 m = MALLOC_30(nr,
double *);
142 matrix_error_30(1,nr,nc);
144 whole = MALLOC_30(nr*nc,
double);
146 matrix_error_30(2,nr,nc);
156 int mne_decompose_eigen (
double *mat,
167 int np = dim*(dim+1)/2;
168 double *w = MALLOC_30(dim,
double);
169 double *z = MALLOC_30(dim*dim,
double);
170 double *work = MALLOC_30(3*dim,
double);
171 double *dmat = MALLOC_30(np,
double);
172 float *vecp = vectors[0];
181 for(
int i = 0; i < np; ++i)
182 if (std::fabs(mat[i]) > std::fabs(mat[maxi]))
186 scale = 1.0/mat[maxi];
188 for (
k = 0;
k < np;
k++)
189 dmat[
k] = mat[
k]*scale;
193 MatrixXd dmat_tmp = MatrixXd::Zero(dim,dim);
195 for (
int i = 0; i < dim; ++i) {
196 for(
int j = 0; j <= i; ++j) {
197 dmat_tmp(i,j) = dmat[idx];
198 dmat_tmp(j,i) = dmat[idx];
202 SelfAdjointEigenSolver<MatrixXd> es;
203 es.compute(dmat_tmp);
204 for (
int i = 0; i < dim; ++i )
205 w[i] = es.eigenvalues()[i];
208 for (
int j = 0; j < dim; ++j ) {
209 for(
int i = 0; i < dim; ++i ) {
210 z[idx] = es.eigenvectors()(i,j);
218 qDebug() <<
"!!!DEBUG ToDo: dspev(compz,uplo,&dim,dmat,w,z,&dim,work,&info);";
222 printf(
"Eigenvalue decomposition failed (LAPACK info = %d)",info);
225 for (
k = 0;
k < dim;
k++)
226 lambda[
k] = scale*w[
k];
227 for (
k = 0;
k < dim*dim;
k++)
239 double **mne_dmatt_dmat_mult2 (
double **m1,
double **m2,
int d1,
int d2,
int d3)
244 double **result = ALLOC_DCMATRIX_30(d1,d3);
251 dgemm (transa,transb,&d3,&d1,&d2,
252 &one,m2[0],&d3,m1[0],&d1,&zero,result[0],&d3);
259 for (j = 0; j < d1; j++)
260 for (
k = 0;
k < d3;
k++) {
262 for (p = 0; p < d2; p++)
263 sum = sum + m1[p][j]*m2[p][
k];
274 MneCovMatrix::MneCovMatrix(
int p_kind,
276 const QStringList& p_names,
287 ,cov_diag(p_cov_diag)
288 ,cov_sparse(p_cov_sparse)
309 FREE_CMATRIX_30(eigen);
333 nval = (c->ncov*(c->ncov+1))/2;
335 vals = MALLOC_30(nval,
double);
337 for (
k = 0;
k < nval;
k++)
338 vals[
k] = c->cov_diag[
k];
339 res = mne_new_cov(c->kind,c->ncov,c->names,NULL,vals);
342 for (
k = 0;
k < nval;
k++)
344 res = mne_new_cov(c->kind,c->ncov,c->names,vals,NULL);
350 res->ch_class = MALLOC_30(c->ncov,
int);
351 for (
k = 0;
k < c->ncov;
k++)
352 res->ch_class[
k] = c->ch_class[
k];
356 res->proj = MneProjOp::mne_dup_proj_op(c->proj);
366 return c->cov_diag != NULL;
376 double *src = c->lambda ? c->lambda : c->cov_diag;
380 qCritical(
"Covariance matrix is not diagonal or not decomposed.");
383 c->inv_lambda = REALLOC_30(c->inv_lambda,c->ncov,
double);
384 for (
k = 0;
k < c->ncov;
k++) {
386 c->inv_lambda[
k] = 0.0;
388 c->inv_lambda[
k] = 1.0/sqrt(src[
k]);
395 int MneCovMatrix::condition_cov(
MneCovMatrix *c,
float rank_threshold,
int use_rank)
397 double *scale = NULL;
399 double *lambda = NULL;
400 float **eigen = NULL;
401 double **data1 = NULL;
402 double **data2 = NULL;
403 double magscale,gradscale,eegscale;
404 int nmag,ngrad,neeg,nok;
411 qCritical(
"Channels not classified. Rank cannot be determined.");
414 magscale = gradscale = eegscale = 0.0;
415 nmag = ngrad = neeg = 0;
416 for (
k = 0;
k < c->ncov;
k++) {
417 if (c->ch_class[
k] == MNE_COV_CH_MEG_MAG) {
418 magscale += c->cov[mne_lt_packed_index(
k,
k)]; nmag++;
420 else if (c->ch_class[
k] == MNE_COV_CH_MEG_GRAD) {
421 gradscale += c->cov[mne_lt_packed_index(
k,
k)]; ngrad++;
423 else if (c->ch_class[
k] == MNE_COV_CH_EEG) {
424 eegscale += c->cov[mne_lt_packed_index(
k,
k)]; neeg++;
427 fprintf(stdout,
"%d ",c->ch_class[
k]);
431 fprintf(stdout,
"\n");
434 magscale = magscale > 0.0 ? sqrt(nmag/magscale) : 0.0;
436 gradscale = gradscale > 0.0 ? sqrt(ngrad/gradscale) : 0.0;
438 eegscale = eegscale > 0.0 ? sqrt(neeg/eegscale) : 0.0;
440 fprintf(stdout,
"%d %g\n",nmag,magscale);
441 fprintf(stdout,
"%d %g\n",ngrad,gradscale);
442 fprintf(stdout,
"%d %g\n",neeg,eegscale);
444 scale = MALLOC_30(c->ncov,
double);
445 for (
k = 0;
k < c->ncov;
k++) {
446 if (c->ch_class[
k] == MNE_COV_CH_MEG_MAG)
448 else if (c->ch_class[
k] == MNE_COV_CH_MEG_GRAD)
449 scale[
k] = gradscale;
450 else if (c->ch_class[
k] == MNE_COV_CH_EEG)
455 cov = MALLOC_30(c->ncov*(c->ncov+1)/2.0,
double);
456 lambda = MALLOC_30(c->ncov,
double);
457 eigen = ALLOC_CMATRIX_30(c->ncov,c->ncov);
458 for (j = 0; j < c->ncov; j++)
459 for (
k = 0;
k <= j;
k++)
460 cov[mne_lt_packed_index(j,
k)] = c->cov[mne_lt_packed_index(j,
k)]*scale[j]*scale[
k];
461 if (mne_decompose_eigen(cov,lambda,eigen,c->ncov) == 0) {
463 for (
k = 0;
k < c->ncov;
k++)
464 fprintf(stdout,
"%g ",lambda[
k]/lambda[c->ncov-1]);
465 fprintf(stdout,
"\n");
468 for (
k = c->ncov-1;
k >= 0;
k--) {
469 if (lambda[
k] >= rank_threshold*lambda[c->ncov-1])
474 printf(
"\n\tEstimated covariance matrix rank = %d (%g)\n",nok,lambda[c->ncov-nok]/lambda[c->ncov-1]);
475 if (use_rank > 0 && use_rank < nok) {
477 printf(
"\tUser-selected covariance matrix rank = %d (%g)\n",nok,lambda[c->ncov-nok]/lambda[c->ncov-1]);
482 for (j = 0; j < c->ncov-nok; j++)
484 data1 = ALLOC_DCMATRIX_30(c->ncov,c->ncov);
485 for (j = 0; j < c->ncov; j++) {
487 mne_print_vector(stdout,NULL,eigen[j],c->ncov);
489 for (
k = 0;
k < c->ncov;
k++)
490 data1[j][
k] = sqrt(lambda[j])*eigen[j][
k];
492 data2 = mne_dmatt_dmat_mult2(data1,data1,c->ncov,c->ncov,c->ncov);
495 for (j = 0; j < c->ncov; j++)
496 mne_print_dvector(stdout,NULL,data2[j],c->ncov);
502 for (
k = 0;
k < c->ncov;
k++)
504 scale[
k] = 1.0/scale[
k];
505 for (j = 0; j < c->ncov; j++)
506 for (
k = 0;
k <= j;
k++)
507 if (c->cov[mne_lt_packed_index(j,
k)] != 0.0)
508 c->cov[mne_lt_packed_index(j,
k)] = scale[j]*scale[
k]*data2[j][
k];
513 FREE_CMATRIX_30(eigen);
514 FREE_DCMATRIX_30(data1);
515 FREE_DCMATRIX_30(data2);
521 int MneCovMatrix::mne_decompose_eigen_cov_small(
MneCovMatrix *c,
float p_small,
int use_rank)
527 float rank_threshold = 1e-6;
535 return mne_add_inv_cov(c);
536 if (c->lambda && c->eigen) {
537 printf(
"\n\tEigenvalue decomposition had been precomputed.\n");
539 for (
k = 0;
k < c->ncov;
k++, c->nzero++)
540 if (c->lambda[
k] > 0)
544 FREE_30(c->lambda); c->lambda = NULL;
545 FREE_CMATRIX_30(c->eigen); c->eigen = NULL;
547 if ((rank = condition_cov(c,rank_threshold,use_rank)) < 0)
550 np = c->ncov*(c->ncov+1)/2;
552 c->lambda = MALLOC_30(c->ncov,
double);
553 c->eigen = ALLOC_CMATRIX_30(c->ncov,c->ncov);
554 if (mne_decompose_eigen (c->cov,c->lambda,c->eigen,c->ncov) != 0)
556 c->nzero = c->ncov - rank;
557 for (
k = 0;
k < c->nzero;
k++)
563 float meglike,eeglike;
567 for (
k = c->nzero; k < c->ncov;
k++) {
568 meglike = eeglike = 0.0;
569 for (p = 0; p < c->ncov; p++) {
570 if (c->ch_class[p] == MNE_COV_CH_EEG)
571 eeglike += std::fabs(c->eigen[
k][p]);
572 else if (c->ch_class[p] == MNE_COV_CH_MEG_MAG || c->ch_class[p] == MNE_COV_CH_MEG_GRAD)
573 meglike += std::fabs(c->eigen[
k][p]);
575 if (meglike > eeglike)
580 printf(
"\t%d MEG and %d EEG-like channels remain in the whitened data\n",nmeg,neeg);
583 return mne_add_inv_cov(c);
586 FREE_30(c->lambda); c->lambda = NULL;
587 FREE_CMATRIX_30(c->eigen); c->eigen = NULL;
594 int MneCovMatrix::mne_decompose_eigen_cov(
MneCovMatrix *c)
597 return mne_decompose_eigen_cov_small(c,-1.0,-1);
602 int MneCovMatrix::mne_lt_packed_index(
int j,
int k)
606 return k + j*(j+1)/2;
608 return j +
k*(
k+1)/2;