function [AR,E]=verrref(A)
%    VERRREF        Verified reduced row-echelon form (RREF) of a rectangular real matrix.
%
%    This is an INTLAB file. It requires to have INTLAB installed under
%    MATLAB to function properly.
%
%    For a rectangular real matrix A,
%        [AR,E]=verrref(A)
%    computes a verified reduced row-echelon form (RREF) AR of A. In
%    particular, the number of nonzero rows of AR yields the verified rank
%    of A. The result is not computed by Gaussian elimination, which
%    contributes to its accuracy. If no verified result is found, then AR
%    consists of NaN's.
%
%    The structure E explains reasons for NaN output.
%
%    See also RREF, VERFULLCOLRANK, RANK, VERRANK, VERPINV.

%    Copyright 2008 Jiri Rohn.
%
%    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-04-13   first version
%    2008-04-19   version for posting
%
gr=getround;
setround(0);
[m,n]=size(A);
AR=repmat(intval(NaN),m,n);
E.error='verrref: none';
E.where='NaN';
E.value='NaN';
if (nargin~=1)||(nargout>2)||~isreal(A)||isintval(A)
    E.error='verrref: wrong data';
    setround(gr); return
end
if issparse(A)
    A=full(A); % sparse not implemented
end
[AR,K]=rref(A); % K index set of the expected basis (later B)
K=sort(K); % increasing order, to be sure
if isempty(K) % no basis index set found
    AR=repmat(intval(NaN),m,n);
    E.error='verrref: no basis index set found';
    setround(gr); return
end
% K nonempty
B=A(:,K); % expected basis
fcr=verfullcolrank(B);
if fcr~=1 % columns of B not verified linearly independent
    AR=repmat(intval(NaN),m,n);
    E.error='verrref: columns of expected basis B not verified linearly independent';
    setround(gr); return
end
% columns of B verified linearly independent
r=length(K);
AR=repmat(intval(0),m,n);
Ir=intval(eye(r,r));
for j=1:n
    if ~any(K==j) % j not in K
        B0=A(:,K(find(K<j))); % repaired 2008-04-19
        fcr=verfullcolrank([B0 A(:,j)]);
        if fcr~=0 % columns of [B0 A(:,j)] not verified linearly dependent
            AR=repmat(intval(NaN),m,n);
            E.error='verrref: j-th column of A not verified to belong to the range space of B0';
            E.where=['j = ',int2str(j)];
            setround(gr); return
        end
        % A(:,j) verified to belong to the range space of B0
        B0p=verpinv(B0);
        if isnan(B0p.inf(1,1)) % pseudoinverse of B0 not computed
            AR=repmat(intval(NaN),m,n);
            E.error='verrref: pseudoinverse of B0 not computed';
            E.where=['j = ',int2str(j)];
            setround(gr); return
        end
        % pseudoinverse of B0 computed (intval quantity)
        C=B0p*A(:,j); % intval quantity
        AR(1:length(C),j)=C;
    else % j in K
        i=find(K==j); % j at the i-th place of K
        C=Ir(:,i);
        AR(1:length(C),j)=C;
    end
end
% first enclosure AR found
% as a by-product, r is the verified rank of A
% second enclosure
C=AR(1:r,:); % first r rows of AR (A=B*C forms rank decomposition now)
B=intval(B);
BTBi=inv(B'*B);
if isnan(BTBi.inf(1,1)) % inverse not computed
    E.where='only first enclosure outputed';
    setround(gr); return % first enclosure outputed
end
% inverse computed
C1=BTBi*B'*A; % A=B*C implies B'*A=B'*B*C implies C=inv(B'*B)*B'*A
C2=intersect(C,C1); % intersection of the two enclosures
if any(any(isnan(C2))) % to be sure
    E.where='only first enclosure outputed';
    setround(gr); return % first enclosure outputed
else
    AR(1:r,:)=C2; % intersection outputed
end
% AR verified RREF of A
setround(gr);