spm_dcm_KL.m 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. function [D,C,K] = spm_dcm_KL(M)
  2. % Computes the distance between two models based on prior responses
  3. % FORMAT [D,C,K] = spm_dcm_KL(Mi,Mj)
  4. %
  5. % M{1:n} - structure array of models
  6. %
  7. % D(n x n) - distance matrix (KL divergence)
  8. % C{1:n} - response covariances
  9. % K{1:n} - response means
  10. %__________________________________________________________________________
  11. % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging
  12. % Karl Friston
  13. % $Id: spm_dcm_KL.m 5219 2013-01-29 17:07:07Z spm $
  14. % Volterra kernels
  15. %==========================================================================
  16. % time bins (if not specified)
  17. %--------------------------------------------------------------------------
  18. try
  19. dt = M{1}.dt;
  20. N = M{1}.N;
  21. catch
  22. % Bilinear representation
  23. %----------------------------------------------------------------------
  24. M0 = spm_bireduce(M{1},P{1});
  25. s = real(eig(full(M0)));
  26. s = max(s(find(s < 0)));
  27. N = 32;
  28. dt = -4/(s*N);
  29. end
  30. % get covariances of prior responses
  31. %==========================================================================
  32. m = length(M);
  33. for i = 1:m
  34. % Get parameters (adding a little to prevent expansion around zero)
  35. %----------------------------------------------------------------------
  36. P = M{i}.pE;
  37. pC = M{i}.pC;
  38. P = spm_vec(P) + sqrt(diag(pC))/8;
  39. P = spm_unvec(P,M{i}.pE);
  40. % add a little to inputs (to prevent expansion around zero)
  41. %----------------------------------------------------------------------
  42. M{i}.u = ones(M{i}.m,1)/8;
  43. % get eigen-space of parameters for computational efficiency
  44. %----------------------------------------------------------------------
  45. V = spm_svd(pC);
  46. pC = V'*pC*V;
  47. % get derivative of kernels w.r.t. parameters
  48. %----------------------------------------------------------------------
  49. [dkdp,k] = spm_diff('spm_kernel',M{i},P,N,dt,2,{[],V});
  50. % prior mean and covariance of kernels
  51. %----------------------------------------------------------------------
  52. k = spm_vec(k);
  53. dk = sparse(length(k),length(dkdp));
  54. for j = 1:length(dkdp)
  55. dk(:,j) = spm_vec(dkdp{j});
  56. end
  57. K{i} = k;
  58. C{i} = dk*pC*dk';
  59. n(i) = length(pC);
  60. end
  61. % evaluate KL divergence
  62. %--------------------------------------------------------------------------
  63. for i = 1:m
  64. for j = 1:m
  65. Pi = spm_pinv(C{i});
  66. k = K{i} - K{j};
  67. d = spm_logdet(C{i}) - spm_logdet(C{j}) + ...
  68. trace(Pi*C{j}) + k'*Pi*k - n(i);
  69. D(i,j) = d/2;
  70. end
  71. end
  72. % ensure D is symmetric
  73. %--------------------------------------------------------------------------
  74. D = (D + D')/2;