function [pd,x,E]=verpd(A)
%    VERPD    Verified positive definiteness of a real matrix.
%
%    For a symmetric real (not interval) matrix A,
%        [pd,x,E]=verpd(A)
%    verifies positive definiteness or not-positive-definiteness of A,
%    or yields no verified result:
%
%    pd= 1 :     A verified positive definite,
%    pd= 0 :     A verified not to be positive definite, and x is a nonzero real
%                vector verified to satisfy x'*A*x<=0 (a "certificate"),
%    pd=-1 :     no verified result.
%
%    If pd~=0, then x is a vector of NaN's.
%
%    The structured array E explains reasons for NaN output. It has three fields:
%    E.error, E.where, E.value.
%
%    See also ISSPD, VERPOSDEF.

%    Copyright 2007-2008 Jiri Rohn.
%    The routine ISSPD copyrighted by Siegfried M. Rump.
%
%    Positive definiteness is first checked by ISSPD. If the test fails,
%    not-positive-definiteness is checked by repeated use of the 2-by-2
%    condition. If this fails, VEREIG is brought in to judge
%    (not-)positive definiteness from verified eigenvalues. If even this
%    fails, finally an attempt is made at finding through random search
%    a real vector x verified to satisfy x'*A*x<=0.
%
%    This work was supported by the Czech Republic National Research
%    Program "Information Society", project 1ET400300415.
%
%    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
%
%    2007, Spring   created as a part of VERQUADPROG
%    2008-05-20     made independent
%    2008-05-21     eigenvalue part added
%    2008-11-16     output variable E added, vereig called instead of ol
%    2008-11-22     final version (html copy)
%
gr=getround;
setround(0);
% checking data
n=size(A,1);
pd=-1;
x=repmat(NaN,n,1);
E.error='verpd: none';
E.where='NaN';
E.value='NaN';
if ~isreal(A)||isintval(A)
    E.error='verpd: matrix not real or of type intval';
    setround(gr); return
end
if ~isequal(A,A')
    E.error='verpd: matrix not symmetric';
    setround(gr); return
end
% verifying positive definiteness via isspd
if isspd(A)==1                                        % routine isspd by S. M. Rump
    pd=1;                                             % verified positive definite
    setround(gr); return
end
% verifying not-positive-definiteness via the 2x2 condition (see e.g. Golub and van Loan)
A=infsup(A,A);
for i=1:n
    if A.sup(i,i)<=0                                  % diagonal entry nonpositive
        pd=0;                                         % verified not positive definite
        x=zeros(n,1); x(i)=1;
        setround(gr); return
    end
    for j=i+1:n
        a=A(i,i)+A(j,j)-2*A(i,j);
        if a.sup<=0                                   % 2x2 condition not satisfied
            pd=0;                                     % verified not positive definite
            x=zeros(n,1); x(i)=1; x(j)=-1;
            setround(gr); return
        end
        a=A(i,i)+A(j,j)+2*A(i,j);
        if a.sup<=0                                   % 2x2 condition not satisfied
            pd=0;                                     % verified not positive definite
            x=zeros(n,1); x(i)=1; x(j)=1;
            setround(gr); return
        end
    end
end
% verifying (not-)positive-definiteness via vereig
[L,X]=vereig(A);
lam=diag(L);
if ~isnan(lam.inf(1))                                 % eigenvalues computed
    if lam.inf(1)>0
        pd=1;                                         % verified positive definite (all eigenvalues verified positive)
        setround(gr); return
    end
    if lam.sup(1)<=0
        a=X(:,1)'*A*X(:,1);
        if a.sup<=0
            pd=0;                                     % verified not positive definite (minimal eigenvalue verified nonpositive)
            x=X(:,1);
            setround(gr); return
        end
    end
end
% finally, trying to find a random x satisfying x'*A*x<=0
for i=1:max(n,1e03)
    x=2*rand(n,1)-1;
    while isequal(x,zeros(n,1))
        x=2*rand(n,1)-1;
    end
    a=x'*A*x;
    if a.sup<=0                                       % x'*A*x verified nonpositive
        pd=0;                                         % verified not positive definite
        setround(gr); return
    end
end
% all tests failed
pd=-1;
x=repmat(NaN,n,1);                                    % no verified result
E.error='verpd: failure';
setround(gr);
% end of verpd
%