function [F,E]=vermatfun(f,A,r)
%    VERMATFUN        Verified matrix function of a complex (or real) matrix.
%
%    This is an INTLAB file. It requires to have INTLAB installed under
%    MATLAB to function properly.
%
%    For a complex (or real) function f of one variable and for a square
%    complex (or real) matrix A,
%        [F,E]=vermatfun(f,A)
%    computes a verified enclosure F of the matrix function f(A), or fails
%    (yields a matrix of NaN's).
%
%    f must be given as an inline function (i.e., an expression between
%    apostrophes), as e.g. in
%        F=vermatfun('(1+x)/x',A).
%
%    The output F is typically a complex interval matrix even if the exact
%    result is real. If you know beforehand that the result is real (as it
%    is e.g. with the functions exp(x), sin(x), cos(x) etc. for real
%    argument), use
%        F=vermatfun(f,A,1)
%    for real output.
%
%    The structured array E explains reasons for NaN output. It has three
%    fields: E.error, E.where, E.value.
%
%    EXAMPLE (Golub and van Loan [1], p. 567).
%    >> A =
%       -49    24
%       -64    31
%    >> format long, F=vermatfun('exp(x)',A,1)
%    intval F =
%    [  -0.73575875814481,  -0.73575875814470] [   0.55181909965806,   0.55181909965814]
%    [  -1.47151759908836,  -1.47151759908816] [   1.10363824071549,   1.10363824071565]
%
%    [1] G. H. Golub and C. V. van Loan, Matrix Computations, The Johns
%    Hopkins University Press, Baltimore 1996.

%    Copyright 2008 Jiri Rohn.
%
%    Based of the fact that if
%        A=X*L*inv(X)
%    is an eigenvalue decomposition of a diagonalizable matrix A, then
%        f(A)=X*f(L)*inv(X)
%    (see [1], Corollary 11.1.2).
%
%    WARRANTY
%
%    Because the program is licensed free of charge, there is
%    no warranty for the program, to the extent permitted by applicable
%    law. Except when otherwise stated in writing the copyright holder
%    and/or other parties provide the program "as is" without warranty
%    of any kind, either expressed or implied, including, but not
%    limited to, the implied warranties of merchantability and fitness
%    for a particular purpose. The entire risk as to the quality and
%    performance of the program is with you. Should the program prove
%    defective, you assume the cost of all necessary servicing, repair
%    or correction.
%
%    History
%
%    2008-03-23   first version
%    2008-03-31   output variable E added; version for posting
%
gr=getround;
setround(0);
[m,n]=size(A);
F=repmat(infsup(NaN,NaN),n,n);
E.error='vermatfun: none';
E.where='NaN';
E.value='NaN';
if ~(2<=nargin&&nargin<=3&&nargout<=2&&m==n&&~isintval(A)) % wrong data
    E.error='vermatfun: wrong data';
    setround(gr); return
end
if issparse(A)
    A=full(A); % sparse matrices not implemented yet
end
[L,X]=ol(A); % main part
if isnan(L.inf(1,1)) % no result
    E.error='vermatfun: ol fails: eigenvalue decomposition not computed';
    setround(gr); return
end
Y=inv(X);
if isnan(Y.inf(1,1)) % inverse not found
    E.error='vermatfun: inv fails: inverse not computed';
    setround(gr); return
end
% X, L, Y computed
f=inline(f);
LL=L; % preallocation
for j=1:n
    LL(j,j)=f(L(j,j)); % LL=f(L)
    if isinf(LL(j,j))||isnan(LL(j,j))
        E.error='vermatfun: function value not finite';
        E.where=['j = ',int2str(j)];
        E.value=['LL(j,j) = [',num2str(LL(j,j).inf),', ',num2str(LL(j,j).sup),']'];
        setround(gr); return
    end
    X(:,j)=LL(j,j)*X(:,j); % X=X*LL
end
F=X*Y; % F=X*LL*Y=X*f(L)*inv(X) (basic formula)
if isequal(nargin,3)&&isequal(r,1) % case of real result
    F=real(F);
end
setround(gr);