spm_SpUtil.m 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. function varargout = spm_SpUtil(varargin)
  2. % Space matrix utilities
  3. % FORMAT varargout = spm_SpUtil(action,varargin)
  4. %
  5. %_______________________________________________________________________
  6. %
  7. % spm_SpUtil is a multi-function function containing various utilities
  8. % for Design matrix and contrast construction and manipulation. In
  9. % general, it accepts design matrices as plain matrices or as space
  10. % structures setup by spm_sp.
  11. %
  12. % Many of the space utilities are computed using an SVD of the design
  13. % matrix. The advantage of using space structures is that the svd of
  14. % the design matrix is stored in the space structure, thereby saving
  15. % unnecessary repeated computation of the SVD. This presents a
  16. % considerable efficiency gain for large design matrices.
  17. %
  18. % Note that when space structures are passed as arguments is is
  19. % assummed that their basic fields are filled in. See spm_sp for
  20. % details of (design) space structures and their manipulation.
  21. %
  22. % Quick Reference :
  23. %---------------------
  24. % ('isCon',x,c) :
  25. % ('allCon',x,c) :
  26. % ('ConR',x,c) :
  27. % ('ConO',x,c) :
  28. % ('size',x,dim) :
  29. % ('iX0check',i0,sL) :
  30. %---------------------
  31. % ('i0->c',x,i0) : Out : c
  32. % ('c->Tsp',x,c) : Out : [X1o [X0]]
  33. % ('+c->Tsp',x,c) : Out : [ukX1o [ukX0]]
  34. % ('i0->x1o',x,i0) : Use ('i0->c',x,i0) and ('c->Tsp',X,c)
  35. % ('+i0->x1o',x,i0) : Use ('i0->c',x,i0) and ('+c->Tsp',X,c)
  36. % ('X0->c',x,X0) :~
  37. % ('+X0->c',x,cukX0) :~
  38. %---------------------
  39. % ('trRV',x[,V]) :
  40. % ('trMV',x[,V]) :
  41. % ('i0->edf',x,i0,V) :
  42. %
  43. %---------------------
  44. %
  45. % Improvement compared to the spm99 beta version :
  46. %
  47. % Improvements in df computation using spm_SpUtil('trRV',x[,V]) and
  48. % spm_SpUtil('trMV',sX [,V]). The degrees of freedom computation requires
  49. % in general that the trace of RV and of RVRV be computed, where R is a
  50. % projector onto either a sub space of the design space or the residual
  51. % space, namely the space that is orthogonal to the design space. V is
  52. % the (estimated or assumed) variance covariance matrix and is a number
  53. % of scans by number of scans matrix which can be huge in some cases. We
  54. % have (thanks to S Rouquette and JB) speed up this computation
  55. % by using matlab built in functions of the frobenius norm and some theorems
  56. % on trace computations.
  57. %
  58. % ======================================================================
  59. %
  60. % FORMAT i = spm_SpUtil('isCon',x,c)
  61. % Tests whether weight vectors specify contrasts
  62. % x - Design matrix X, or space structure of X
  63. % c - contrast matrix (I.e. matrix of contrast weights, contrasts in columns)
  64. % Must have column dimension matching that of X
  65. % [defaults to eye(size(X,2)) to test uniqueness of parameter estimates]
  66. % i - logical row vector indiciating estimability of contrasts in c
  67. %
  68. % A linear combination of the parameter estimates is a contrast if and
  69. % only if the weight vector is in the space spanned by the rows of X.
  70. %
  71. % The algorithm works by regressing the contrast weight vectors using
  72. % design matrix X' (X transposed). Any contrast weight vectors will be
  73. % fitted exactly by this procedure, leaving zero residual. Parameter
  74. % tol is the tolerance applied when searching for zero residuals.
  75. %
  76. % Christensen R (1996)
  77. % "Plane Answers to Complex Questions"
  78. % 2nd Ed. Springer-Verlag, New York
  79. %
  80. % Andrade A, Paradis AL, Rouquette S and Poline JB, NeuroImage 9, 1999
  81. % ----------------
  82. %
  83. % FORMAT i = spm_SpUtil('allCon',x,c)
  84. % Tests whether all weight vectors specify contrasts:
  85. % Same as all(spm_SpUtil('isCon',x,c)).
  86. %
  87. % ----------------
  88. %
  89. % FORMAT r = spm_SpUtil('ConR',x,c)
  90. % Assess orthogonality of contrasts (wirit the data)
  91. % x - Design matrix X, or space structure of X
  92. % c - contrast matrix (I.e. matrix of contrast weights, contrasts in columns)
  93. % Must have column dimension matching that of X
  94. % defaults to eye(size(X,2)) to test independence of parameter estimates
  95. % r - Contrast correlation matrix, of dimension the number of contrasts.
  96. %
  97. % For the general linear model Y = X*B + E, a contrast weight vector c
  98. % defines a contrast c*B. This is estimated by c*b, where b are the
  99. % least squares estimates of B given by b=pinv(X)*Y. Thus, c*b = w*Y,
  100. % where weight vector w is given by w=c*pinv(X); Since the data are
  101. % assummed independent, two contrasts are indpendent if the
  102. % corresponding weight vectors are orthogonal.
  103. %
  104. % r is the matrix of normalised inner products between the weight
  105. % vectors corresponding to the contrasts. For iid E, r is the
  106. % correlation matrix of the contrasts.
  107. %
  108. % The logical matrix ~r will be true for orthogonal pairs of contrasts.
  109. %
  110. % ----------------
  111. %
  112. % FORMAT r = spm_SpUtil('ConO',x,c)
  113. % Assess orthogonality of contrasts (wirit the data)
  114. % x - Design matrix X, or space structure of X
  115. % c - contrast matrix (I.e. matrix of contrast weights, contrasts in columns)
  116. % Must have column dimension matching that of X
  117. % [defaults to eye(size(X,2)) to test uniqueness of parameter estimates]
  118. % r - Contrast orthogonality matrix, of dimension the number of contrasts.
  119. %
  120. % This is the same as ~spm_SpUtil('ConR',X,c), but uses a quicker
  121. % algorithm by looking at the orthogonality of the subspaces of the
  122. % design space which are implied by the contrasts:
  123. % r = abs(c*X'*X*c')<tol
  124. %
  125. % ----------------
  126. %
  127. % FORMAT c = spm_SpUtil('i0->c',x,i0)
  128. % Return F-contrast for specified design matrix partition
  129. % x - Design matrix X, or space structure of X
  130. % i0 - column indices of null hypothesis design matrix
  131. %
  132. % This functionality returns a rank n mxp matrix of contrasts suitable
  133. % for an extra-sum-of-squares F-test comparing the design X, with a
  134. % reduced design. The design matrix for the reduced design is X0 =
  135. % X(:,i0), a reduction of n degrees of freedom.
  136. %
  137. % The algorithm, due to J-B, and derived from Christensen, computes the
  138. % contrasts as an orthonormal basis set for the rows of the
  139. % hypothesised redundant columns of the design matrix, after
  140. % orthogonalisation with respect to X0. For non-unique designs, there
  141. % are a variety of ways to produce equivalent F-contrasts. This method
  142. % produces contrasts with non-zero weights only for the hypothesised
  143. % redundant columns.
  144. %
  145. % ----------------
  146. %
  147. % case {'x0->c'} %-
  148. % FORMAT c = spm_SpUtil('X0->c',sX,X0)
  149. % ----------------
  150. %
  151. % FORMAT [X1,X0] = spm_SpUtil('c->TSp',X,c)
  152. % Orthogonalised partitioning of design space implied by F-contrast
  153. % x - Design matrix X, or space structure of X
  154. % c - contrast matrix (I.e. matrix of contrast weights, contrasts in columns)
  155. % Must have column dimension matching that of X
  156. % X1o - contrast space - design matrix corresponding according to contrast
  157. % (orthogonalised wirit X0)
  158. % X0 - matrix reduced according to null hypothesis
  159. % (of same size as X but rank deficient)
  160. % FORMAT [uX1,uX0] = spm_SpUtil('c->TSp+',X,c)
  161. % + version to deal with the X1o and X0 partitions in the "uk basis"
  162. %
  163. % ( Note that unless X0 is reduced to a set of linearely independant )
  164. % ( vectors, c will only be contained in the null space of X0. If X0 )
  165. % ( is "reduced", then the "parent" space of c must be reduced as well )
  166. % ( for c to be the actual null space of X0. )
  167. %
  168. % This functionality returns a design matrix subpartition whose columns
  169. % span the hypothesised null design space of a given contrast. Note
  170. % that X1 is orthogonal(ised) to X0, reflecting the situation when an
  171. % F-contrast is tested using the extra sum-of-squares principle (when
  172. % the extra distance in the hypothesised null space is measured
  173. % orthogonal to the space of X0).
  174. %
  175. % Note that the null space design matrix will probably not be a simple
  176. % sub-partition of the full design matrix, although the space spanned
  177. % will be the same.
  178. %
  179. % ----------------
  180. %
  181. % FORMAT X1 = spm_SpUtil('i0->x1o',X,i0)
  182. % x - Design matrix X, or space structure of X
  183. % i0 - Columns of X that make up X0 - the reduced model (Ho:B1=0)
  184. % X1 - Hypothesised null design space, i.e. that part of X orthogonal to X0
  185. % This offers the same functionality as the 'c->TSp' option, but for
  186. % simple reduced models formed from the columns of X.
  187. %
  188. % FORMAT X1 = spm_SpUtil('i0->x1o+',X,i0)
  189. % + version to deal with the X1o and X0 partitions in the "uk basis"
  190. %
  191. % ----------------
  192. %
  193. % FORMAT [trRV,trRVRV] = spm_SpUtil('trRV',x[,V])
  194. % trace(RV) & trace(RVRV) - used in df calculation
  195. % x - Design matrix X, or space structure of X
  196. % V - V matrix [defult eye] (trRV == trRVRV if V==eye, since R idempotent)
  197. % trRV - trace(R*V), computed efficiently
  198. % trRVRV - trace(R*V*R*V), computed efficiently
  199. % This uses the Karl's cunning understanding of the trace:
  200. % (tr(A*B) = sum(sum(A'*B)).
  201. % If the space of X is set, then algorithm uses x.u to avoid extra computation.
  202. %
  203. % ----------------
  204. %
  205. % FORMAT [trMV, trMVMV]] = spm_SpUtil('trMV',x[,V])
  206. % trace(MV) & trace(MVMV) if two ouput arguments.
  207. % x - Design matrix X, or space structure of X
  208. % V - V matrix [defult eye] (trMV == trMVMV if V==eye, since M idempotent)
  209. % trMV - trace(M*V), computed efficiently
  210. % trMVMV - trace(M*V*M*V), computed efficiently
  211. % Again, this uses the Karl's cunning understanding of the trace:
  212. % (tr(A*B) = sum(sum(A'.*B)).
  213. % If the space of X is set, then algorithm uses x.u to avoid extra computation.
  214. %
  215. % ----------------
  216. %
  217. % OBSOLETE use FcUtil('H') for spm_SpUtil('c->H',x,c)
  218. % Extra sum of squares matrix O for beta's from contrast
  219. % x - Design matrix X, or space structure of X
  220. % c - contrast matrix (I.e. matrix of contrast weights, contrasts in columns)
  221. % Must have column dimension matching that of X
  222. % O - Matrix such that b'*O*b = extra sum of squares for F-test of contrast c
  223. %
  224. % ----------------
  225. %
  226. % OBSOLETE use spm_sp('=='...) for spm_SpUtil('c==X1o',x,c) {or 'cxpequi'}
  227. % x - Design matrix X, or space structure of X
  228. % c - contrast matrix (I.e. matrix of contrast weights, contrasts in columns)
  229. % Must have column dimension matching that of X
  230. % b - True is c is a spanning set for space of X
  231. % (I.e. if contrast and space test the same thing)
  232. %
  233. % ----------------
  234. %
  235. % FORMAT [df1,df2] = spm_SpUtil('i0->edf',x,i0,V) {or 'edf'}
  236. % (effective) df1 and df2 the residual df for the projector onto the
  237. % null space of x' (residual forming projector) and the numerator of
  238. % the F-test where i0 are the columns for the null hypothesis model.
  239. % x - Design matrix X, or space structure of X
  240. % i0 - Columns of X corresponding to X0 partition X = [X1,X0] & with
  241. % parameters B = [B1;B0]. Ho:B1=0
  242. % V - V matrix
  243. %
  244. % ----------------
  245. %
  246. % FORMAT sz = spm_SpUtil('size',x,dim)
  247. % FORMAT [sz1,sz2,...] = spm_SpUtil('size',x)
  248. % Returns size of design matrix
  249. % (Like MatLab's `size`, but copes with design matrices inside structures.)
  250. % x - Design matrix X, or structure containing design matrix in field X
  251. % (Structure needn't be a space structure.)
  252. % dim - dimension which to size
  253. % sz - size
  254. %
  255. %_______________________________________________________________________
  256. % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging
  257. % Andrew Holmes Jean-Baptiste Poline
  258. % $Id: spm_SpUtil.m 4137 2010-12-15 17:18:32Z guillaume $
  259. % (frobenius norm trick by S. Rouquette)
  260. %-Format arguments
  261. %-----------------------------------------------------------------------
  262. if nargin==0, error('do what? no arguments given...')
  263. else action = varargin{1}; end
  264. switch lower(action),
  265. case {'iscon','allcon','conr','cono'}
  266. %=======================================================================
  267. % i = spm_SpUtil('isCon',x,c)
  268. if nargin==0, varargout={[]}; error('isCon : no argument specified'), end;
  269. if nargin==1,
  270. varargout={[]}; warning('isCon : no contrast specified'); return;
  271. end;
  272. if ~spm_sp('isspc',varargin{2})
  273. sX = spm_sp('Set',varargin{2});
  274. else sX = varargin{2}; end
  275. if nargin==2, c=eye(spm_sp('size',sX,2)); else c=varargin{3}; end;
  276. if isempty(c), varargout={[]}; return, end
  277. switch lower(action)
  278. case 'iscon'
  279. varargout = { spm_sp('eachinspp',sX,c) };
  280. case 'allcon'
  281. varargout = {spm_sp('isinspp',sX,c)};
  282. case 'conr'
  283. if size(c,1) ~= spm_sp('size',sX,2)
  284. error('Contrast not of the right size'), end
  285. %-Compute inner products of data weight vectors
  286. % (c'b = c'*pinv(X)*Y = w'*Y
  287. % (=> w*w' = c'*pinv(X)*pinv(X)'*c == c'*pinv(X'*X)*c
  288. r = c'*spm_sp('XpX-',sX)*c;
  289. %-normalize by "cov(r)" to get correlations
  290. r = r./(sqrt(diag(r))*sqrt(diag(r))');
  291. r(abs(r) < sX.tol)=0; %-set near-zeros to zero
  292. varargout = {r}; %-return r
  293. case 'cono'
  294. %-This is the same as ~spm_SpUtil('ConR',x,c), and so returns
  295. % the contrast orthogonality (though not their corelations).
  296. varargout = { abs(c'* spm_sp('XpX',sX) *c) < sX.tol};
  297. end
  298. case {'+c->tsp','c->tsp'} %- Ortho. partitioning implied by F-contrast
  299. %=======================================================================
  300. % spm_SpUtil('c->Tsp',sX,c)
  301. % + version of 'c->tsp'.
  302. % The + version returns the same in the base u(:,1:r).
  303. %--------- begin argument check ------------------------------
  304. if nargin ~= 3, error(['Wrong number of arguments in ' action])
  305. else sX = varargin{2}; c = varargin{3}; end;
  306. if nargout > 2, error(['Too many output arguments in ' action]), end;
  307. if ~spm_sp('isspc',sX), sX = spm_sp('set',varargin{2}); end;
  308. if sX.rk == 0, error('c->Tsp null rank sX == 0'); end;
  309. if ~isempty(c) && spm_sp('size',sX,2) ~= size(c,1),
  310. error(' c->TSp matrix & contrast dimensions don''t match');
  311. end
  312. %--------- end argument check ---------------------------------
  313. %- project c onto the space of X' if needed
  314. %-------------------------------------------
  315. if ~isempty(c) && ~spm_sp('isinspp',sX,c),
  316. warning([sprintf('\n') 'c is not a proper contrast in ' action ...
  317. ' in ' mfilename sprintf('\n') '!!! projecting...' ]);
  318. disp('from'), c, disp('to'), c = spm_sp('oPp:',sX,c)
  319. end
  320. cukFlag = strcmp(lower(action),'+c->tsp');
  321. switch nargout
  322. % case 0
  323. % warning(['no output demanded in ' mfilename ' ' action])
  324. case {0,1}
  325. if ~isempty(c) && any(any(c)) %- c not empty & not null
  326. if cukFlag, varargout = { spm_sp('cukxp-:',sX,c) };
  327. else varargout = { spm_sp('xp-:',sX,c) };
  328. end
  329. else if isempty(c), varargout = { [] }; %- c empty
  330. else %- c null
  331. if cukFlag, varargout = { spm_sp('cukx',sX,c) };
  332. else varargout = { spm_sp('x',sX)*c };
  333. end
  334. end
  335. end
  336. case 2
  337. if ~isempty(c) && any(any(c)) %- not empty and not null
  338. if cukFlag,
  339. varargout = {
  340. spm_sp('cukxp-:',sX,c), ... %- X1o
  341. spm_sp('cukx',sX,spm_sp('r',spm_sp('set',c))) }; %- X0
  342. else
  343. varargout = {
  344. spm_sp(':',sX, spm_sp('xp-:',sX,c)), ... %- X1o
  345. spm_sp(':',sX, ...
  346. spm_sp('x',sX)*spm_sp('r',spm_sp('set',c))) }; %- X0
  347. end
  348. else
  349. if isempty(c), %- empty
  350. if cukFlag, varargout = { [], spm_sp('cukx',sX) };
  351. else varargout = { [], spm_sp('x',sX) };
  352. end
  353. else %- null
  354. if cukFlag,
  355. varargout = { spm_sp(':',sX,spm_sp('cukx',sX,c)), ...
  356. spm_sp(':',sX,spm_sp('cukx',sX)) };
  357. else
  358. varargout = { spm_sp('x',sX)*c, spm_sp('x',sX)};
  359. end
  360. end;
  361. end
  362. otherwise
  363. error(['wrong number of output argument in ' action]);
  364. end
  365. case {'i0->x1o','+i0->x1o'} %- Space tested whilst keeping size of X(i0)
  366. %=======================================================================
  367. % X1o = spm_SpUtil('i0->X1o',sX,i0)
  368. % arguments are checked in calls to spm_Util
  369. %--------------------------------------------
  370. if nargin<3, error('Insufficient arguments'),
  371. else sX = varargin{2}; i0 = varargin{3}; end;
  372. cukFlag = strcmp(lower(action),'+i0->x1o');
  373. c = spm_SpUtil('i0->c',sX,i0);
  374. if cukFlag,
  375. varargout = { spm_SpUtil('+c->TSp',sX,c) };
  376. else
  377. varargout = { spm_SpUtil('c->TSp',sX,c) };
  378. end
  379. case {'i0->c'} %-
  380. %=======================================================================
  381. % c = spm_SpUtil('i0->c',sX,i0)
  382. %
  383. % if i0 == [] : returns a proper contrast
  384. % if i0 == [1:size(sX.X,2)] : returns [];
  385. %
  386. %- Algorithm : avoids the pinv(X0) and insure consistency
  387. %- Get the estimable parts of c0 and c1
  388. %- remove from c1_estimable the estimable part of c0.
  389. %- Use the rotation making X1o orthog. to X0.
  390. %- i0 is checked when Fc is created
  391. %- If i0 defines a space that is the space of X but with
  392. %- fewer vectors, c is null.
  393. %--------- begin argument check --------------------------------
  394. if nargin<3, error('Insufficient arguments'),
  395. else sX = varargin{2}; i0 = varargin{3}; end;
  396. if ~spm_sp('isspc',sX), sX = spm_sp('set',varargin{2}); end;
  397. if spm_sp('rk',sX) == 0, error('i0->c null rank sX == 0'); end;
  398. sL = spm_sp('size',sX,2);
  399. i0 = sf_check_i0(i0,sL);
  400. %--------- end argument check ----------------------------------
  401. c0 = eye(sL); c0 = c0(:,i0);
  402. c1 = eye(sL); c1 = c1(:,setdiff(1:sL,i0));
  403. %- try to avoid the matlab error when doing svd of matrices with
  404. %- high multiplicities. (svd convergence pb)
  405. if ~ spm_sp('isinspp',sX,c0), c0 = spm_sp('oPp:',sX,c0); end;
  406. if ~ spm_sp('isinspp',sX,c1), c1 = spm_sp('oPp:',sX,c1); end;
  407. if ~isempty(c1)
  408. if ~isempty(c0)
  409. %- varargout = { spm_sp('res',spm_sp('set',opp*c0),opp*c1) };
  410. %- varargout = { c1 - c0*pinv(c0)*c1 }; NB: matlab pinv uses
  411. %- svd: will fail if spm_sp('set') fails.
  412. varargout = { spm_sp('r:',spm_sp('set',c0),c1) };
  413. else varargout = { spm_sp('xpx',sX) }; end;
  414. else
  415. varargout = { [] }; %- not zeros(sL,1) : this is return when
  416. %- appropriate
  417. end
  418. %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  419. %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  420. case {'+x0->c','x0->c'} %-
  421. %=======================================================================
  422. % c = spm_SpUtil('X0->c',sX,X0)
  423. % c = spm_SpUtil('+X0->c',sX,cukX0)
  424. % + version of 'x0->c'.
  425. % The + version returns the same in the base u(:,1:r).
  426. warning('Not tested for release - provided for completeness');
  427. cukFlag = strcmp(lower(action),'+x0->c');
  428. %--------- begin argument check ---------
  429. if nargin<3, error('Insufficient arguments'),
  430. else
  431. sX = varargin{2};
  432. if cukFlag, cukX0 = varargin{3}; else X0 = varargin{3}; end
  433. end
  434. if ~spm_sp('isspc',sX), sX = spm_sp('set',varargin{2}); end
  435. if spm_sp('rk',sX) == 0, error(['null rank sX == 0 in ' action]); end
  436. if cukFlag
  437. if ~isempty(cukX0) && spm_sp('rk',sX) ~= size(cukX0,1),
  438. cukX0, spm_sp('rk',sX),
  439. error(['cukX0 of wrong size ' mfilename ' ' action]), end
  440. else
  441. if ~isempty(X0) && spm_sp('size',sX,1) ~= size(X0,1),
  442. X0, spm_sp('size',sX,1),
  443. error(['X0 of wrong size ' mfilename ' ' action]),X0, end
  444. end
  445. %--------- end argument check ---------
  446. if cukFlag
  447. if isempty(cukX0), X0 = []; else X0 = spm_sp('ox',sX)*cukX0; end
  448. end
  449. varargout = { sf_X0_2_c(X0,sX) };
  450. case {'c->h','betarc'} %-Extra sum of squares matrix for beta's from
  451. %- contrast : use F-contrast if possible
  452. %=======================================================================
  453. % H = spm_SpUtil('c->H',sX,c)
  454. error(' Obsolete : Use F-contrast utilities ''H'' or ''Hsqr''... ');
  455. %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  456. %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  457. %=======================================================================
  458. %=======================================================================
  459. % trace part
  460. %=======================================================================
  461. %=======================================================================
  462. %
  463. case 'trrv' %-Traces for (effective) df calculation
  464. %=======================================================================
  465. % [trRV,trRVRV]= spm_SpUtil('trRV',x[,V])
  466. if nargin == 1, error('insufficient arguments');
  467. else sX = varargin{2}; end;
  468. if ~spm_sp('isspc',sX), sX = spm_sp('Set',sX); end;
  469. rk = spm_sp('rk',sX);
  470. sL = spm_sp('size',sX,1);
  471. if sL == 0,
  472. warning('space with no dimension ');
  473. if nargout==1, varargout = {[]};
  474. else varargout = {[], []}; end
  475. else
  476. if nargin > 2 && ~isempty(varargin{3})
  477. V = varargin{3};
  478. u = sX.u(:,1:rk);
  479. clear sX;
  480. if nargout==1
  481. %-only trRV needed
  482. if rk==0 || isempty(rk), trMV = 0;
  483. else trMV = sum(sum( u .* (V*u) ));
  484. end
  485. varargout = { trace(V) - trMV};
  486. else
  487. %-trRVRV is needed as well
  488. if rk==0 || isempty(rk),
  489. trMV = 0;
  490. trRVRV = (norm(V,'fro'))^2;
  491. trV = trace(V);
  492. clear V u
  493. else
  494. Vu = V*u;
  495. trV = trace(V);
  496. trRVRV = (norm(V,'fro'))^2;
  497. clear V;
  498. trRVRV = trRVRV - 2*(norm(Vu,'fro'))^2;
  499. trRVRV = trRVRV + (norm(u'*Vu,'fro'))^2;
  500. trMV = sum(sum( u .* Vu ));
  501. clear u Vu
  502. end
  503. varargout = {(trV - trMV), trRVRV};
  504. end
  505. else %- nargin == 2 | isempty(varargin{3})
  506. if nargout==1
  507. if rk==0 || isempty(rk), varargout = {sL};
  508. else varargout = {sL - rk};
  509. end
  510. else
  511. if rk==0 || isempty(rk), varargout = {sL,sL};
  512. else varargout = {sL - rk, sL - rk};
  513. end
  514. end
  515. end
  516. end
  517. case 'trmv' %-Traces for (effective) Fdf calculation
  518. %=======================================================================
  519. % [trMV, trMVMV]] = spm_SpUtil('trMV',sX [,V])
  520. %
  521. % NB : When V is given empty, the routine asssumes it's identity
  522. % This is used in spm_FcUtil.
  523. if nargin == 1, error('insufficient arguments');
  524. else sX = varargin{2}; end;
  525. if ~spm_sp('isspc',sX), sX = spm_sp('Set',sX); end;
  526. rk = spm_sp('rk',sX);
  527. if isempty(rk)
  528. warning('Rank is empty');
  529. if nargout==1, varargout = {[]};
  530. else varargout = {[], []}; end
  531. return;
  532. elseif rk==0, warning('Rank is null in spm_SpUtil trMV ');
  533. if nargout==1, varargout = {0};
  534. else varargout = {0, 0}; end
  535. return;
  536. end;
  537. if nargin > 2 && ~isempty(varargin{3}) %- V provided, and assumed correct !
  538. V = varargin{3};
  539. u = sX.u(:,1:rk);
  540. clear sX;
  541. if nargout==1
  542. %-only trMV needed
  543. trMV = sum(sum(u' .* (u'*V) ));
  544. varargout = {trMV};
  545. else
  546. %-trMVMV is needed as well
  547. Vu = V*u;
  548. clear V
  549. trMV = sum(sum( u .* Vu ));
  550. trMVMV = (norm(u'*Vu,'fro'))^2;
  551. clear u Vu
  552. varargout = {trMV, trMVMV};
  553. end
  554. else % nargin == 2 | isempty(varargin{3}) %-no V specified: trMV == trMVMV
  555. if nargout==1
  556. varargout = {rk};
  557. else
  558. varargout = {rk, rk};
  559. end
  560. end
  561. case {'i0->edf','edf'} %-Effective F degrees of freedom
  562. %=======================================================================
  563. % [df1,df2] = spm_SpUtil('i0->edf',sX,i0,V)
  564. %-----------------------------------------------------------------------
  565. %--------- begin argument check ----------------------------------------
  566. if nargin<3, error('insufficient arguments'),
  567. else i0 = varargin{3}; sX = varargin{2}; end
  568. if ~spm_sp('isspc',sX), sX = spm_sp('Set',sX); end;
  569. i0 = sf_check_i0(i0,spm_sp('size',sX,2));
  570. if nargin == 4, V=varargin{4}; else V = eye(spm_sp('size',sX,1)); end;
  571. if nargin>4, error('Too many input arguments'), end;
  572. %--------- end argument check ------------------------------------------
  573. warning(' Use F-contrast utilities if possible ... ');
  574. [trRV,trRVRV] = spm_SpUtil('trRV', sX, V);
  575. [trMpV,trMpVMpV] = spm_SpUtil('trMV',spm_SpUtil('i0->x1o',sX, i0),V);
  576. varargout = {trMpV^2/trMpVMpV, trRV^2/trRVRV};
  577. %=======================================================================
  578. %=======================================================================
  579. % Utilities
  580. %=======================================================================
  581. %=======================================================================
  582. case 'size' %-Size of design matrix
  583. %=======================================================================
  584. % sz = spm_SpUtil('size',x,dim)
  585. if nargin<3, dim=[]; else dim = varargin{3}; end
  586. if nargin<2, error('insufficient arguments'), end
  587. if isstruct(varargin{2})
  588. if isfield(varargin{2},'X')
  589. sz = size(varargin{2}.X);
  590. else error('no X field'); end;
  591. else
  592. sz = size(varargin{2});
  593. end
  594. if ~isempty(dim)
  595. if dim>length(sz), sz = 1; else sz = sz(dim); end
  596. varargout = {sz};
  597. elseif nargout>1
  598. varargout = cell(1,min(nargout,length(sz)));
  599. for i=1:min(nargout,length(sz)), varargout{i} = sz(i); end
  600. else
  601. varargout = {sz};
  602. end
  603. case 'ix0check' %-
  604. %=======================================================================
  605. % i0c = spm_SpUtil('iX0check',i0,sL)
  606. if nargin<3, error('insufficient arguments'),
  607. else i0 = varargin{2}; sL = varargin{3}; end;
  608. varargout = {sf_check_i0(i0,sL)};
  609. otherwise
  610. %=======================================================================
  611. error('Unknown action string in spm_SpUtil')
  612. %=======================================================================
  613. end
  614. %=======================================================================
  615. function i0c = sf_check_i0(i0,sL)
  616. % NB : [] = sf_check_i0([],SL);
  617. %
  618. if all(ismember(i0,[0,1])) && length(i0(:))==sL, i0c=find(i0);
  619. elseif ~isempty(i0) && any(floor(i0)~=i0) || any(i0<1) || any(i0>sL)
  620. error('logical mask or vector of column indices required')
  621. else i0c = i0; end
  622. %=======================================================================
  623. function c = sf_X0_2_c(X0,sX)
  624. %
  625. %- Algorithm to avoids the pinv(X0) and insure consistency
  626. %- Get a contrast that span the space of X0 and is estimable
  627. %- Get the orthogonal complement and project onto the estimable space
  628. %- Strip zeros columns and use the rotation making X1o orthog. to X0
  629. % !!! tolerance dealing ?
  630. if ~isempty(X0)
  631. sc0 = spm_sp('set',spm_sp('x-',sX,X0));
  632. if sc0.rk
  633. c = spm_sp('oPp:',sX,spm_sp('r',sc0));
  634. else
  635. c = spm_sp('oPp',sX);
  636. end;
  637. c = c(:,any(c));
  638. sL = spm_sp('size',sX,2);
  639. %- why the "& size(X0,2) ~= sL" !!!?
  640. if isempty(c) && size(X0,2) ~= sL
  641. c = zeros(sL,1);
  642. end
  643. else
  644. c = spm_sp('xpx',sX);
  645. end
  646. %- c = spm_sp('r',sc0,spm_sp('oxp',sX)); would also works.