function [K,V,DELTA,PDELTA,Y] = mykalman(THIS,Y,OPT,IALT)

try
    IALT;
catch %#ok<CTCH>
    IALT = 1;
end

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

K = Inf;
V = 1;
DELTA = [];
PDELTA = [];

ne = sum(THIS.nametype == 3);
maxlag = -THIS.mint;
maxlead = THIS.maxt;
nxper = size(Y,2);
t = 1+maxlag : nxper-maxlead;
nper = length(t);
isident = ~isnan(THIS.ident);
neqtn = length(THIS.eqtn);

% Create vector of steady-state values.
L = real(THIS.Assign(1,:,IALT));

% Detect unobservables.
imagdata = imag(Y);
unobsindex = isfinite(imagdata) & imagdata ~= 0;
isunobs = any(unobsindex(:));
islog = any(THIS.log);

istransform = isstruct(OPT.transform) ...
    && ~isempty(fieldnames(OPT.transform));

% Discard imaginary part, which is only used to earmark unobservables.
Y = real(Y);

% Combine currently assigned `stdcorr` in the model object with the
% user-supplied time-vaying `stdcorr`.
thisstdcorr = THIS.stdcorr(1,:,IALT).';
stdcorr = metaobj.mycombinestdcorr(thisstdcorr,OPT.stdcorr,nper);

% Create covariance matrix from stdcorr vector.
Omg = covfun.stdcorr2cov(stdcorr,ne);

% Factorise the cov matrix for use in the filter; if Cholesky fails (most
% often because of numerical singularity) we will return Inf immediately.
try
    P = nan(size(Omg));
    lastomg = size(Omg,3);
    for i = 1 : lastomg
        P(:,:,i) = chol(Omg(:,:,i)).';
    end
catch %#ok<CTCH>
    Y(:) = NaN;
    utils.warning('syeq', ...
        ['Cannot run filter and evaluate likelihood because ', ...
        'covariance matrix of shocks fails to be positive definite.']);
    return
end

% Reset shocks to zero.
Y(THIS.nametype == 3,:) = 0;

% Find identity variables that need to be evaluated.
select = false(1,neqtn);
doselectident();

% `Y` is nname-by-nper; permute `Y` to 1-by-nname-by-nper.
Y = permute(Y,[3,1,2]);

if isunobs
    if islog
        y = Y;
        y(1,THIS.log,:) = log(y(1,THIS.log,:));
        x0 = y(unobsindex);
    else
        x0 = Y(unobsindex);
    end
    x0(~isfinite(x0)) = 0;
    oo = optimset('display','iter');%,'algorithm','levenberg-marquardt');
    [x1,W,~,exitflag] = lsqnonlin(@dofilter,x0,[],[],oo);
    e1 = dofilter(x1);
    % Assign estimate unobservables.
    if exitflag <= 0
        Y = ipermute(Y,[3,1,2]);
        Y(:) = NaN;
        utils.warning('syeq','Filter failed to converge.');
        return
    end
    %{
    y(unobsindex) = x1;
    y(1,THIS.log,:) = exp(y(1,THIS.log,:));
    Y(unobsindex) = y(unobsindex);
    % Evaluate identities.
    Y = myevalident(THIS,Y,t,select,IALT);
    %}
else
    e1 = dofilter();    
    % Weighted sum of shocks.
    W = e1*e1.';
end

% Differentiate equations wrt variables(0).
T = system(THIS,Y,t,'T',IALT);

% Calculate minus log likelihood.
[K,V] = dominusloglik();

% Permute dimensions back.
Y = ipermute(Y,[3,1,2]);

% Back out approximate shocks.
e1 = reshape(e1,[ne,nper]);
for i = 1 : lastomg-1
    e1(:,i) = P(:,:,i)*e1(:,i);
end
e1(:,lastomg:end) = P(:,:,lastomg)*e1(:,lastomg:end);

% Assign approximate shocks.
Y(THIS.nametype == 3,:) = NaN;
Y(THIS.nametype == 3,t) = e1;

% Nested functions.

%**************************************************************************
    function doselectident()
        valid = true(1,neqtn);
        for ieq = find(isident)
            id = THIS.ident(ieq);
            nandata = isnan(Y(id,t));
            if all(nandata)
                select(ieq) = true;
            elseif any(nandata)
                valid(ieq) = false;
            end
        end
        if any(~valid)
            utils.error('syeq', ...
                ['The LHS variables in this identity ', ...
                'has some but not all observations NaNs: ''%s''.'], ...
                THIS.eqtn{~valid});
        end
    end
% doselectident().

%**************************************************************************
    function e = dofilter(x)

        % Fill in unobservables.
        if nargin > 0 && isunobs
            if islog
                y(unobsindex) = x;
                y(1,THIS.log,:) = exp(y(1,THIS.log,:));
                Y(unobsindex) = y(unobsindex);
            else
                Y(unobsindex) = x;
            end
        end
        
        % Apply transformation functions.
        if istransform
            for iiname = find(any(unobsindex,2)).'
                name = THIS.name{iiname};
                if isfield(OPT.transform,name) ...
                        && isa(OPT.transform.(name),'function_handle')
                    index = false(size(unobsindex));
                    index(iiname,:) = unobsindex(iiname,:);
                    Y(index) = OPT.transform.(name)(Y(index));
                end
            end
        end
        
        % Evaluate identities.
        Y = myevalident(THIS,Y,t,select,IALT);
        
        % Differentiate equations wrt shocks.
        [~,R] = system(THIS,Y,t,'R',IALT);
        
        % Get residuals from non-ident equations.
        %u = zeros(0,nper);
        %for ieq = find(nonidentindex)
        %    u(end+1,:) = THIS.eqtnf{ieq}(Y,t,L); %#ok<AGROW>
        %end
        u = THIS.evalnonident(Y,t,L);
        
        % Convert equation residuals to structural shocks.
        e = nan(size(u));
        for ii = 1 : nper
            e(:,ii) = -R(:,:,ii)\u(:,ii);
        end

        for ii = 1 : lastomg-1
            e(:,ii) = P(:,:,ii)\e(:,ii);
        end
        e(:,lastomg:end) = P(:,:,lastomg)\e(:,lastomg:end);        
        e = e(:).';

    end
% dofilter().

%**************************************************************************
    function [K,V] = dominusloglik()
        sumlogdetOmg = 0;
        for ii = 1 : lastomg-1
            sumlogdetOmg = sumlogdetOmg + log(det(Omg(:,:,ii)));
        end
        sumlogdetOmg = sumlogdetOmg ...
            + (nper-lastomg+1)*log(det(Omg(:,:,lastomg)));
        if OPT.relative
            nobs = nper*size(Omg,1);
            V = W / nobs;
            W = nobs;
            sumlogdetOmg = sumlogdetOmg + nobs*log(V);   
        else
            V = 1;
        end
        sumlogdetT = 0;
        for ii = 1 : nper
            sumlogdetT = sumlogdetT + log(abs(det(T(:,:,ii))));
            if ~isfinite(sumlogdetT)
                K = Inf;
                return
            end
        end
        K = (sumlogdetOmg + W)/2 - sumlogdetT;
        if ~isfinite(K)
            K = Inf;
            return
        end
    end
% dominusloglik().

end