spm_mb_ui.m 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. function [MB] = spm_mb_ui(action,varargin)
  2. % VOI extraction of adjusted data and Markov Blanket decomposition
  3. % FORMAT [MB] = spm_mb_ui('specify',SPM)
  4. %
  5. % SPM - structure containing generic analysis details
  6. %
  7. % MB.contrast - contrast name
  8. % MB.name - MB name
  9. % MB.c - contrast weights
  10. % MB.X - contrast subspace
  11. % MB.Y - whitened and adjusted data
  12. % MB.X0 - null space of contrast
  13. %
  14. % MB.XYZ - locations of voxels (mm)
  15. % MB.xyz - seed voxel location (mm)
  16. % MB.VOX - dimension of voxels (mm)
  17. %
  18. % MB.V - canonical vectors (data)
  19. % MB.v - canonical variates (data)
  20. % MB.W - canonical vectors (design)
  21. % MB.w - canonical variates (design)
  22. % MB.C - canonical contrast (design)
  23. %
  24. % MB.chi - Chi-squared statistics testing D >= i
  25. % MB.df - d.f.
  26. % MB.p - p-values
  27. %
  28. % also saved in MB_*.mat in the SPM working directory
  29. %
  30. % FORMAT [MB] = spm_cva_ui('results',MB)
  31. % Display the results of a MB analysis
  32. %__________________________________________________________________________
  33. %
  34. % This routine uses the notion of Markov blankets and the renormalisation
  35. % group to evaluate the coupling among neuronal systems at increasing
  36. % spatial scales. The underlying generative model is based upon the
  37. % renormalisation group: a working definition of renormalization involves
  38. % three elements: vectors of random variables, a course-graining operation
  39. % and a requirement that the operation does not change the functional form
  40. % of the Lagrangian. In our case, the random variables are neuronal states;
  41. % the course graining operation corresponds to the grouping (G) into a
  42. % particular partition and adiabatic reduction (R) - that leaves the
  43. % functional form of the dynamics unchanged.
  44. %
  45. % Here, the grouping operator (G) is based upon coupling among states as
  46. % measured by the Jacobian. In brief, the sparsity structure of the
  47. % Jacobian is used to recursively identify Markov blankets around internal
  48. % states to create a partition of states - at any level - into particles;
  49. % where each particle comprises external and blanket states. The ensuing
  50. % reduction operator (R) eliminates the internal states and retains the slow
  51. % eigenmodes of the blanket states. These then constitute the (vector)
  52. % states at the next level and the process begins again.
  53. %
  54. % This routine starts using a simple form of dynamic causal modelling
  55. % applied to the principal eigenvariate of local parcels (i.e., particles)
  56. % of voxels with compact support. The Jacobian is estimated using a
  57. % linearised dynamic causal (state space) model, where observations are
  58. % generated by applying a (e.g., haemodynamic) convolution operator to
  59. % hidden (e.g., neuronal) states. This estimation uses parametric empirical
  60. % Bayes (PEB: spm_PEB). The ensuing estimates of the Jacobian (i.e.,
  61. % effective connectivity) are reduced using Bayesian model reduction (BMR:
  62. % spm_dcm_BMR_all) within a bespoke routine (spm_dcm_J).
  63. %
  64. % The Jacobian is then partitioned using the course graining operator into
  65. % particles or parcels (using spm_markov blanket). The resulting partition
  66. % is then reduced by eliminating internal states and retaining slow
  67. % eigenmodes with the largest (real) eigenvalues (spm_A_reduce). The
  68. % Jacobian of the reduced states is then used to repeat the process -
  69. % recording the locations of recursively coarse-grained particles - until
  70. % there is a single particle.
  71. %
  72. % The result of this recursive decomposition (i.e., renormalisation)
  73. % affords a characterisation of directed coupling, as characterised by a
  74. % complex Jacobian; namely, a multivariate coupling matrix, describing the
  75. % coupling between eigenmodes of Markov blankets at successive scales. This
  76. % can be regarded as a recursive parcellation scheme based upon effective
  77. % connectivity and a generative (dynamic causal) model of multivariate
  78. % (neuronal) timeseries.
  79. %
  80. %__________________________________________________________________________
  81. % Copyright (C) 2008-2014 Wellcome Trust Centre for Neuroimaging
  82. % Karl Friston
  83. % $Id: spm_mb_ui.m 7679 2019-10-24 15:54:07Z spm $
  84. OPT.d = 48; % maximum connection length (mm)
  85. OPT.np = 512; % number of parcels (particles)
  86. OPT.xyz = [0;0;0]; % centre of (spherical) VOI (mm)
  87. OPT.spec = 128; % radius of (spherical) VOI (mm)
  88. OPT.Ic = 1; % contrast (for adjusted data)
  89. OPT.T = 1; % threshold for adiabatic reduction
  90. OPT.N = 8; % max modes for adiabatic reduction
  91. switch lower(action)
  92. case 'specify'
  93. %==================================================================
  94. % M B : S P E C I F Y
  95. %==================================================================
  96. if isempty(varargin)
  97. [SPM,sts] = spm_select(1,'mat','Select SPM',[],[],'^SPM.*\.mat$');
  98. if ~sts, return; end
  99. else
  100. SPM = varargin{1};
  101. end
  102. if ischar(SPM)
  103. SPM = load(SPM);
  104. SPM = SPM.SPM;
  105. end
  106. %-Contrast specification
  107. %------------------------------------------------------------------
  108. con = SPM.xCon(OPT.Ic).name;
  109. c = SPM.xCon(OPT.Ic).c;
  110. c = full(c);
  111. %-Specify search volume
  112. %------------------------------------------------------------------
  113. xY.def = 'sphere';
  114. xY.xyz = OPT.xyz;
  115. xY.spec = OPT.spec;
  116. Q = ones(1,size(SPM.xVol.XYZ,2));
  117. XYZmm = SPM.xVol.M(1:3,:)*[SPM.xVol.XYZ; Q];
  118. [xY,XYZ,j] = spm_ROI(xY,XYZmm);
  119. %-Extract required data from results files
  120. %==================================================================
  121. spm('Pointer','Watch')
  122. %-Get explanatory variables (data)
  123. %------------------------------------------------------------------
  124. Y = spm_get_data(SPM.xY.VY,SPM.xVol.XYZ(:,j));
  125. if isempty(Y)
  126. spm('alert*',{'No voxels in this VOI';'Please use a larger volume'},...
  127. 'Markov Blanket analysis');
  128. return
  129. end
  130. %-Remove serial correlations and get design (note X := W*X)
  131. %------------------------------------------------------------------
  132. Y = SPM.xX.W*Y;
  133. X = SPM.xX.xKXs.X;
  134. M = SPM.xVol.M(1:3,1:3); %-voxels to mm matrix
  135. VOX = diag(sqrt(diag(M'*M))'); %-voxel size
  136. %-Null-space
  137. %------------------------------------------------------------------
  138. X0 = [];
  139. try X0 = [X0 blkdiag(SPM.xX.K.X0)]; end %-drift terms
  140. try X0 = [X0 spm_detrend(SPM.xGX.gSF)]; end %-global estimate
  141. % exogenous inputs (decimated)
  142. %------------------------------------------------------------------
  143. for i = 1:numel(SPM.Sess.U)
  144. U(:,i) = SPM.Sess.U(i).u(33:end,:);
  145. end
  146. Dy = spm_dctmtx(size(Y,1),size(Y,1));
  147. Du = spm_dctmtx(size(U,1),size(Y,1));
  148. Dy = Dy*sqrt(size(Y,1)/size(U,1));
  149. U = Dy*(Du'*U);
  150. %-First level partition: compact support
  151. %==================================================================
  152. X0 = [X0, (X - X*c*pinv(c))];
  153. V = spm_mvb_U(Y,'compact',spm_svd(X0),XYZ,[],OPT.np);
  154. Y = Y*V;
  155. [nt,nv] = size(Y);
  156. % distance priors (plausible connections: R(i,j) = 1)
  157. %------------------------------------------------------------------
  158. R = zeros(nv,nv);
  159. D = abs(V);
  160. D = bsxfun(@rdivide,D,sum(D));
  161. xyz = XYZ*D;
  162. for i = 1:nv
  163. for j = i:nv
  164. d = xyz(:,i) - xyz(:,j);
  165. if sqrt(d'*d) < OPT.d
  166. R(i,j) = 1;
  167. R(j,i) = 1;
  168. end
  169. end
  170. end
  171. % first order Jacobian
  172. %==================================================================
  173. J = spm_dcm_J(Y,U,X0,SPM.xY.RT,R);
  174. % hierarchal decomposition
  175. %==================================================================
  176. clear MB
  177. %-Assemble results
  178. %------------------------------------------------------------------
  179. MB{1}.con = con; %-contrast name
  180. MB{1}.XYZ = XYZ; %-locations of voxels (mm)
  181. MB{1}.VOX = VOX; %-dimension of voxels (mm)
  182. N = 4; % maximum number of scales
  183. m = [1 1 1 1]; % # internal states
  184. MB{1}.J = J; % Jacobian
  185. MB{1}.z = num2cell(1:nv); % indices of states
  186. MB{1}.s = num2cell(diag(J)); % Lyapunov exponents
  187. MB{1}.U = U; % exogenous inputs
  188. MB{1}.V = V; % support in voxel space
  189. MB{1}.Y = Y; % time-series
  190. %% renormalization
  191. %------------------------------------------------------------------
  192. for i = 1:N
  193. % Markov blanket (particular) partition
  194. %--------------------------------------------------------------
  195. spm_figure('getwin',sprintf('Markov level %i',i)); clf;
  196. MB{i}.m = m(i);
  197. MB{i}.x = spm_Markov_blanket(MB{i}.J,MB{i}.z,m(i));
  198. % dimension reduction (eliminating internal states)
  199. %--------------------------------------------------------------
  200. [J,z,v,s] = spm_A_reduce(MB{i}.J,MB{i}.x,OPT.T,OPT.N);
  201. MB{i + 1}.J = J;
  202. MB{i + 1}.z = z;
  203. MB{i + 1}.s = s;
  204. % eigenmodes and variates (V and Y)
  205. %--------------------------------------------------------------
  206. for j = 1:size(MB{i}.x,2)
  207. u = [MB{i}.x{1:2,j}]; % blanket states
  208. w = MB{i + 1}.z{j}; % new states
  209. MB{i + 1}.V(:,w) = MB{i}.V(:,u)*v{j};
  210. MB{i + 1}.Y(:,w) = MB{i}.Y(:,u)*v{j};
  211. end
  212. % functional anatomy of states
  213. %--------------------------------------------------------------
  214. spm_mb_anatomy(MB{i},XYZ,VOX,7);
  215. % break if a single particle or parcel
  216. %--------------------------------------------------------------
  217. if i > N || size(MB{i}.x,2) < 2
  218. break
  219. end
  220. end
  221. %% Save results
  222. %==================================================================
  223. %-Save
  224. %------------------------------------------------------------------
  225. save(fullfile(SPM.swd,['MB_' con]),'MB');
  226. case 'results'
  227. %==================================================================
  228. % M B : R E S U L T S
  229. %==================================================================
  230. %-Get MB and ananlysis
  231. %------------------------------------------------------------------
  232. MB = varargin{1};
  233. analysis = varargin{2};
  234. if ischar(MB)
  235. MB = load(MB);
  236. MB = MB.MB;
  237. end
  238. switch analysis
  239. case('anatomy')
  240. % functional anatomy
  241. %--------------------------------------------------------------
  242. VOX = MB{1}.VOX;
  243. XYZ = MB{1}.XYZ;
  244. for i = 1:(numel(MB) - 1)
  245. spm_figure('getwin',sprintf('Markov level %i',i)); clf;
  246. spm_mb_anatomy(MB{i},XYZ,VOX)
  247. end
  248. case('distance')
  249. % spatial distance and (first-level) coupling
  250. %--------------------------------------------------------------
  251. spm_figure('getwin','Distance rules'); clf;
  252. J = MB{1}.J;
  253. nv = length(J);
  254. D = abs(MB{1}.V);
  255. D = bsxfun(@rdivide,D,sum(D));
  256. xyz = MB{1}.XYZ*D;
  257. D = [];
  258. E = [];
  259. for i = 1:nv
  260. for j = 1:nv
  261. d = xyz(:,i) - xyz(:,j);
  262. d = sqrt(d'*d);
  263. if abs(J(i,j)) > exp(-16) && d
  264. D(end + 1,1) = sqrt(d'*d);
  265. E(end + 1,1) = J(i,j);
  266. end
  267. end
  268. end
  269. % regression
  270. %----------------------------------------------------------
  271. [D,i] = sort(D,'ascend');
  272. D = D - D(1);
  273. E = E(i);
  274. r = find(E < 0);
  275. g = find(E > 0);
  276. [Fr,dfr,Br] = spm_ancova([ones(size(r)) D(r)],[],log(-E(r)));
  277. [Fg,dfg,Bg] = spm_ancova([ones(size(g)) D(g)],[],log( E(g)));
  278. subplot(2,2,1)
  279. hold off, plot(D(r),E(r),'.r',D(g),E(g),'.g','MarkerSize',1)
  280. hold on, plot(D(r),-exp(Br(1))*exp(Br(2)*D(r)),'r','LineWidth',2)
  281. hold on, plot(D(g), exp(Bg(1))*exp(Bg(2)*D(g)),'g','LineWidth',2)
  282. title('Eponential distance rule','FontSize',16)
  283. xlabel('Distance (mm)'), ylabel('coupling strength (Hz}')
  284. axis square, box off, set(gca,'YLim',[-.4,.4])
  285. subplot(2,2,2)
  286. hold off, plot(D(r),log(-E(r)),'.r',D(g),log(E(g)),'.g','MarkerSize',1)
  287. hold on, plot(D(r),Br(1) + Br(2)*D(r),'r','LineWidth',2)
  288. hold on, plot(D(g),Bg(1) + Bg(2)*D(g),'g','LineWidth',2)
  289. title('Log coupling','FontSize',16)
  290. xlabel('Distance (mm)'), ylabel('log coupling')
  291. axis square, box off, set(gca,'YLim',[-16,0])
  292. % assymetry
  293. %----------------------------------------------------------
  294. D = [];
  295. E = [];
  296. for i = 1:nv
  297. for j = 1:nv
  298. if abs(J(i,j)) > exp(-8) && j ~= i
  299. D(end + 1,1) = J(j,i);
  300. E(end + 1,1) = J(i,j);
  301. end
  302. end
  303. end
  304. subplot(2,1,2)
  305. hold off, plot(E,D,'.r','MarkerSize',1)
  306. title('reciprocal coupling','FontSize',16)
  307. xlabel('coupling (Hz)'), ylabel('coupling (Hz)')
  308. axis square, box off, axis([-1 1 -1 1]/2)
  309. case('scaling')
  310. % time constants over scales
  311. %----------------------------------------------------------
  312. spm_figure('getwin','Scaling'); clf;
  313. N = min(3,numel(MB));
  314. SR = cell(N,1);
  315. SI = cell(N,1);
  316. for i = 1:N
  317. for j = 1:numel(MB{i}.s)
  318. SR{i} = [SR{i}; real(MB{i}.s{j})];
  319. SI{i} = [SI{i}; imag(MB{i}.s{j})];
  320. end
  321. end
  322. subplot(2,1,1), hold off
  323. col = spm_MB_col(N);
  324. s = linspace(-1,1/16,16);
  325. for i = 1:N
  326. [n,s] = hist(SR{i},s);
  327. n = n/sum(n);
  328. m(i) = mean(1./SR{i});
  329. plot(s,n,'color',col{i},'LineWidth',2), hold on
  330. end
  331. legend({'scale 1','scale 2','scale 3'})
  332. title('Temporal scaling','FontSize',16)
  333. xlabel('eigenvalue (Hz)'), ylabel('Frequency')
  334. axis square, box off
  335. subplot(2,1,2)
  336. bar(-1:numel(m),[0 0 -m])
  337. title('Average time constants','FontSize',16)
  338. xlabel('scale'), ylabel('Seconds')
  339. axis square, box off
  340. case('kernels')
  341. % time constants over scales
  342. %----------------------------------------------------------
  343. spm_figure('getwin','Transfer functions'); clf;
  344. col = spm_MB_col(128);
  345. for i = 2:min(3,numel(MB))
  346. % first particle
  347. %------------------------------------------------------
  348. for p = 1:numel(MB{i}.z)
  349. if numel(MB{i}.z{p}) > 4
  350. j = MB{i}.z{p};
  351. j = j(real(MB{i}.s{p}) < 0);
  352. J = MB{i}.J(j,j);
  353. n = length(J);
  354. % Bilinear operator - M0
  355. %----------------------------------------------
  356. M0 = spm_cat({0 [];
  357. [] J});
  358. % Bilinear operator - M1 = dM0/du
  359. %----------------------------------------------
  360. M1{1} = spm_cat({0, [];
  361. ones(n,1), spm_zeros(J)});
  362. % kernels
  363. %----------------------------------------------
  364. N = 4096;
  365. dt = 1/8;
  366. [K0,K1] = spm_kernels(M0,M1,N,dt);
  367. % Transfer functions (FFT of kernel)
  368. %----------------------------------------------
  369. S1 = fft(K1)*dt;
  370. w = ((1:N) - 1)/(N*dt);
  371. j = find(w < 1/4);
  372. subplot(2,2,i - 1), hold on
  373. plot(w(j),abs(S1(j,:,1)),'color',col{p})
  374. title(sprintf('Scale %i',i),'fontsize',16)
  375. xlabel('frequency (Hz)'), ylabel('transfer tunctions')
  376. axis square, box off
  377. if any(imag(MB{i}.s{p}))
  378. subplot(2,2,i + 1), hold on
  379. plot(MB{i}.s{p},'.','MarkerSize',32,'color',col{p})
  380. title('Eigenvalues','fontsize',16)
  381. xlabel('real (Hz)'), ylabel('imaginary (Hz)')
  382. axis square, box off, axis([-1 1 -1/4 1/4])
  383. end
  384. end
  385. end
  386. end
  387. otherwise
  388. error('Unknown action.');
  389. end
  390. otherwise
  391. error('Unknown action.');
  392. end
  393. %% subroutines
  394. %==========================================================================
  395. % functional anatomy
  396. %==========================================================================
  397. function spm_mb_anatomy(MB,XYZ,VOX,N)
  398. %__________________________________________________________________________
  399. % set-up
  400. %--------------------------------------------------------------------------
  401. if nargin < 4, N = 11; end
  402. nz = numel(MB.z); % number of states
  403. nn = min(size(MB.x,2),N); % number of particles
  404. col = spm_MB_col(nz); % colours
  405. % functional anatomy of states
  406. %--------------------------------------------------------------------------
  407. subplot(3,4,1),cla,hold off
  408. c = var(real(MB.Y));
  409. spm_mip(logical(abs(MB.V))*c',XYZ,VOX);
  410. axis image, axis off
  411. title(sprintf('%i (vector) states',nz),'FontSize',16)
  412. % functional anatomy of particles
  413. %--------------------------------------------------------------------------
  414. for j = 1:nn
  415. Z = any(MB.V(:,MB.x{1,j}),2)*4; % active states
  416. Z = any(MB.V(:,MB.x{2,j}),2)*4 + Z; % sensory states
  417. Z = any(MB.V(:,MB.x{3,j}),2)*1 + Z; % internal states
  418. subplot(3,4,j + 1)
  419. Z(1) = 4;
  420. mip = spm_mip(Z,XYZ,VOX);
  421. for k = 1:3
  422. c = col{j}(k)/2;
  423. MIP(:,:,k) = (1 - mip/64)*(1 - c) + c;
  424. end
  425. image(MIP), axis image, axis off
  426. title(sprintf('Particle %i',j),'FontSize',16)
  427. end