function [MINUSL,SCORE,INFO,V] = diffloglik(THIS,DATA,RANGE,PLIST,varargin)
% diffloglik  Approximate gradient and hessian of log-likelihood function.
%
% Syntax
% =======
%
%     [MINUSL,GRAD,HESS,V] = diffloglik(M,D,RANGE,LIST,...)
%
% Input arguments
% ================
%
% * `M` [ model ] - Model object whose likelihood function will be
% differentiated.
%
% * `D` [ cell | struct ] - Input data from which measurement variables
% will be taken.
%
% * `RANGE` [ numeric ] - Date range on which the likelihood function
% will be evaluated.
%
% * `LIST` [ cellstr ] - List of model parameters with respect to which the
% likelihood function will be differentiated.
%
% Output arguments
% =================
%
% * `MINUSL` [ numeric ] - Value of minus the likelihood function at the input
% data.
%
% * `GRAD` [ numeric ] - Gradient (or score) vector.
%
% * `HESS` [ numeric ] - Hessian (or information) matrix.
%
% * `V` [ numeric ] - Estimated variance scale factor if the `'relative='`
% options is true; otherwise `v` is 1.
%
% Options
% ========
%
% * `'refresh='` [ *`true`* | `false` ] - Refresh dynamic links for each change
% in a parameter.
%
% * `'solve='` [ *`true`* | `false` ] - Re-compute solution for each change in a
% parameter.
%
% * `'sstate='` [ `true` | *`false`* | cell ] - Re-compute steady state in each
% differentiation step; if the model is non-linear, you can pass in a cell
% array with options used in the `sstate` function.
%
% See help on [`model/filter`](model/filter) for other options available.
%
% Description
% ============
%
% Example
% ========
%

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

P = inputParser();
P.addRequired('model',@ismodel);
P.addRequired('data',@(x) isstruct(x) || iscell(x));
P.addRequired('range',@isnumeric);
P.addRequired('plist',@(x) ischar(x) || iscellstr(x));
P.parse(THIS,DATA,RANGE,PLIST);

[opt,varargin] = passvalopt('model.diffloglik',varargin{:});

% Process Kalman filter options; `loglikopt` also expands solution forward
% if needed for tunes on the mean of shocks.
[kalmanopt,THIS] = mypreloglik(THIS,RANGE,'t',[],varargin{:});

% Get measurement variables.
DATA = datarequest('y',THIS,DATA,RANGE);

% Create an `stdcorr` vector from user-supplied database.
kalmanopt.stdcorr = mytune2stdcorr(THIS,RANGE,[],kalmanopt,'clip');

% Requested output data.
kalmanopt.retpevec = true;
kalmanopt.retf = true;

if ischar(PLIST)
    PLIST = regexp(PLIST,'\w+','match');
end

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

nalt = size(THIS.Assign,3);

% Multiple parameterizations are not allowed.
if nalt > 1
    utils.error('model', ...
        'Cannot run DIFFLOGLIK on multiple parametrisations.');
end

% Find parameter names and create parameter index.
[assignpos,stdcorrpos] = mynameposition(THIS,PLIST,'error');

% Call low-level diffloglik.
[MINUSL,SCORE,INFO,V] = mydiffloglik( ...
    THIS,DATA,RANGE,assignpos,stdcorrpos,opt,kalmanopt);

end