function [THIS,OUTP,V] = filter(THIS,INP,RANGE,varargin)
% filter  Kalman smoother and estimator of out-of-likelihood parameters.
%
% Syntax
% =======
%
%     [M,OUTP,V,DELTA,PE] = filter(M,INP,RANGE,...)
%     [M,OUTP,V,DELTA,PE] = filter(M,INP,RANGE,J,...)
%
% Input arguments
% ================
%
% * `M` [ model ] - Solved model object.
%
% * `INP` [ struct | cell ] - Input database from which the observables and
% initial values for primary unobservables will be taken.
%
% * `RANGE` [ numeric ] - Filter date range.
%
% Output arguments
% =================
%
% * `OUTP` [ struct | cell ] - Output struct with smoother or prediction
% data.
%
% Options
% ========
%
% * `'ahead='` [ numeric | *1* ] - Predictions will be computed this number
% of period ahead.
%
% * `'deviation='` [ `true` | *`false`* ] - Treat input and output data as
% deviations from balanced-growth path.
%
% * `'dtrends='` [ *'auto'* | true | false ] - Measurement data contain
% deterministic trends.
%
% * `'data='` [ 'predict' | *'smooth'* | 'predict,smooth' ] - Return
% smoother data or prediction data or both.
%
% * `'exclude='` [ cellstr | *empty* ] - List of measurement variables that
% will be excluded from the likelihood function.
%
% * `'initCond='` [ 'fixed' | 'optimal' | *'stochastic'* | struct ] - Method
% or data to initialise the Kalman filter.
%
% * `'lastSmooth='` [ numeric | *`Inf`* ] - Last date up to which to smooth
% data backward from the end of the range; if Inf smoother will run on the
% entire range.
%
% * `'meanOnly='` [ `true` | *`false`* ] - Return a plain database with mean
% data only.
%
% * `'outOfLik='` [ cellstr | empty ] - List of parameters in deterministic
% trends that will be estimated by concentrating them out of the likelihood
% function.
%
% * `'objective='` [ *'-loglik'* | 'prederr' ] - Objective function
% computed; can be either minus the log likelihood function or weighted sum
% of prediction errors.
%
% * `'objRange='` [ numeric | *`Inf`* ] - The objective function will
% be computed on this subrange only; `Inf` means the entire filter range.
%
% * `'output='` [ *'auto'* | 'dbase' | 'dpack' ] - Format of output data.
%
% * `'precision='` [ *'double'* | 'single' ] - Numeric precision to which
% output data will be stored; all calculations themselves always run to
% double precision.
%
% * `'rollback='` [ numeric | *empty* ] - Date up to which to roll back
% individual observations on measurement variables from the end of the
% sample.
%
% * `'relative='` [ *`true`* | `false` ] - Std devs of shocks assigned in the
% model object will be treated as relative std devs, and a common variance
% scale factor will be estimated.
%
% * `'returnMse='` [ *`true`* | `false` ] - Return MSE matrices for
% predetermined state variables; these can be used for settin up initial
% condition in subsequent call to another `filter` or `jforecast`.
%
% * `'returnStd='` [ *`true`* | `false` ] - Return database with std devs of
% model variables.
%
% * `'tolMse='` [ numeric | *0* ] - Tolerance under which two MSE matrices
% in two consecutive periods will be treated as equal, and the Kalman gain
% system will be re-used, not re-computed.
%
% * `'weighting='` [ numeric | *empty* ] - Weighting vector or matrix for
% prediction errors when `'objective=' 'prederr'`; if empty prediction
% errors are weighted equally.
%
% Description
% ============
%
% The options `'ahead='` and `'rollback='` cannot be combined with one
% another, or with multiple data sets, or with multiple parameterisations.
%
% Example
% ========
%

% -IRIS Toolbox.
% -Copyright (c) 2007-2012 Jaromir Benes.

P = inputParser();
P.addRequired('THIS',@(x) isa(x,'syeq'));
P.addRequired('INP',@(x) isstruct(x) || iscell(x) || isempty(x));
P.addRequired('RANGE',@isnumeric);
P.parse(THIS,INP,RANGE);

% This FILTER function options.
[opt,varargin] = passvalopt('syeq.filter',varargin{:}); %#ok<ASGLU>

% Prepare loglik function.
[loglikopt,THIS] = mypreloglik(THIS,RANGE,[],[],varargin);

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

nalt = size(THIS.Assign,3);
ndata = 1;
NLOOP = max([nalt,ndata]);

% Preallocate output database.
OUTP = struct();
ppinitoutp;

for iloop = 1 : NLOOP
    
    idata = min(iloop,ndata);
    ialt = min(iloop,nalt);
    
    % Get an nname-by-nper matrix of current data.
    Y = mydatarequest([],THIS,INP,RANGE,idata);
    
    % Run the filter.
    [obj,V,~,~,Y] = mykalman(THIS,Y,loglikopt,ialt); %#ok<ASGLU>
    
    Y = mybackoutshocks(THIS,Y,ialt); %#ok<NASGU>
    
    % Add current filter data to output database.
    COLS = iloop; %#ok<NASGU>
    ppassignoutp;

end

% Scale std devs by estimated factor in model object.
if V ~= 1
    nalt = size(THIS.Assign,3);
    ne = sum(THIS.nametype == 3);
    se = sqrt(V);
    for ialt = 1 : nalt
        THIS.stdcorr(1,1:ne,ialt) = ...
            THIS.stdcorr(1,1:ne,ialt)*se(min(ialt,end));
    end
end

% Convert output data to tseries objects.
ppconvertoutp;

end