function srd=srdCV(data)
%SRDCV: SRD cross-validation 
%==========================================================================
% INPUT:
% [1] data: struct with all of the input parameters 
%     (see srdPreProcess.m for details)
% OUTPUT:
% [1] srd: struct of SRD results.  Depends on value of data.cv
%     - If 'none', then srd is simply the struct returned by srdMatrix.m
%     - If 'classic', then srd is ( N x 1 ) array of structs 
%       (where N=data.nIterations is the number of folds) such that 
%       srd(i) are SRD results returned by srdMatrix.m for ith fold
%     - If 'lmo', then srd is ( N x 1 ) array of structs
%       (where N=data.nIterations is number of LMO iterations) such 
%       that srd(i) are SRD results returned by the ith LMO iteration
%==========================================================================

switch data.cv
    case 'none'
        % NO cross validation
        srd=srdMatrix(data.A,data.T,data.exact);
    case 'classic'
        nFold=data.nIteration;
        % Create the group ids for each block and concatenate them
        g=classicGroup(data.nRow,nFold);
        % Perform CV per fold
        srd=classicFold(data,g,1);
        srd=repmat(srd,nFold,1);        % Initialize SRD struct array 
        for fold=2:nFold, srd(fold)=classicFold(data,g,fold); end; 
    case 'lmo'
        nIteration=data.nIteration;
        srd=lmoIteration(data,1);  
        srd=repmat(srd,nIteration,1);          % Initialize SRD struct array
        for i=2:nIteration, srd(i)=lmoIteration(data,i); end;
end
%==========================================================================
end

%
%--------------------------------------------------------------------------
%
% FUNCTION FOR CLASSIC CROSS-VALIDATION
%
%--------------------------------------------------------------------------
%

function [g,nFold]=classicGroup(nRow,nFold)
%==========================================================================
nBlock=length(nRow);
if nFold > min(nRow)
    n=sum(nRow);
    g=rem((0:n-1)',nFold)+1;
else    
    g=cell(nBlock,1);
    for i=1:nBlock
        n=nRow(i);
        gBlock=rem((0:n-1)',nFold)+1;
        g{i}=sort(gBlock);
    end
    g=srdStack(g); 
end
%==========================================================================
end

function srd=classicFold(data,g,fold)
% SRDs per CV fold
%==========================================================================
fprintf('Fold=%d\n',fold);
rows=(g~=fold);
srd=srdMatrix(data.A(rows,:),data.T(rows),data.exact);
m=size(data.A,1); 
srd.samples=zeros(m,1); srd.samples(rows)=1;
%==========================================================================
end


%
%--------------------------------------------------------------------------
%
% FUNCTION FOR LEAVE-MULTIPLE-OUT (LMO) ITERATIONS
%
%--------------------------------------------------------------------------
%

function srd=lmoIteration(data,iter)
% SRDs per LMO iteration
%==========================================================================
fprintf('Iteration=%d\n',iter);
rows=lmoRows(data);
srd=srdMatrix(data.A(rows,:),data.T(rows),data.exact);
m=size(data.A,1); 
srd.samples=zeros(m,1); srd.samples(rows)=1;
%==========================================================================
end

function rows=lmoRows(data)
%==========================================================================
rows=cell(data.nBlock,1);
if data.allMix
    for i=1:data.nBlock
        rows{i}=lmoBlockRows(data,i);  
        if (i > 1)
            nPreviousRows=sum(data.nRow(1:i-1));
            rows{i}=rows{i} + nPreviousRows;
        end
    end    
else    
    for i=1:data.nBlock
        if (i==1)
            rows{1}=lmoBlockRows(data,i);
        else
            nPreviousRows=sum(data.nRow(1:i-1));
            rows{i}=rows{1} + nPreviousRows;
        end
    end
end    
rows=srdStack(rows); 
%==========================================================================
end

function rows=lmoBlockRows(data,i)
%==============================================
n=data.nRow(i);
shuffle=randperm(n);
nKeep=round( (1-data.percent/100)*n );
rows=shuffle(1:nKeep);
rows=rows(:);
%==============================================
end
     