autoMixingMatrix Diagonalizer_to_MixingMatrix (Diagonalizer me) { try { autoMixingMatrix thee = MixingMatrix_create (my numberOfRows, my numberOfColumns); NUMpseudoInverse (my data, my numberOfRows, my numberOfColumns, thy data, 0); return thee; } catch (MelderError) { Melder_throw (me, U": no MixingMatrix created."); } }
autoDiagonalizer MixingMatrix_to_Diagonalizer (MixingMatrix me) { try { if (my numberOfRows != my numberOfColumns) { Melder_throw (U"The number of channels and the number of components must be equal."); } autoDiagonalizer thee = Diagonalizer_create (my numberOfRows); NUMpseudoInverse (my data, my numberOfRows, my numberOfColumns, thy data, 0); return thee; } catch (MelderError) { Melder_throw (me, U": no Diagonalizer created."); } }
Any structAffineTransform :: v_invert () { autoAffineTransform thee = Data_copy (this); double tolerance = 0.000001; NUMpseudoInverse (r, n, n, thy r, tolerance); for (long i = 1; i <= n; i++) { thy t[i] = 0; for (long j = 1; j <= thy n; j++) { thy t[i] -= thy r[i][j] * t[j]; } } return thee.transfer(); }
autoSound Sound_and_MixingMatrix_unmix (Sound me, MixingMatrix thee) { try { if (my ny != thy numberOfRows) { Melder_throw (U"The MixingMatrix and the Sound must have the same number of channels."); } autoNUMmatrix<double> minv (1, thy numberOfColumns, 1, thy numberOfRows); NUMpseudoInverse (thy data, thy numberOfRows, thy numberOfColumns, minv.peek(), 0); autoSound him = Sound_create (thy numberOfColumns, my xmin, my xmax, my nx, my dx, my x1); for (long i = 1; i <= thy numberOfColumns; i++) { for (long j = 1; j <= my nx; j++) { double s = 0; for (long k = 1; k <= my ny; k++) { s += minv[i][k] * my z[k][j]; } his z[i][j] = s; } } return him; } catch (MelderError) { Melder_throw (me, U": not unmixed."); } }
void MixingMatrix_and_CrossCorrelationTables_improveUnmixing (MixingMatrix me, CrossCorrelationTables thee, long maxNumberOfIterations, double tol, int method) { autoDiagonalizer him = MixingMatrix_to_Diagonalizer (me); Diagonalizer_and_CrossCorrelationTables_improveDiagonality (him.peek(), thee, maxNumberOfIterations, tol, method); NUMpseudoInverse (his data, his numberOfRows, his numberOfColumns, my data, 0); }
static void Diagonalizer_and_CrossCorrelationTable_qdiag (Diagonalizer me, CrossCorrelationTables thee, double *cweights, long maxNumberOfIterations, double delta) { try { CrossCorrelationTable c0 = (CrossCorrelationTable) thy item[1]; double **w = my data; long dimension = c0 -> numberOfColumns; autoEigen eigen = Thing_new (Eigen); autoCrossCorrelationTables ccts = Data_copy (thee); autoNUMmatrix<double> pinv (1, dimension, 1, dimension); autoNUMmatrix<double> d (1, dimension, 1, dimension); autoNUMmatrix<double> p (1, dimension, 1, dimension); autoNUMmatrix<double> m1 (1, dimension, 1, dimension); autoNUMmatrix<double> wc (1, dimension, 1, dimension); autoNUMvector<double> wvec (1, dimension); autoNUMvector<double> wnew (1, dimension); autoNUMvector<double> mvec (1, dimension); for (long i = 1; i <= dimension; i++) // Transpose W for (long j = 1; j <= dimension; j++) { wc[i][j] = w[j][i]; } // d = diag(diag(W'*C0*W)); // W = W*d^(-1/2); NUMdmatrix_normalizeColumnVectors (wc.peek(), dimension, dimension, c0 -> data); // scale eigenvectors for sphering // [vb,db] = eig(C0); // P = db^(-1/2)*vb'; Eigen_initFromSymmetricMatrix (eigen.peek(), c0 -> data, dimension); for (long i = 1; i <= dimension; i++) { if (eigen -> eigenvalues[i] < 0) { Melder_throw (U"Covariance matrix not positive definite, eigenvalue[", i, U"] is negative."); } double scalef = 1 / sqrt (eigen -> eigenvalues[i]); for (long j = 1; j <= dimension; j++) { p[dimension - i + 1][j] = scalef * eigen -> eigenvectors[i][j]; } } // P*C[i]*P' for (long ic = 1; ic <= thy size; ic++) { CrossCorrelationTable cov1 = (CrossCorrelationTable) thy item[ic]; CrossCorrelationTable cov2 = (CrossCorrelationTable) ccts -> item[ic]; NUMdmatrices_multiply_VCVp (cov2 -> data, p.peek(), dimension, dimension, cov1 -> data, 1); } // W = P'\W == inv(P') * W NUMpseudoInverse (p.peek(), dimension, dimension, pinv.peek(), 0); NUMdmatrices_multiply_VpC (w, pinv.peek(), dimension, dimension, wc.peek(), dimension); // initialisation for order KN^3 for (long ic = 2; ic <= thy size; ic++) { CrossCorrelationTable cov = (CrossCorrelationTable) ccts -> item[ic]; // C * W NUMdmatrices_multiply_VC (m1.peek(), cov -> data, dimension, dimension, w, dimension); // D += scalef * M1*M1' NUMdmatrices_multiplyScaleAdd (d.peek(), m1.peek(), dimension, dimension, 2 * cweights[ic]); } long iter = 0; double delta_w; autoMelderProgress progress (U"Simultaneous diagonalization of many CrossCorrelationTables..."); try { do { // the standard diagonality measure is rather expensive to calculate so we compare the norms of // differences of eigenvectors. delta_w = 0; for (long kol = 1; kol <= dimension; kol++) { for (long i = 1; i <= dimension; i++) { wvec[i] = w[i][kol]; } update_one_column (ccts.peek(), d.peek(), cweights, wvec.peek(), -1, mvec.peek()); Eigen_initFromSymmetricMatrix (eigen.peek(), d.peek(), dimension); // Eigenvalues already sorted; get eigenvector of smallest ! for (long i = 1; i <= dimension; i++) { wnew[i] = eigen -> eigenvectors[dimension][i]; } update_one_column (ccts.peek(), d.peek(), cweights, wnew.peek(), 1, mvec.peek()); for (long i = 1; i <= dimension; i++) { w[i][kol] = wnew[i]; } // compare norms of eigenvectors. We have to compare ||wvec +/- w_new|| because eigenvectors // may change sign. double normp = 0, normm = 0; for (long j = 1; j <= dimension; j++) { double dm = wvec[j] - wnew[j], dp = wvec[j] + wnew[j]; normp += dm * dm; normm += dp * dp; } normp = normp < normm ? normp : normm; normp = sqrt (normp); delta_w = normp > delta_w ? normp : delta_w; } iter++; Melder_progress ((double) iter / (double) (maxNumberOfIterations + 1), U"Iteration: ", iter, U", norm: ", delta_w); } while (delta_w > delta && iter < maxNumberOfIterations); } catch (MelderError) { Melder_clearError (); } // Revert the sphering W = P'*W; // Take transpose to make W*C[i]W' diagonal instead of W'*C[i]*W => (P'*W)'=W'*P NUMmatrix_copyElements (w, wc.peek(), 1, dimension, 1, dimension); NUMdmatrices_multiply_VpC (w, wc.peek(), dimension, dimension, p.peek(), dimension); // W = W'*P: final result // Calculate the "real" diagonality measure // double dm = CrossCorrelationTables_and_Diagonalizer_getDiagonalityMeasure (thee, me, cweights, 1, thy size); } catch (MelderError) { Melder_throw (me, U" & ", thee, U": no joint diagonalization (qdiag)."); } }