/* 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_CrossCorrelationTables_ffdiag (Diagonalizer me, CrossCorrelationTables thee, long maxNumberOfIterations, double delta) { try { long iter = 0, dimension = my numberOfRows; double **v = my data; autoCrossCorrelationTables ccts = CrossCorrelationTables_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 = CrossCorrelationTables_getDiagonalityMeasure (ccts.peek(), nullptr, 0, 0); try { double dm_old, theta = 1, 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, zij = 0, zjj = 0, yij = 0, yji = 0; // zij = zji for (long k = 1; k <= ccts -> size; k++) { CrossCorrelationTable ct = (CrossCorrelationTable) ccts -> item [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; for (long i = 1; i <= dimension; i++) { double normai = 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 = (CrossCorrelationTable) ccts -> item[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 = CrossCorrelationTables_getDiagonalityMeasure (ccts.peek(), 0, 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 CrossCorrelationTables_and_Diagonalizer_getDiagonalityMeasure (CrossCorrelationTables me, Diagonalizer thee, double *w, long start, long end) { autoCrossCorrelationTables him = CrossCorrelationTables_and_Diagonalizer_diagonalize (me, thee); double dm = CrossCorrelationTables_getDiagonalityMeasure (him.peek(), w, start, end); return dm; }
Diagonalizer d = FIRST (Diagonalizer); double dm = CrossCorrelationTables_and_Diagonalizer_getDiagonalityMeasure (ccts, d, 0, GET_INTEGER (L"First table"), GET_INTEGER (L"Last table")); Melder_information (Melder_double (dm), L" (= average sum of squared off-diagonal elements)"); END DIRECT (CrossCorrelationTable_and_Diagonalizer_diagonalize) CrossCorrelationTable cct = FIRST (CrossCorrelationTable); Diagonalizer d = FIRST (Diagonalizer); praat_new (CrossCorrelationTable_and_Diagonalizer_diagonalize (cct, d), cct->name, L"_", d->name); END DIRECT (CrossCorrelationTables_and_Diagonalizer_diagonalize) CrossCorrelationTables ccts = FIRST (CrossCorrelationTables); Diagonalizer d = FIRST (Diagonalizer); praat_new (CrossCorrelationTables_and_Diagonalizer_diagonalize (ccts, d), ccts->name, L"_", d->name); END FORM (CrossCorrelationTables_and_MixingMatrix_improveUnmixing, L"", 0) LABEL (L"", L"Iteration parameters") NATURAL (L"Maximum number of iterations", L"100") POSITIVE (L"Tolerance", L"0.001") OPTIONMENU (L"Diagonalization method", 2) OPTION (L"qdiag") OPTION (L"ffdiag") OK DO MixingMatrix mm = FIRST (MixingMatrix); CrossCorrelationTables ccts = FIRST (CrossCorrelationTables); MixingMatrix_and_CrossCorrelationTables_improveUnmixing (mm, ccts, GET_INTEGER (L"Maximum number of iterations"), GET_REAL (L"Tolerance"), GET_INTEGER (L"Diagonalization method"));