ICA.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. /* ICA.cpp
  2. *
  3. * Copyright (C) 2010-2018 David Weenink
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /*
  19. djmw 20101202 Initial version
  20. djmw 20110304 Thing_new
  21. */
  22. #include "ICA.h"
  23. #include "Interpreter.h"
  24. #include "NUM2.h"
  25. #include "Sound_and_PCA.h"
  26. #include "SVD.h"
  27. // matrix multiply R = V*C*V', V is nrv x ncv, C is ncv x ncv, R is nrv x nrv
  28. static void NUMdmatrices_multiply_VCVp (double **r, double **v, integer nrv, integer ncv, double **c, bool csym) {
  29. for (integer i = 1; i <= nrv; i ++) {
  30. integer jstart = csym ? i : 1;
  31. for (integer j = jstart; j <= nrv; j ++) {
  32. // V_ik C_kl V'_lj = V_ik C_kl V_jl
  33. double vcv = 0.0;
  34. for (integer k = 1; k <= ncv; k ++) {
  35. for (integer l = 1; l <= ncv; l ++) {
  36. vcv += v [i] [k] * c [k] [l] * v [j] [l];
  37. }
  38. }
  39. r [i] [j] = vcv;
  40. if (csym) {
  41. r [j] [i] = vcv;
  42. }
  43. }
  44. }
  45. }
  46. #if 0
  47. // matrix multiply R = V'*C*V, V is nrv x ncv, C is ncv x ncv, R is nrv x nrv
  48. static void NUMdmatrices_multiply_VpCV (double **r, double **v, integer nrv, integer ncv, double **c, int csym) {
  49. for (integer i = 1; i <= ncv; i ++) {
  50. integer jstart = csym ? i : 1;
  51. for (integer j = jstart; j <= ncv; j ++) {
  52. // V'_ik C_kl V_lj = V_ki C_kl V_lj
  53. double vcv = 0;
  54. for (integer k = 1; k <= nrv; k ++) {
  55. for (integer l = 1; l <= ncv; l ++) {
  56. vcv += v [k] [i] * c [k] [l] * v [l] [j];
  57. }
  58. }
  59. r [i] [j] = vcv;
  60. if (csym) {
  61. r [j] [i] = vcv;
  62. }
  63. }
  64. }
  65. }
  66. #endif
  67. // matrix multiply V*C, V is nrv x ncv, C is ncv x ncc, R is nrv x ncc;
  68. static void NUMdmatrices_multiply_VC (double **r, double **v, integer nrv, integer ncv, double **c, integer ncc) {
  69. for (integer i = 1; i <= nrv; i ++) {
  70. for (integer j = 1; j <= ncc; j ++) {
  71. // V_ik C_kj
  72. longdouble vc = 0.0;
  73. for (integer k = 1; k <= ncv; k ++) {
  74. vc += v [i] [k] * c [k] [j];
  75. }
  76. r [i] [j] = (double) vc;
  77. }
  78. }
  79. }
  80. // matrix multiply V'*C, V is nrv x ncv, C is nrv x ncc, R is ncv x ncc;
  81. static void NUMdmatrices_multiply_VpC (double **r, double **v, integer nrv, integer ncv, double **c, integer ncc) {
  82. for (integer i = 1; i <= ncv; i ++) {
  83. for (integer j = 1; j <= ncc; j ++) {
  84. // V'_ik C_kj
  85. longdouble vc = 0.0;
  86. for (integer k = 1; k <= nrv; k ++) {
  87. vc += v [k] [i] * c [k] [j];
  88. }
  89. r [i] [j] = (double) vc;
  90. }
  91. }
  92. }
  93. // D += scalef * M * M', M = nrm x ncm, D is nrm x nrm
  94. static void NUMdmatrices_multiplyScaleAdd (double **r, double **m, integer nrm, integer ncm, double scalef) {
  95. for (integer i = 1; i <= nrm; i ++) {
  96. for (integer j = 1; j <= nrm; j ++) {
  97. // M_ik M'_kj = M_ik M_jk
  98. longdouble mm = 0.0;
  99. for (integer k = 1; k <= ncm; k ++) {
  100. mm += m [i] [k] * m [j] [k];
  101. }
  102. r [i] [j] += scalef * mm;
  103. }
  104. }
  105. }
  106. /*
  107. d = diag(diag(W'*C0*W));
  108. W = W*d^(-1/2);
  109. D_ij = W'_ik C_kl W_lj => D_ii = W_ki C_kl W_li
  110. */
  111. static void NUMdmatrix_normalizeColumnVectors (double **w, integer nrw, integer ncw, double **c) {
  112. for (integer i = 1; i <= ncw; i ++) {
  113. longdouble di = 0.0;
  114. for (integer k = 1; k <= ncw; k ++)
  115. for (integer l = 1; l <= nrw; l ++) {
  116. di += w [k] [i] * c [k] [l] * w [l] [i];
  117. }
  118. di = 1.0 / sqrt (di);
  119. for (integer j = 1; j <= nrw; j ++) {
  120. w [j] [i] *= di;
  121. }
  122. }
  123. }
  124. static double NUMdmatrix_diagonalityMeasure (double **v, integer dimension) {
  125. longdouble dmsq = 0.0;
  126. if (dimension < 2) {
  127. return 0.0;
  128. }
  129. for (integer i = 1; i <= dimension; i ++) {
  130. for (integer j = 1; j <= dimension; j ++) {
  131. if (i != j) {
  132. dmsq += v [i] [j] * v [i] [j];
  133. }
  134. }
  135. }
  136. return (double) dmsq / (dimension * (dimension - 1));
  137. }
  138. #if 0
  139. static double NUMdmatrix_diagonalityIndex (double **v, integer dimension) {
  140. double dindex = 0;
  141. for (integer irow = 1; irow <= dimension; irow ++) {
  142. double rowmax = fabs (v [irow] [1]), rowsum = 0;
  143. for (integer icol = 2; icol <= dimension; icol ++) {
  144. if (fabs (v [irow] [icol]) > rowmax) {
  145. rowmax = fabs (v [irow] [icol]);
  146. }
  147. }
  148. for (integer icol = 1; icol <= dimension; icol ++) {
  149. rowsum += fabs (v [irow] [icol]) / rowmax;
  150. }
  151. dindex += rowsum - 1;
  152. }
  153. for (integer icol = 1; icol <= dimension; icol ++) {
  154. double colmax = fabs (v [icol] [1]), colsum = 0;
  155. for (integer irow = 2; irow <= dimension; irow ++) {
  156. if (fabs (v [irow] [icol]) > colmax) {
  157. colmax = fabs (v [irow] [icol]);
  158. }
  159. }
  160. for (integer irow = 1; irow <= dimension; irow ++) {
  161. colsum += fabs (v [irow] [icol]) / colmax;
  162. }
  163. dindex += colsum - 1;
  164. }
  165. return dindex;
  166. }
  167. #endif
  168. /*
  169. This routine is modeled after qdiag.m from Andreas Ziehe, Pavel Laskov, Guido Nolte, Klaus-Robert Müller,
  170. A Fast Algorithm for Joint Diagonalization with Non-orthogonal Transformations and its Application to
  171. Blind Source Separation, Journal of Machine Learning Research 5 (2004), 777–800.
  172. */
  173. static void Diagonalizer_CrossCorrelationTableList_ffdiag (Diagonalizer me, CrossCorrelationTableList thee, integer maxNumberOfIterations, double delta) {
  174. try {
  175. integer iter = 0, dimension = my numberOfRows;
  176. autoCrossCorrelationTableList ccts = CrossCorrelationTableList_Diagonalizer_diagonalize (thee, me);
  177. autoMAT w = MATzero (dimension, dimension);
  178. autoMAT vnew = MATzero (dimension, dimension);
  179. autoMAT cc = MATzero (dimension, dimension);
  180. for (integer i = 1; i <= dimension; i ++) {
  181. w [i] [i] = 1.0;
  182. }
  183. autoMelderProgress progress (U"Simultaneous diagonalization of many CrossCorrelationTables...");
  184. longdouble dm_new = CrossCorrelationTableList_getDiagonalityMeasure (ccts.get(), nullptr, 0, 0);
  185. try {
  186. longdouble dm_old, theta = 1.0, dm_start = dm_new;
  187. do {
  188. dm_old = dm_new;
  189. for (integer i = 1; i <= dimension; i ++) {
  190. for (integer j = i + 1; j <= dimension; j ++) {
  191. longdouble zii = 0.0, zij = 0.0, zjj = 0.0, yij = 0.0, yji = 0.0; // zij == zji
  192. for (integer k = 1; k <= ccts -> size; k ++) {
  193. CrossCorrelationTable ct = ccts -> at [k];
  194. zii += ct -> data [i] [i] * ct -> data [i] [i];
  195. zij += ct -> data [i] [i] * ct -> data [j] [j];
  196. zjj += ct -> data [j] [j] * ct -> data [j] [j];
  197. yij += ct -> data [j] [j] * ct -> data [i] [j];
  198. yji += ct -> data [i] [i] * ct -> data [i] [j];
  199. }
  200. longdouble denom = zjj * zii - zij * zij;
  201. if (denom != 0.0) {
  202. w [i] [j] = (double) (zij * yji - zii * yij) / denom;
  203. w [j] [i] = (double) (zij * yij - zjj * yji) / denom;
  204. }
  205. }
  206. }
  207. longdouble norma = 0.0;
  208. for (integer i = 1; i <= dimension; i ++) {
  209. longdouble normai = 0.0;
  210. for (integer j = 1; j <= dimension; j ++) {
  211. if (i != j) {
  212. normai += fabs (w [i] [j]);
  213. }
  214. }
  215. if (normai > norma) {
  216. norma = normai;
  217. }
  218. }
  219. // evaluate the norm
  220. if (norma > theta) {
  221. longdouble normf = 0.0;
  222. for (integer i = 1; i <= dimension; i ++)
  223. for (integer j = 1; j <= dimension; j ++)
  224. if (i != j) {
  225. normf += w [i] [j] * w [i] [j];
  226. }
  227. longdouble scalef = theta / sqrt (normf);
  228. for (integer i = 1; i <= dimension; i ++) {
  229. for (integer j = 1; j <= dimension; j ++) {
  230. if (i != j) {
  231. w [i] [j] *= scalef;
  232. }
  233. }
  234. }
  235. }
  236. // update V
  237. matrixcopy_preallocated (vnew.get(), my data.get());
  238. NUMdmatrices_multiply_VC (my data.at, w.at, dimension, dimension, vnew.at, dimension);
  239. for (integer k = 1; k <= ccts -> size; k ++) {
  240. CrossCorrelationTable ct = ccts -> at [k];
  241. Melder_assert (ct -> data.nrow == dimension && ct -> data.ncol == dimension); // ppgb 20180913
  242. matrixcopy_preallocated (cc.get(), ct -> data.get());
  243. NUMdmatrices_multiply_VCVp (ct -> data.at, w.at, dimension, dimension, cc.at, true);
  244. }
  245. dm_new = CrossCorrelationTableList_getDiagonalityMeasure (ccts.get(), nullptr, 0, 0);
  246. iter ++;
  247. Melder_progress ((double) iter / (double) maxNumberOfIterations, U"Iteration: ", iter, U", measure: ", (double) dm_new, U"\n fractional measure: ", (double)(dm_new / dm_start));
  248. } while (fabs ((dm_old - dm_new) / dm_new) > delta && iter < maxNumberOfIterations);
  249. } catch (MelderError) {
  250. Melder_clearError ();
  251. }
  252. } catch (MelderError) {
  253. Melder_throw (me, U" & ", thee, U": no joint diagonalization (ffdiag).");
  254. }
  255. }
  256. /*
  257. The folowing two routines are modeled after qdiag.m from
  258. R. Vollgraf and K. Obermayer, Quadratic Optimization for Simultaneous
  259. Matrix Diagonalization, IEEE Transaction on Signal Processing, 2006,
  260. */
  261. static void update_one_column (CrossCorrelationTableList me, double **d, double *wp, double *wvec, double scalef, double *work) {
  262. integer dimension = my at [1] -> numberOfColumns;
  263. for (integer ic = 2; ic <= my size; ic ++) { // exclude C0
  264. SSCP cov = my at [ic];
  265. double **c = cov -> data.at;
  266. // m1 = C * wvec
  267. for (integer i = 1; i <= dimension; i ++) {
  268. double r = 0;
  269. for (integer j = 1; j <= dimension; j ++) {
  270. r += c [i] [j] * wvec [j];
  271. }
  272. work [i] = r;
  273. }
  274. // D = D +/- 2*p(t)*(m1*m1');
  275. for (integer i = 1; i <= dimension; i ++) {
  276. for (integer j = 1; j <= dimension; j ++) {
  277. d [i] [j] += 2 * scalef * wp [ic] * work [i] * work [j];
  278. }
  279. }
  280. }
  281. }
  282. static void Diagonalizer_CrossCorrelationTable_qdiag (Diagonalizer me, CrossCorrelationTableList thee, double *cweights, integer maxNumberOfIterations, double delta) {
  283. try {
  284. CrossCorrelationTable c0 = thy at [1];
  285. double **w = my data.at;
  286. integer dimension = c0 -> numberOfColumns;
  287. autoEigen eigen = Thing_new (Eigen);
  288. autoCrossCorrelationTableList ccts = Data_copy (thee);
  289. autoMAT d (dimension, dimension, kTensorInitializationType::RAW);
  290. autoNUMmatrix<double> pinv (1, dimension, 1, dimension);
  291. //autoNUMmatrix<double> d (1, dimension, 1, dimension);
  292. autoNUMmatrix<double> p (1, dimension, 1, dimension);
  293. autoNUMmatrix<double> m1 (1, dimension, 1, dimension);
  294. autoNUMmatrix<double> wc (1, dimension, 1, dimension);
  295. autoNUMvector<double> wvec (1, dimension);
  296. autoNUMvector<double> wnew (1, dimension);
  297. autoNUMvector<double> mvec (1, dimension);
  298. for (integer i = 1; i <= dimension; i ++) // Transpose W
  299. for (integer j = 1; j <= dimension; j ++) {
  300. wc [i] [j] = w [j] [i];
  301. }
  302. // d = diag(diag(W'*C0*W));
  303. // W = W*d^(-1/2);
  304. NUMdmatrix_normalizeColumnVectors (wc.peek(), dimension, dimension, c0 -> data.at);
  305. // scale eigenvectors for sphering
  306. // [vb,db] = eig(C0);
  307. // P = db^(-1/2)*vb';
  308. Eigen_initFromSymmetricMatrix (eigen.get(), c0 -> data.get());
  309. for (integer i = 1; i <= dimension; i ++) {
  310. Melder_require (eigen -> eigenvalues [i] >= 0.0, U"Covariance matrix should be positive definite. Eigenvalue [", i, U"] is negative.");
  311. double scalef = 1.0 / sqrt (eigen -> eigenvalues [i]);
  312. for (integer j = 1; j <= dimension; j ++) {
  313. p [dimension - i + 1] [j] = scalef * eigen -> eigenvectors [i] [j];
  314. }
  315. }
  316. // P*C [i]*P'
  317. for (integer ic = 1; ic <= thy size; ic ++) {
  318. CrossCorrelationTable cov1 = thy at [ic];
  319. CrossCorrelationTable cov2 = ccts -> at [ic];
  320. NUMdmatrices_multiply_VCVp (cov2 -> data.at, p.peek(), dimension, dimension, cov1 -> data.at, true);
  321. }
  322. // W = P'\W == inv(P') * W
  323. NUMpseudoInverse (p.peek(), dimension, dimension, pinv.peek(), 0);
  324. NUMdmatrices_multiply_VpC (w, pinv.peek(), dimension, dimension, wc.peek(), dimension);
  325. // initialisation for order KN^3
  326. for (integer ic = 2; ic <= thy size; ic ++) {
  327. CrossCorrelationTable cov = ccts -> at [ic];
  328. // C * W
  329. NUMdmatrices_multiply_VC (m1.peek(), cov -> data.at, dimension, dimension, w, dimension);
  330. // D += scalef * M1*M1'
  331. NUMdmatrices_multiplyScaleAdd (d.at, m1.peek(), dimension, dimension, 2 * cweights [ic]);
  332. }
  333. integer iter = 0;
  334. double delta_w;
  335. autoMelderProgress progress (U"Simultaneous diagonalization of many CrossCorrelationTables...");
  336. try {
  337. do {
  338. // the standard diagonality measure is rather expensive to calculate so we compare the norms of
  339. // differences of eigenvectors.
  340. delta_w = 0;
  341. for (integer kol = 1; kol <= dimension; kol ++) {
  342. for (integer i = 1; i <= dimension; i ++) {
  343. wvec [i] = w [i] [kol];
  344. }
  345. update_one_column (ccts.get(), d.at, cweights, wvec.peek(), -1, mvec.peek());
  346. Eigen_initFromSymmetricMatrix (eigen.get(), d.get());
  347. // Eigenvalues already sorted; get eigenvector of smallest !
  348. for (integer i = 1; i <= dimension; i ++) {
  349. wnew [i] = eigen -> eigenvectors [dimension] [i];
  350. }
  351. update_one_column (ccts.get(), d.at, cweights, wnew.peek(), 1, mvec.peek());
  352. for (integer i = 1; i <= dimension; i ++) {
  353. w [i] [kol] = wnew [i];
  354. }
  355. // compare norms of eigenvectors. We have to compare ||wvec +/- w_new|| because eigenvectors
  356. // may change sign.
  357. double normp = 0, normm = 0;
  358. for (integer j = 1; j <= dimension; j ++) {
  359. double dm = wvec [j] - wnew [j], dp = wvec [j] + wnew [j];
  360. normp += dm * dm;
  361. normm += dp * dp;
  362. }
  363. normp = normp < normm ? normp : normm;
  364. normp = sqrt (normp);
  365. delta_w = normp > delta_w ? normp : delta_w;
  366. }
  367. iter ++;
  368. Melder_progress ((double) iter / (double) (maxNumberOfIterations + 1), U"Iteration: ", iter, U", norm: ", delta_w);
  369. } while (delta_w > delta && iter < maxNumberOfIterations);
  370. } catch (MelderError) {
  371. Melder_clearError ();
  372. }
  373. // Revert the sphering W = P'*W;
  374. // Take transpose to make W*C [i]W' diagonal instead of W'*C [i]*W => (P'*W)'=W'*P
  375. NUMmatrix_copyElements (w, wc.peek(), 1, dimension, 1, dimension);
  376. NUMdmatrices_multiply_VpC (w, wc.peek(), dimension, dimension, p.peek(), dimension); // W = W'*P: final result
  377. // Calculate the "real" diagonality measure
  378. // double dm = CrossCorrelationTableList_Diagonalizer_getDiagonalityMeasure (thee, me, cweights, 1, thy size);
  379. } catch (MelderError) {
  380. Melder_throw (me, U" & ", thee, U": no joint diagonalization (qdiag).");
  381. }
  382. }
  383. void MixingMatrix_CrossCorrelationTableList_improveUnmixing (MixingMatrix me, CrossCorrelationTableList thee, integer maxNumberOfIterations, double tol, int method) {
  384. autoDiagonalizer him = MixingMatrix_to_Diagonalizer (me);
  385. Diagonalizer_CrossCorrelationTableList_improveDiagonality (him.get(), thee, maxNumberOfIterations, tol, method);
  386. NUMpseudoInverse (his data.at, his numberOfRows, his numberOfColumns, my data.at, 0);
  387. }
  388. /* Preconditions:
  389. * x [1..nrows] [1..ncols], cc [1..nrows] [1..nrows], centroid [1..nrows]
  390. * if (lag>0) {i2 + lag <= ncols} else {i1-lag >= 1}
  391. * no array boundary checks!
  392. * lag >= 0
  393. */
  394. static void NUMcrossCorrelate_rows (double **x, integer nrows, integer icol1, integer icol2, integer lag, double **cc, double *centroid, double scale) {
  395. lag = labs (lag);
  396. integer nsamples = icol2 - icol1 + 1 + lag;
  397. for (integer i = 1; i <= nrows; i ++) {
  398. double sum = 0.0;
  399. for (integer k = icol1; k <= icol2 + lag; k ++) {
  400. sum += x [i] [k];
  401. }
  402. centroid [i] = sum / nsamples;
  403. }
  404. for (integer i = 1; i <= nrows; i ++) {
  405. for (integer j = i; j <= nrows; j ++) {
  406. double ccor = 0;
  407. for (integer k = icol1; k <= icol2; k ++) {
  408. ccor += (x [i] [k] - centroid [i]) * (x [j] [k + lag] - centroid [j]);
  409. }
  410. cc [j] [i] = cc [i] [j] = ccor * scale;
  411. }
  412. }
  413. }
  414. /*
  415. This is for multi-channel "sounds" like EEG signals.
  416. The cross-correlation between channel i and channel j is defined as
  417. sum(k=1..nsamples, (z [i] [k] - mean [i])(z [j] [k + tau] - mean [j]))*samplingTime
  418. */
  419. autoCrossCorrelationTable Sound_to_CrossCorrelationTable (Sound me, double startTime, double endTime, double lagStep)
  420. {
  421. try {
  422. if (endTime <= startTime) {
  423. startTime = my xmin;
  424. endTime = my xmax;
  425. }
  426. integer lag = Melder_ifloor (lagStep / my dx); // ppgb: voor al dit soort dingen geldt: waarom afronden naar beneden?
  427. integer i1 = Sampled_xToNearestIndex (me, startTime);
  428. if (i1 < 1) {
  429. i1 = 1;
  430. }
  431. integer i2 = Sampled_xToNearestIndex (me, endTime);
  432. if (i2 > my nx) {
  433. i2 = my nx;
  434. }
  435. i2 -= lag;
  436. integer nsamples = i2 - i1 + 1;
  437. Melder_require (nsamples > my ny, U"Not enough samples, choose a longer interval.");
  438. autoCrossCorrelationTable thee = CrossCorrelationTable_create (my ny);
  439. NUMcrossCorrelate_rows (my z.at, my ny, i1, i2, lag, thy data.at, thy centroid.at, my dx);
  440. thy numberOfObservations = nsamples;
  441. return thee;
  442. } catch (MelderError) {
  443. Melder_throw (me, U": CrossCorrelationTable not created.");
  444. }
  445. }
  446. /* Calculate the CrossCorrelationTable between the channels of two multichannel sounds irrespective of the domains.
  447. * Both sounds are treated as if their domain runs from 0 to duration.
  448. * Outside the chosen interval the sounds are assumed to be zero
  449. */
  450. autoCrossCorrelationTable Sounds_to_CrossCorrelationTable_combined (Sound me, Sound thee,
  451. double relativeStartTime, double relativeEndTime, double lagStep)
  452. {
  453. try {
  454. Melder_require (my dx == thy dx, U"Sampling frequencies should be equal.");
  455. if (relativeEndTime <= relativeStartTime) {
  456. relativeStartTime = my xmin;
  457. relativeEndTime = my xmax;
  458. }
  459. integer ndelta = Melder_ifloor (lagStep / my dx), nchannels = my ny + thy ny;
  460. integer i1 = Sampled_xToNearestIndex (me, relativeStartTime);
  461. if (i1 < 1) {
  462. i1 = 1;
  463. }
  464. integer i2 = Sampled_xToNearestIndex (me, relativeEndTime);
  465. if (i2 > my nx) {
  466. i2 = my nx;
  467. }
  468. i2 -= ndelta;
  469. integer nsamples = i2 - i1 + 1;
  470. Melder_require (nsamples > nchannels, U"Not enough samples");
  471. autoCrossCorrelationTable him = CrossCorrelationTable_create (nchannels);
  472. autoNUMvector<double *> data (1, nchannels);
  473. for (integer i = 1; i <= my ny; i ++) {
  474. data [i] = my z [i];
  475. }
  476. for (integer i = 1; i <= thy ny; i ++) {
  477. data [i + my ny] = thy z [i];
  478. }
  479. NUMcrossCorrelate_rows (data.peek(), nchannels, i1, i2, ndelta, his data.at, his centroid.at, my dx);
  480. his numberOfObservations = nsamples;
  481. return him;
  482. } catch (MelderError) {
  483. Melder_throw (me, U": CrossCorrelationTable not created.");
  484. }
  485. }
  486. autoCovariance Sound_to_Covariance_channels (Sound me, double startTime, double endTime) {
  487. try {
  488. double lagStep = 0.0;
  489. autoCrossCorrelationTable thee = Sound_to_CrossCorrelationTable (me, startTime, endTime, lagStep);
  490. autoCovariance him = Thing_new (Covariance);
  491. thy structCrossCorrelationTable :: v_copy (him.get());
  492. return him;
  493. } catch (MelderError) {
  494. Melder_throw (me, U": no Covariance created.");
  495. }
  496. }
  497. autoCrossCorrelationTableList Sound_to_CrossCorrelationTableList (Sound me,
  498. double startTime, double endTime, integer numberOfCrossCorrelations, double lagStep)
  499. {
  500. try {
  501. if (lagStep < my dx) {
  502. lagStep = my dx;
  503. }
  504. if (endTime <= startTime) {
  505. startTime = my xmin;
  506. endTime = my xmax;
  507. }
  508. Melder_require (startTime + numberOfCrossCorrelations * lagStep <= endTime, U"Lag time is too large.");
  509. autoCrossCorrelationTableList thee = CrossCorrelationTableList_create ();
  510. for (integer i = 1; i <= numberOfCrossCorrelations; i ++) {
  511. double lag = (i - 1) * lagStep;
  512. autoCrossCorrelationTable ct = Sound_to_CrossCorrelationTable (me, startTime, endTime, lag);
  513. thy addItem_move (ct.move());
  514. }
  515. return thee;
  516. } catch (MelderError) {
  517. Melder_throw (me, U": no CrossCorrelationTableList created.");
  518. }
  519. }
  520. autoSound Sound_to_Sound_BSS (Sound me,
  521. double startTime, double endTime, integer numberOfCrossCorrelations, double lagStep,
  522. integer maxNumberOfIterations, double tol, int method)
  523. {
  524. try {
  525. autoMixingMatrix him = Sound_to_MixingMatrix (me,
  526. startTime, endTime, numberOfCrossCorrelations, lagStep,
  527. maxNumberOfIterations, tol, method);
  528. autoSound thee = Sound_MixingMatrix_unmix (me, him.get());
  529. return thee;
  530. } catch (MelderError) {
  531. Melder_throw (me, U": not separated.");
  532. }
  533. }
  534. /************************ Diagonalizer **********************************/
  535. Thing_implement (Diagonalizer, TableOfReal, 0);
  536. autoDiagonalizer Diagonalizer_create (integer dimension) {
  537. try {
  538. autoDiagonalizer me = Thing_new (Diagonalizer);
  539. TableOfReal_init (me.get(), dimension, dimension);
  540. for (integer i = 1; i <= dimension; i ++) {
  541. my data [i] [i] = 1.0;
  542. }
  543. return me;
  544. } catch (MelderError) {
  545. Melder_throw (U"Diagonalizer not created.");
  546. }
  547. }
  548. /***************** Diagonalizer & MixingMatrix *************************/
  549. autoDiagonalizer MixingMatrix_to_Diagonalizer (MixingMatrix me) {
  550. try {
  551. Melder_require (my numberOfRows == my numberOfColumns, U"The number of channels and the number of components should be equal.");
  552. autoDiagonalizer thee = Diagonalizer_create (my numberOfRows);
  553. NUMpseudoInverse (my data.at, my numberOfRows, my numberOfColumns, thy data.at, 0.0);
  554. return thee;
  555. } catch (MelderError) {
  556. Melder_throw (me, U": no Diagonalizer created.");
  557. }
  558. }
  559. autoMixingMatrix Diagonalizer_to_MixingMatrix (Diagonalizer me) {
  560. try {
  561. autoMixingMatrix thee = MixingMatrix_create (my numberOfRows, my numberOfColumns);
  562. MixingMatrix_setRandomGauss ( thee.get(), 0.0, 1.0);
  563. NUMpseudoInverse (my data.at, my numberOfRows, my numberOfColumns, thy data.at, 0.0);
  564. return thee;
  565. } catch (MelderError) {
  566. Melder_throw (me, U": no MixingMatrix created.");
  567. }
  568. }
  569. void MixingMatrix_Sound_improveUnmixing (MixingMatrix me, Sound thee,
  570. double startTime, double endTime, integer numberOfCrossCorrelations, double lagStep,
  571. integer maxNumberOfIterations, double tol, int method)
  572. {
  573. autoCrossCorrelationTableList ccs = Sound_to_CrossCorrelationTableList (thee, startTime, endTime, numberOfCrossCorrelations, lagStep);
  574. MixingMatrix_CrossCorrelationTableList_improveUnmixing (me, ccs.get(), maxNumberOfIterations, tol, method);
  575. }
  576. autoMixingMatrix Sound_to_MixingMatrix (Sound me,
  577. double startTime, double endTime, integer numberOfCrossCorrelations, double lagStep,
  578. integer maxNumberOfIterations, double tol, int method)
  579. {
  580. try {
  581. autoCrossCorrelationTableList ccs = Sound_to_CrossCorrelationTableList (me, startTime, endTime, numberOfCrossCorrelations, lagStep);
  582. autoMixingMatrix thee = MixingMatrix_create (my ny, my ny);
  583. MixingMatrix_setRandomGauss (thee.get(), 0.0, 1.0);
  584. MixingMatrix_CrossCorrelationTableList_improveUnmixing (thee.get(), ccs.get(), maxNumberOfIterations, tol, method);
  585. return thee;
  586. } catch (MelderError) {
  587. Melder_throw (me, U": no MixingMatrix created.");
  588. }
  589. }
  590. autoMixingMatrix TableOfReal_to_MixingMatrix (TableOfReal me) {
  591. try {
  592. Melder_require (my numberOfColumns == my numberOfRows, U"Number of rows and columns should be equal.");
  593. autoMixingMatrix thee = Thing_new (MixingMatrix);
  594. my structTableOfReal :: v_copy (thee.get());
  595. return thee;
  596. } catch (MelderError) {
  597. Melder_throw (me, U": not converted to MixingMatrix.");
  598. }
  599. }
  600. /************* CrossCorrelationTable *****************************/
  601. Thing_implement (CrossCorrelationTable, SSCP, 0);
  602. void structCrossCorrelationTable :: v_info () {
  603. structSSCP :: v_info ();
  604. double dm = CrossCorrelationTable_getDiagonalityMeasure (this);
  605. MelderInfo_writeLine (U"Diagonality measure: ", dm);
  606. }
  607. autoCrossCorrelationTable CrossCorrelationTable_create (integer dimension) {
  608. try {
  609. autoCrossCorrelationTable me = Thing_new (CrossCorrelationTable);
  610. SSCP_init (me.get(), dimension, dimension);
  611. return me;
  612. } catch (MelderError) {
  613. Melder_throw (U"CrossCorrelationTable not created.");
  614. }
  615. }
  616. autoCrossCorrelationTable CrossCorrelationTable_createSimple (conststring32 covars_string, conststring32 centroid_string, integer numberOfSamples) {
  617. try {
  618. autostring32vector covars = STRVECtokenize (covars_string);
  619. autostring32vector centroid = STRVECtokenize (centroid_string);
  620. integer dimension = centroid.size;
  621. integer ncovars = covars.size;
  622. integer ncovars_wanted = dimension * (dimension + 1) / 2;
  623. Melder_require (ncovars == ncovars_wanted, U"The number of matrix elements and the number of "
  624. U"centroid elements should agree. There should be \"d(d+1)/2\" matrix values and \"d\" centroid values.");
  625. autoCrossCorrelationTable me = CrossCorrelationTable_create (dimension);
  626. /*
  627. Construct the full matrix from the upper-diagonal elements
  628. */
  629. integer irow = 1;
  630. for (integer inum = 1; inum <= ncovars; inum ++) {
  631. double number;
  632. integer nmissing = (irow - 1) * irow / 2;
  633. integer inumc = inum + nmissing;
  634. irow = (inumc - 1) / dimension + 1;
  635. integer icol = (inumc - 1) % dimension + 1;
  636. Interpreter_numericExpression (nullptr, covars [inum].get(), & number);
  637. my data [irow] [icol] = my data [icol] [irow] = number;
  638. if (icol == dimension)
  639. irow ++;
  640. }
  641. for (integer inum = 1; inum <= dimension; inum ++) {
  642. double number;
  643. Interpreter_numericExpression (nullptr, centroid [inum].get(), & number);
  644. my centroid [inum] = number;
  645. }
  646. my numberOfObservations = numberOfSamples;
  647. return me;
  648. } catch (MelderError) {
  649. Melder_throw (U"CrossCorrelationTable not created.");
  650. }
  651. }
  652. double CrossCorrelationTable_getDiagonalityMeasure (CrossCorrelationTable me) {
  653. return NUMdmatrix_diagonalityMeasure (my data.at, my numberOfColumns);
  654. }
  655. /************* CrossCorrelationTables *****************************/
  656. void structCrossCorrelationTableList :: v_info () {
  657. our structThing :: v_info ();
  658. MelderInfo_writeLine (U"Contains ", our size, U" CrossCorrelationTable objects");
  659. CrossCorrelationTable thee = our at [1];
  660. MelderInfo_writeLine (U"Number of rows and columns: ", thy numberOfRows, U" in each CrossCorrelationTable");
  661. for (integer i = 1; i <= our size; i ++) {
  662. double dm = CrossCorrelationTable_getDiagonalityMeasure (our at [i]);
  663. MelderInfo_writeLine (U" Diagonality measure for item ", i, U": ", dm);
  664. }
  665. }
  666. autoCrossCorrelationTableList CrossCorrelationTables_to_CrossCorrelationTableList (OrderedOf<structCrossCorrelationTable> *me) {
  667. try {
  668. autoCrossCorrelationTableList thee = CrossCorrelationTableList_create ();
  669. integer numberOfRows = 0, numberOfColumns = 0, numberOfSelected = 0;
  670. for (integer i = 1; i <= my size; i ++) {
  671. CrossCorrelationTable item = my at [i];
  672. numberOfSelected ++;
  673. if (numberOfSelected == 1) {
  674. numberOfRows = item -> numberOfRows;
  675. numberOfColumns = item -> numberOfColumns;
  676. }
  677. Melder_require (item -> numberOfRows == numberOfRows && item -> numberOfColumns == numberOfColumns,
  678. U"Dimensions of table ", i, U" differs from the rest.");
  679. autoCrossCorrelationTable myc = Data_copy (item);
  680. thy addItem_move (myc.move());
  681. }
  682. return thee;
  683. } catch (MelderError) {
  684. Melder_throw (U"No CrossCorrelationTableList created from CrossCorrelationTable(s)");
  685. }
  686. }
  687. Thing_implement (CrossCorrelationTableList, SSCPList, 0);
  688. double CrossCorrelationTableList_getDiagonalityMeasure (CrossCorrelationTableList me, double *w, integer start, integer end) {
  689. if (start >= end) {
  690. start = 1;
  691. end = my size;
  692. }
  693. if (start < 1) {
  694. start = 1;
  695. }
  696. if (end > my size) {
  697. end = my size;
  698. }
  699. integer ntables = end - start + 1;
  700. integer dimension = my at [1] -> numberOfColumns;
  701. double dmsq = 0;
  702. for (integer k = start; k <= end; k ++) {
  703. CrossCorrelationTable thee = my at [k];
  704. double dmksq = NUMdmatrix_diagonalityMeasure (thy data.at, dimension);
  705. dmsq += (w ? dmksq * w [k] : dmksq / ntables);
  706. }
  707. return dmsq;
  708. }
  709. /************************** CrossCorrelationTables & Diagonalizer *******************************/
  710. double CrossCorrelationTableList_Diagonalizer_getDiagonalityMeasure (CrossCorrelationTableList me, Diagonalizer thee, double *w, integer start, integer end) {
  711. autoCrossCorrelationTableList him = CrossCorrelationTableList_Diagonalizer_diagonalize (me, thee);
  712. double dm = CrossCorrelationTableList_getDiagonalityMeasure (him.get(), w, start, end);
  713. return dm;
  714. }
  715. autoCrossCorrelationTable CrossCorrelationTable_Diagonalizer_diagonalize (CrossCorrelationTable me, Diagonalizer thee) {
  716. try {
  717. Melder_require (my numberOfRows == thy numberOfRows, U"The CrossCorrelationTable and the Diagonalizer matrix dimensions should be equal.");
  718. autoCrossCorrelationTable him = CrossCorrelationTable_create (my numberOfColumns);
  719. NUMdmatrices_multiply_VCVp (his data.at, thy data.at, my numberOfColumns, my numberOfColumns, my data.at, true);
  720. return him;
  721. } catch (MelderError) {
  722. Melder_throw (U"CrossCorrelationTable not diagonalized.");
  723. }
  724. }
  725. autoCrossCorrelationTableList CrossCorrelationTableList_Diagonalizer_diagonalize (CrossCorrelationTableList me, Diagonalizer thee) {
  726. try {
  727. autoCrossCorrelationTableList him = CrossCorrelationTableList_create ();
  728. for (integer i = 1; i <= my size; i ++) {
  729. CrossCorrelationTable item = my at [i];
  730. autoCrossCorrelationTable ct = CrossCorrelationTable_Diagonalizer_diagonalize (item, thee);
  731. his addItem_move (ct.move());
  732. }
  733. return him;
  734. } catch (MelderError) {
  735. Melder_throw (U"CrossCorrelationTableList not diagonalized.");
  736. }
  737. }
  738. autoDiagonalizer CrossCorrelationTableList_to_Diagonalizer (CrossCorrelationTableList me, integer maxNumberOfIterations, double tol, int method) {
  739. try {
  740. Melder_assert (my size > 0);
  741. CrossCorrelationTable him = my at [1];
  742. autoDiagonalizer thee = Diagonalizer_create (his numberOfColumns);
  743. Diagonalizer_CrossCorrelationTableList_improveDiagonality (thee.get(), me, maxNumberOfIterations, tol, method);
  744. return thee;
  745. } catch (MelderError) {
  746. Melder_throw (U"Diagonalizer not created from CrossCorrelationTableList.");
  747. };
  748. }
  749. void Diagonalizer_CrossCorrelationTableList_improveDiagonality (Diagonalizer me, CrossCorrelationTableList thee, integer maxNumberOfIterations, double tol, int method) {
  750. if (method == 1) {
  751. autoNUMvector<double> cweights (1, thy size);
  752. for (integer i = 1; i <= thy size; i ++) {
  753. cweights [i] = 1.0 / thy size;
  754. }
  755. Diagonalizer_CrossCorrelationTable_qdiag (me, thee, cweights.peek(), maxNumberOfIterations, tol);
  756. } else {
  757. Diagonalizer_CrossCorrelationTableList_ffdiag (me, thee, maxNumberOfIterations, tol);
  758. }
  759. }
  760. autoSound Sound_whitenChannels (Sound me, double varianceFraction) {
  761. try {
  762. autoCovariance cov = Sound_to_Covariance_channels (me, 0.0, 0.0);
  763. autoSound thee = Sound_Covariance_whitenChannels (me, cov.get(), varianceFraction);
  764. return thee;
  765. } catch (MelderError) {
  766. Melder_throw (me, U": not whitened.");
  767. }
  768. }
  769. autoSound Sound_Covariance_whitenChannels (Sound me, Covariance thee, double varianceFraction) {
  770. try {
  771. autoPCA pca = SSCP_to_PCA (thee);
  772. integer numberOfComponents = Eigen_getDimensionOfFraction (pca.get(), varianceFraction);
  773. autoSound him = Sound_PCA_whitenChannels (me, pca.get(), numberOfComponents);
  774. return him;
  775. } catch (MelderError) {
  776. Melder_throw (me, U": not whitened from ", thee);
  777. }
  778. }
  779. /*
  780. * Generate n different cct's that have a common diagonalizer.
  781. */
  782. autoCrossCorrelationTableList CrossCorrelationTableList_createTestSet (integer dimension, integer n, int firstPositiveDefinite, double sigma) {
  783. try {
  784. /*
  785. Start with a square matrix with random gaussian elements and make its singular value decomposition UDV'
  786. The V matrix will be the common diagonalizer matrix that we use.
  787. */
  788. autoMAT d = MATrandomGauss (dimension, dimension, 0.0, 1.0);
  789. autoMAT v = MATraw (dimension, dimension);
  790. autoSVD svd = SVD_createFromGeneralMatrix (d.get());
  791. autoCrossCorrelationTableList me = CrossCorrelationTableList_create ();
  792. for (integer i = 1; i <= dimension; i ++) {
  793. for (integer j = 1; j <= dimension; j ++) {
  794. d [i] [j] = 0.0;
  795. }
  796. }
  797. // Start with a diagonal matrix D and calculate V'DV
  798. for (integer k = 1; k <= n; k ++) {
  799. autoCrossCorrelationTable ct = CrossCorrelationTable_create (dimension);
  800. double low = (k == 1 && firstPositiveDefinite ? 0.1 : -1.0);
  801. for (integer i = 1; i <= dimension; i ++) {
  802. d [i] [i] = NUMrandomUniform (low, 1.0);
  803. }
  804. for (integer i = 1; i <= dimension; i ++) {
  805. for (integer j = 1; j <= dimension; j ++) {
  806. v [i] [j] = NUMrandomGauss (svd -> v [i] [j], sigma);
  807. }
  808. }
  809. // we need V'DV, however our V has eigenvectors row-wise -> VDV'
  810. NUMdmatrices_multiply_VCVp (ct -> data.at, v.at, dimension, dimension, d.at, true);
  811. my addItem_move (ct.move());
  812. }
  813. return me;
  814. } catch (MelderError) {
  815. Melder_throw (U"CrossCorrelationTableList test set not created.");
  816. }
  817. }
  818. #if 0
  819. static void Sound_MixingMatrix_improveUnmixing_fica (Sound me, MixingMatrix thee, integer maxNumberOfIterations, double /* tol */, int /* method */) {
  820. try {
  821. integer iter = 0;
  822. Melder_require (my ny == thy numberOfColumns, U"Dimensions should agree.");
  823. autoNUMmatrix<double> x (NUMmatrix_copy (my z, 1, my ny, 1, my nx), 1, 1);
  824. do {
  825. iter ++;
  826. } while (/*fabs((dm_old - dm_new) / dm_new) > tol &&*/ iter < maxNumberOfIterations);
  827. } catch (MelderError) {
  828. Melder_throw (me, U" & ", thee, U" .");
  829. }
  830. }
  831. #endif
  832. /* End of file ICA.cpp */