function [D,C,K] = spm_dcm_KL(M) % Computes the distance between two models based on prior responses % FORMAT [D,C,K] = spm_dcm_KL(Mi,Mj) % % M{1:n} - structure array of models % % D(n x n) - distance matrix (KL divergence) % C{1:n} - response covariances % K{1:n} - response means %__________________________________________________________________________ % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging % Karl Friston % $Id: spm_dcm_KL.m 5219 2013-01-29 17:07:07Z spm $ % Volterra kernels %========================================================================== % time bins (if not specified) %-------------------------------------------------------------------------- try dt = M{1}.dt; N = M{1}.N; catch % Bilinear representation %---------------------------------------------------------------------- M0 = spm_bireduce(M{1},P{1}); s = real(eig(full(M0))); s = max(s(find(s < 0))); N = 32; dt = -4/(s*N); end % get covariances of prior responses %========================================================================== m = length(M); for i = 1:m % Get parameters (adding a little to prevent expansion around zero) %---------------------------------------------------------------------- P = M{i}.pE; pC = M{i}.pC; P = spm_vec(P) + sqrt(diag(pC))/8; P = spm_unvec(P,M{i}.pE); % add a little to inputs (to prevent expansion around zero) %---------------------------------------------------------------------- M{i}.u = ones(M{i}.m,1)/8; % get eigen-space of parameters for computational efficiency %---------------------------------------------------------------------- V = spm_svd(pC); pC = V'*pC*V; % get derivative of kernels w.r.t. parameters %---------------------------------------------------------------------- [dkdp,k] = spm_diff('spm_kernel',M{i},P,N,dt,2,{[],V}); % prior mean and covariance of kernels %---------------------------------------------------------------------- k = spm_vec(k); dk = sparse(length(k),length(dkdp)); for j = 1:length(dkdp) dk(:,j) = spm_vec(dkdp{j}); end K{i} = k; C{i} = dk*pC*dk'; n(i) = length(pC); end % evaluate KL divergence %-------------------------------------------------------------------------- for i = 1:m for j = 1:m Pi = spm_pinv(C{i}); k = K{i} - K{j}; d = spm_logdet(C{i}) - spm_logdet(C{j}) + ... trace(Pi*C{j}) + k'*Pi*k - n(i); D(i,j) = d/2; end end % ensure D is symmetric %-------------------------------------------------------------------------- D = (D + D')/2;