function x = spm_invGcdf(F,h,l,tol) % Inverse Cumulative Distribution Function (CDF) of Gamma distribution % FORMAT x = spm_invGcdf(p,h,l,tol) % % F - CDF (lower tail p-value) % h - Shape parameter (h>0) % l - Scale parameter (l>0) % x - Gamma ordinates at which CDF F(x)=F % tol - tolerance [default 10^-6] %__________________________________________________________________________ % % spm_invGcdf implements the inverse Cumulative Distribution Function % for Gamma distributions. % % Definition: %-------------------------------------------------------------------------- % The Gamma distribution has shape parameter h and scale l, and is % defined for h>0 & l>0 and for x in [0,Inf) (See Evans et al., Ch18, % but note that this reference uses the alternative parameterisation of % the Gamma with scale parameter c=1/l) % % The Cumulative Distribution Function (CDF) F(x) is the probability % that a realisation of a Gamma random variable X has value less than % x. F(x)=Pr{X1; if sum(xa)>1 && any(any(diff(as(xa,:)),1)) error('non-scalar args must match in size'); end %-Computation - Undefined and special cases %-------------------------------------------------------------------------- %-Initialise result to zeros x = zeros(rs); %-Only defined for F in [0,1] & strictly positive h & l. % Return NaN if undefined. md = ( F>=0 & F<=1 & h>0 & l>0 ); if any(~md(:)) x(~md) = NaN; warning('Returning NaN for out of range arguments'); end %-Special cases: x=0 when F=0, x=Inf when F=1 x(md & F==1) = Inf; %-Compute where defined & not special case %-------------------------------------------------------------------------- Q = find( md & F>0 & F<1 ); if isempty(Q), return, end if xa(1), FQ=F(Q); FQ=FQ(:); else FQ=F*ones(length(Q),1); end if xa(2), hQ=h(Q); hQ=hQ(:); else hQ=h*ones(length(Q),1); end if xa(3), lQ=l(Q); lQ=lQ(:); else lQ=l*ones(length(Q),1); end %-?Q=?Q(:) stuff is to avoid discrepant orientations of vector arguments! %-Compute initial interval estimates [0,mean] & Grow to encompass F(QF); %-------------------------------------------------------------------------- a = zeros(length(Q),1); b = hQ./(2*lQ); QQ = 1:length(Q); while ~isempty(QQ) b(QQ) = 2*b(QQ); QQ = find(spm_Gcdf(b,hQ,lQ) < FQ); end %-Interval bisection %-------------------------------------------------------------------------- fa = spm_Gcdf(a,hQ,lQ)-FQ; fb = spm_Gcdf(b,hQ,lQ)-FQ; i = 0; xQ = a+(b-a)/2; QQ = 1:length(Q); while ~isempty(QQ) && i 0; a(QQ(mQQ)) = xQ(QQ(mQQ)); fa(QQ(mQQ)) = fxQQ(mQQ); b(QQ(~mQQ)) = xQ(QQ(~mQQ)); fb(QQ(~mQQ)) = fxQQ(~mQQ); xQ(QQ) = a(QQ) + (b(QQ)-a(QQ))/2; QQ = QQ( (b(QQ)-a(QQ))>tol ); i = i+1; end if i==maxIt warning('convergence criteria not reached - maxIt reached'); end x(Q) = xQ;