/* This routine is modeled after qdiag.m from Andreas Ziehe, Pavel Laskov, Guido Nolte, Klaus-Robert Müller, A Fast Algorithm for Joint Diagonalization with Non-orthogonal Transformations and its Application to Blind Source Separation, Journal of Machine Learning Research 5 (2004), 777–800. */ static void Diagonalizer_and_CrossCorrelationTableList_ffdiag (Diagonalizer me, CrossCorrelationTableList thee, long maxNumberOfIterations, double delta) { try { long iter = 0, dimension = my numberOfRows; double **v = my data; autoCrossCorrelationTableList ccts = CrossCorrelationTableList_and_Diagonalizer_diagonalize (thee, me); autoNUMmatrix<double> w (1, dimension, 1, dimension); autoNUMmatrix<double> vnew (1, dimension, 1, dimension); autoNUMmatrix<double> cc (1, dimension, 1, dimension); for (long i = 1; i <= dimension; i++) { w[i][i] = 1; } autoMelderProgress progress (U"Simultaneous diagonalization of many CrossCorrelationTables..."); double dm_new = CrossCorrelationTableList_getDiagonalityMeasure (ccts.get(), nullptr, 0, 0); try { double dm_old, theta = 1.0, dm_start = dm_new; do { dm_old = dm_new; for (long i = 1; i <= dimension; i++) { for (long j = i + 1; j <= dimension; j ++) { double zii = 0.0, zij = 0.0, zjj = 0.0, yij = 0.0, yji = 0.0; // zij == zji for (long k = 1; k <= ccts->size; k ++) { CrossCorrelationTable ct = ccts->at [k]; zii += ct -> data [i] [i] * ct -> data [i] [i]; zij += ct -> data [i] [i] * ct -> data [j] [j]; zjj += ct -> data [j] [j] * ct -> data [j] [j]; yij += ct -> data [j] [j] * ct -> data [i] [j]; yji += ct -> data [i] [i] * ct -> data [i] [j]; } double denom = zjj * zii - zij * zij; if (denom != 0) { w[i][j] = (zij * yji - zii * yij) / denom; w[j][i] = (zij * yij - zjj * yji) / denom; } } } double norma = 0.0; for (long i = 1; i <= dimension; i ++) { double normai = 0.0; for (long j = 1; j <= dimension; j ++) { if (i != j) { normai += fabs (w[ i] [j]); } } if (normai > norma) { norma = normai; } } // evaluate the norm if (norma > theta) { double normf = 0; for (long i = 1; i <= dimension; i ++) for (long j = 1; j <= dimension; j ++) if (i != j) { normf += w [i] [j] * w [i] [j]; } double scalef = theta / sqrt (normf); for (long i = 1; i <= dimension; i ++) { for (long j = 1; j <= dimension; j ++) { if (i != j) { w [i] [j] *= scalef; } } } } // update V NUMmatrix_copyElements (v, vnew.peek(), 1, dimension, 1, dimension); NUMdmatrices_multiply_VC (v, w.peek(), dimension, dimension, vnew.peek(), dimension); for (long k = 1; k <= ccts->size; k ++) { CrossCorrelationTable ct = ccts->at [k]; NUMmatrix_copyElements (ct -> data, cc.peek(), 1, dimension, 1, dimension); NUMdmatrices_multiply_VCVp (ct -> data, w.peek(), dimension, dimension, cc.peek(), 1); } dm_new = CrossCorrelationTableList_getDiagonalityMeasure (ccts.get(), nullptr, 0, 0); iter++; Melder_progress ((double) iter / (double) maxNumberOfIterations, U"Iteration: ", iter, U", measure: ", dm_new, U"\n fractional measure: ", dm_new / dm_start); } while (fabs ((dm_old - dm_new) / dm_new) > delta && iter < maxNumberOfIterations); } catch (MelderError) { Melder_clearError (); } } catch (MelderError) { Melder_throw (me, U" & ", thee, U": no joint diagonalization (ffdiag)."); } }
double CrossCorrelationTableList_and_Diagonalizer_getDiagonalityMeasure (CrossCorrelationTableList me, Diagonalizer thee, double *w, long start, long end) { autoCrossCorrelationTableList him = CrossCorrelationTableList_and_Diagonalizer_diagonalize (me, thee); double dm = CrossCorrelationTableList_getDiagonalityMeasure (him.get(), w, start, end); return dm; }
double dm = CrossCorrelationTableList_and_Diagonalizer_getDiagonalityMeasure (ccts, d, 0, GET_INTEGER (U"First table"), GET_INTEGER (U"Last table")); Melder_information (dm, U" (= average sum of squared off-diagonal elements)"); END DIRECT (CrossCorrelationTable_and_Diagonalizer_diagonalize) CrossCorrelationTable cct = FIRST (CrossCorrelationTable); Diagonalizer d = FIRST (Diagonalizer); autoCrossCorrelationTable thee = CrossCorrelationTable_and_Diagonalizer_diagonalize (cct, d); praat_new (thee.move(), cct -> name, U"_", d -> name); END DIRECT (CrossCorrelationTableList_and_Diagonalizer_diagonalize) CrossCorrelationTableList ccts = FIRST (CrossCorrelationTableList); Diagonalizer d = FIRST (Diagonalizer); autoCrossCorrelationTableList thee = CrossCorrelationTableList_and_Diagonalizer_diagonalize (ccts, d); praat_new (thee.move(), ccts->name, U"_", d->name); END FORM (CrossCorrelationTableList_and_MixingMatrix_improveUnmixing, U"", nullptr) LABEL (U"", U"Iteration parameters") NATURAL (U"Maximum number of iterations", U"100") POSITIVE (U"Tolerance", U"0.001") OPTIONMENU (U"Diagonalization method", 2) OPTION (U"qdiag") OPTION (U"ffdiag") OK DO MixingMatrix mm = FIRST (MixingMatrix); CrossCorrelationTableList ccts = FIRST (CrossCorrelationTableList); MixingMatrix_and_CrossCorrelationTableList_improveUnmixing (mm, ccts,