function [stat,crit] = portest(w,data,h,varargin)
% portest  Portmanteau test for autocorrelation in VAR residuals.
%
% Syntax
% =======
%
%     [STAT,CRIT] = portest(V,DATA,H)
%
% Input arguments
% ================
%
% * `V` [ VAR | swar ] - Estimated VAR from which the tested residuals were
% obtained.
%
% * `DATA` [ tseries ] - VAR residuals, or VAR output data including
% residuals, to be tested for autocorrelation.
%
% * `H` [ numeric ] - Test horizon; must be greater than the order of the
% tested VAR.
%
% Output arguments
% =================
%
% * `STAT` [ numeric ] - Portmanteau test statistic.
%
% * `CRIT` [ numeric ] - Portmanteau test critical value based on
% chi-square distribution.
%
% Options
% ========
%
% * `'level='` [ numeric | *0.05* ] - Requested significance level for
% computing the criterion `CRIT`.
%
% Description
% ============
%
% Example
% ========
%

% -IRIS Toolbox.
% -Copyright 2007-2012 Jaromir Benes.

if length(varargin) == 1 && isnumericscalar(varargin{1})
    % Bkw compatibility.
    opt = struct('level',varargin{1});
else
    opt = passvalopt('VAR.portest',varargin{:});
end

%**************************************************************************

[ny,p,nalt] = sizeof(w);
if h <= p
    VAR.error(8);
end

% Request residuals.
[ans,ans,ans,e] = VAR.datarequest(w,data,w.range); %#ok<NOANS,ASGLU>
ndata = size(e,3);
if ndata ~= nalt
    VAR.error(24);
end

% Orthonormalise residuals by Choleski factor of Omega.
for ialt = 1 : nalt
    P = chol(w.Omega(:,:,ialt));
    e(:,:,ialt) = P\e(:,:,ialt);
end

% Test statistic.
stat = zeros(1,nalt);
for ialt = 1 : nalt
    fitted = w.fitted(1,:,ialt);
    nobs = sum(fitted);
    ei = e(:,fitted,ialt);
    for i = 1 : h
        Ci = ei(:,1+i:end)*ei(:,1:end-i)' / nobs;
        stat(ialt) = stat(ialt) + trace(Ci'*Ci) / (nobs-i);
    end
    stat(ialt) = (nobs^2)*stat(ialt);
end

% Critical value
if nargout > 1
    crit = chi2inv(1-opt.level,ny^2*(h-p));
end

end
