% DEMCLASSIFICATIONSVARGPLVM
% COPYRIGHT Andreas C. Damianou, 2012
% SEEALSO: demClassificationSvargplvm2, demClassificationSvargplvm3,  demClassificationSvargplvm4
% VARGPLVM

% clear;scale2var1 = 1;dataPerClass = 10;initial_X = 'together';itNo =
% [];indPoints = 30; initVardistIters = 300;latentDim = 6;demClassificationSvargplvm

% Fix seeds
randn('seed', 1e5);
rand('seed', 1e5);
if ~exist('onlyTest'), onlyTest = false; end
if exist('diaryFile'),    diary(diaryFile), end
if ~exist('doPredictions'),    doPredictions = false; end
if ~exist('testDataPerClass'), testDataPerClass = 100; end
if ~exist('printPlots'), printPlots = true; end

addpath(genpath('../../bc-vargplvm/matlab'));
addpath(genpath('../../vargplvm/matlab'));

% This script initialises the options structure 'globalOpt'.
svargplvm_init;

if onlyTest
    load(['demOilSvargplvm' num2str(experimentNo)]);
    globalOpt = model.globalOpt;
end

globalOpt.dataSetNames = {'oilData', 'oilLabels'};
globalOpt.dataSetName = 'oil';

if exist('timeStamps')
    [globalOpt, YtrAll] = bc_loadData(globalOpt, timeStamps);
else
    [globalOpt, YtrAll] = bc_loadData(globalOpt);
end
Yall{1} = YtrAll.Y;
lblsTrain = YtrAll.lbls;
labelsTrain = transformLabels(lblsTrain);
% ---- We want labels with -1 and 1, not 0 and 1 (anti-correlation)
YtrAll.lbls(YtrAll.lbls == 0) = -1;
Yall{2} = YtrAll.lbls;

globalOptTest = globalOpt;
globalOptTest.dataPerClass = testDataPerClass;
globalOptTest.dataSetName = 'oilTest';
if exist('timeStamps')
    [globalOptTest, YtsAll] = bc_loadData(globalOptTest, timeStamps);
else
    [globalOptTest, YtsAll] = bc_loadData(globalOptTest);
end
lblsTest = YtsAll.lbls;
labelsTest = transformLabels(lblsTest);
Yts{1} = YtsAll.Y;
YtsAll.lbls(YtsAll.lbls == 0) = -1;
Yts{2} = YtsAll.lbls;

if isfield(globalOpt, 'normaliseData') && globalOpt.normaliseData
    Yall{1} = utils_normaliseData(Yall{1});
    Yts{1} = utils_normaliseData(Yts{1});
end

if onlyTest
    model = svargplvmRestorePrunedModel(model, Yall);
end

numberOfDatasets = length(Yall);

% globalOpt.baseKern = {'rbfardjit', 'linard2'};

%globalOpt.baseKern = {'rbfardjit', 'rbfardjit'};

globalOpt.indPoints = min(globalOpt.indPoints, size(Yall{1},1));

%-- Load datasets
for i=1:numberOfDatasets
    Y = Yall{i};
    dims{i} = size(Y,2);
    N{i} = size(Y,1);
    indTr = globalOpt.indTr;
    if indTr == -1
        indTr = 1:N{i};
    end
    if ~exist('Yts')
        indTs = setdiff(1:size(Y,1), indTr);
        Yts{i} = Y(indTs,:);
    end
    Ytr{i} = Y(indTr,:);

    t{i} = linspace(0, 2*pi, size(Y, 1)+1)'; t{i} = t{i}(1:end-1, 1);
    timeStampsTraining{i} = t{i}(indTr,1); %timeStampsTest = t(indTs,1);
end

for i=2:numberOfDatasets
    if N{i} ~= N{i-1}
        error('The number of observations in each dataset must be the same!');
    end
end

%%
if ~onlyTest
    % Free up some memory
    clear('Y')

    options = svargplvmOptions(Ytr, globalOpt, labelsTrain);

    if ~isempty(globalOpt.dynamicsConstrainType)
        for i=1:numberOfDatasets
            % Set up dynamcis (i.e. back-constraints) model
            optionsDyn{i}.type = 'vargpTime';
            optionsDyn{i}.inverseWidth=30;
            %   optionsDyn.vardistCovars = vardistCovarsMult;
            optionsDyn{i}.initX = globalOpt.initX;
            optionsDyn{i}.constrainType = globalOpt.dynamicsConstrainType;

            if exist('timeStampsTraining')
                optionsDyn{i}.t = timeStampsTraining;
            end
            if exist('labelsTrain') && ~isempty(labelsTrain)
                optionsDyn{i}.labels = labelsTrain;
            end
        end
    else
        optionsDyn= [];
    end

    model = svargplvmModelCreate(Ytr, globalOpt, options, optionsDyn);
    if exist('diaryFile')
        model.diaryFile = diaryFile;
    end

    model.globalOpt = globalOpt;
    model.options = options;

    %-- Define what level of parallelism to use (w.r.t submodels or/and w.r.t
    % datapoints).
    %{
fprintf('# Parallel computations w.r.t the submodels!\n');
model.parallel = 1;
model = svargplvmPropagateField(model,'parallel', 1);
%
fprintf('# Parallel computations w.r.t the datapoints!\n');
model.vardist.parallel = 1;
for i=1:model.numModels
    model.comp{i}.vardist.parallel = 1;
end
    %}

            %%%% TEMP
    if exist('whiteVar')
        fprintf('aaa\n\n\n')
        model.dynamics.kern.comp{2}.variance = whiteVar;
    end
    %%%%

    % Force kernel computations
    params = svargplvmExtractParam(model);
    model = svargplvmExpandParam(model, params);

    %%
    fprintf('# Median of vardist. covars: %d \n',median(median(model.vardist.covars)));
    fprintf('# Min of vardist. covars: %d \n',min(min(model.vardist.covars)));
    fprintf('# Max of vardist. covars: %d \n',max(max(model.vardist.covars)));

    model = svargplvmOptimiseModel(model);

    svargplvmShowScales(model)
    figure
end

%%
    capName = model.globalOpt.dataSetName;
    capName(1) = upper(capName(1));
    errors = fgplvmNearestNeighbour(model.comp{1}, lblsTrain);
    model2 = vargplvmReduceModel(model.comp{1}, 2);
    errors2 = fgplvmNearestNeighbour(model2, lblsTrain);
    fprintf('# Visualisation errors in all dims/in 2D:  %d / %d\n', errors, errors2)
    if printPlots
        vargplvmPrintPlot(model2, lblsTrain, [capName 'Vargplvm'], model.globalOpt.experimentNo);

        %%
        % For 3D plots:
         labels = labelsTrain; dims = [1 2 3];
         plot3k({model.X(:,dims(1)) model.X(:,dims(2)) model.X(:,dims(3))}, 'ColorData', labels, 'Marker', {'x',6});
    end

%%
obsMod = 1; % one of the involved sub-models (the one for which we have the data)
infMod = setdiff(1:2, obsMod);

sharedDims = svargplvmFindSharedDims(model);

%---------------------------- PREDICTIONS ---------------
if ~doPredictions
    return
end

%%

if ~exist('testOnTraining')
    testOnTraining=0;
end

%--------------------%
svargplvmPredictions %---- Script returning: ZpredMuAll and mini(the indices for NN)
%--------------------%

%--- For classification we are interested in labels
ZpredMuAll(ZpredMuAll > 0) = 1;
ZpredMuAll(ZpredMuAll < 0) = -1;
NNpred = Ytr{infMod}(mini,:);
realLabels = lblsTest(testInd,:);

% Find the error in the labels ------------
[labelErrors, labelSharingErrors, wrongIndices] = findLabelErrors(realLabels, ZpredMuAll);
[labelErrorsNN, void, wrongIndicesNN] = findLabelErrors(realLabels,NNpred);

fprintf('# Gplvm label errors: %d\n', labelErrors);
fprintf('# Gplvm label sharing errors: %d\n', labelSharingErrors);
fprintf('# NN label errors:    %d\n', labelErrorsNN);

% Confusion matrix
cmat_a = confMatrix( XpredAll, model.X, labelsTrain, labelsTest, 1);
cmat_rel = cmat_a ./ repmat(sum(cmat_a, 2), 1, length(unique(labelsTrain)));
cmat_rel


function varargout = drawSquareMesh(nodes, edges, faces, varargin) %#ok<INUSL>
%DRAWSQUAREMESH Draw a 3D square mesh given as a graph
%
%   drawSquareMesh(NODES, EDGES, FACES)
%   Draw the mesh defined by NODES, EDGES and FACES. FACES must be a N-by-4
%   array of vertex indices.
%
%   See Also
%   boundaryGraph, drawGraph
%
%   ---------
%   author: David Legland
%   INRA - TPV URPOI - BIA IMASTE
%   created the 28/06/2004.
%

% input size check up
if size(faces, 2) ~= 4
    error('Requires a face array with 4 columns');
end

% number of faces
Nf = size(faces, 1);

% allocate memory for vertex coordinates
px = zeros(4, Nf);
py = zeros(4, Nf);
pz = zeros(4, Nf);

% initialize vertex coordinates of each face
for f = 1:Nf
    face = faces(f, 1:4);
    px(1:4, f) = nodes(face, 1);
    py(1:4, f) = nodes(face, 2);
    pz(1:4, f) = nodes(face, 3);
end

p = patch(px, py, pz, 'r');

if nargout > 0
    varargout = {p};
end


function vizLineRpts(ax,data,fld1,fld2,line)
% vizLineRpts(ax,data,fld1,fld2,line)
% Visualize experimental repeats for given stat/line.
%
% data: data struct
% fld1: field for x-axis of scatterplot. Defaults to day_num.
% fld2: field for y-axis of scatterplot
% line: line to visualize

if isempty(ax)
    figure;
    ax = axes;
end

if isempty(fld1)
    fld1 = 'day_num';
end

tfLine = strcmp({data.line_name}',line);
tmpGF = {data.bdpOrNot}';
%tmpGF = repmat({'not'},numel(tfLine),1);
tmpGF(tfLine) = {line};

axes(ax);
x = OlyDat.Analysis.getNumericScalarFieldSafe(data,fld1);
y = OlyDat.Analysis.getNumericScalarFieldSafe(data,fld2);
h = gscatter(x,y,tmpGF);
set(h(1),'MarkerEdgeColor',[0.75 0.75 0.75]);
set(h(2),'MarkerEdgeColor',[0.3 0.3 0.8]);
set(h(3),'MarkerEdgeColor',[1 0 0],'MarkerSize',14);
hLeg = legend;
set(hLeg,'interpreter','none');
xlabel(fld1,'interpreter','none','FontWeight','bold');
ylabel(fld2,'interpreter','none','FontWeight','bold');
titlestr = sprintf('%s: %d exps',line,nnz(tfLine));
title(titlestr,'interpreter','none','FontWeight','bold');
grid on;

% plot ctl mean, std in x- and y- dirs
hold on;
tfCtl = [data.tfBDP]';
xCtl = [data(tfCtl).(fld1)];
yCtl = [data(tfCtl).(fld2)];
mux = mean(xCtl);
sdx = std(xCtl);
lox = mux-2*sdx;
hix = mux+2*sdx;
muy = mean(yCtl);
sdy = std(yCtl);
loy = muy-2*sdy;
hiy = muy+2*sdy;
%plot(mux,muy,'ob','MarkerSize',14,'MarkerFaceColor',[0 0 1]);
% plot([lox hix],[loy loy],'b');
% plot([lox hix],[hiy hiy],'b');
% plot([lox lox],[loy hiy],'b');
% plot([hix hix],[loy hiy],'b');
hold off;


function [imX,imY,imZ] = dtiSaveImageSlicesOverlays(handles, overlayFGs, overlayROIs, queryParameters, fname, upSamp, curPosAcpc, bg)
%
%   dtiSaveImageSlicesOverlays(handles,[overlayFGs=[]],[overlayROIs=[]],[queryParameters=0],[fname],[upSamp])
%
%Author: Dougherty, Wandell
%Purpose:
%   Save out image slices.  Potentially we overlay the FGs and ROIs.
%   Potentially we query for the image processing parameters
%
% Examples:
%   dtiSaveImageSlicesOverlays(handles)       %Just slices, no overlays
%   dtiSaveImageSlicesOverlays(handles,1,0)   % Overlay fiber groups
%   dtiSaveImageSlicesOverlays(handles,1,0,1) % Overlay fiber groups and
%              query for imaging parameters

if ieNotDefined('overlayFGs'),  overlayFGs = []; end
if ieNotDefined('overlayROIs'), overlayROIs = []; end
if ieNotDefined('queryParameters'), queryParameters = 1; end
if(~exist('upSamp','var') | isempty(upSamp)) upSamp = 4; end
if(~exist('curPosAcpc','var') | isempty(curPosAcpc)) curPosAcpc = dtiGet(handles, 'acpcpos'); end
skipAxes = isnan(curPosAcpc);
curPosAcpc(skipAxes) = 0;
if(~exist('bg','var') | isempty(bg))
    bg = handles.bg(dtiGet(handles,'curbgnum'));
    bg.acpcToImgXform = dtiGet(handles, 'acpc2imgxform');
    bg.mmPerVox = bg.mmPerVoxel;
end

% May want to interpolate here...
curPosImgInt = round(mrAnatXformCoords(bg.acpcToImgXform, curPosAcpc));

if(size(bg.img,4)==3)
	% Special case for vector images
	z = squeeze(bg.img(:,:,curPosImgInt(3),:));
	y = squeeze(bg.img(:,curPosImgInt(2),:,:));
	x = squeeze(bg.img(curPosImgInt(1),:,:,:));
else
    z = repmat(squeeze(bg.img(:,:,curPosImgInt(3))),[1,1,3]);
    y = repmat(squeeze(bg.img(:,curPosImgInt(2),:)),[1,1,3]);
    x = repmat(squeeze(bg.img(curPosImgInt(1),:,:)),[1,1,3]);
end

curPosImg = mrAnatXformCoords(bg.acpcToImgXform, curPosAcpc);
if(~exist('fname','var')) fname = ''; end

% Maybe the user wanted to set the parameters
roiBlurSize = 0;
fgBlurSize = 0;
if queryParameters
    prompt={'Upsample factor (1,2,4,8,16):','ROI blur size:','Fiber blur size:'};
    def={num2str(upSamp),num2str(roiBlurSize),num2str(fgBlurSize)};
    dlgTitle='Image processing parameters';
    lineNo=1;
    answer=inputdlg(prompt,dlgTitle,lineNo,def);
    if isempty(answer), disp('dtiSaveImageSlice cancelled.'); return;
    else
        upSamp = str2num(answer{1});
        roiBlurSize = str2num(answer{2});
        fgBlurSize = str2num(answer{3});
    end
end

% Figure out the file
persistent imPath;
if(nargout==0 & isempty(fname))
    if(isempty(imPath)) imPath = fullfile(handles.defaultPath,'slice'); end
    [p,f,e] = fileparts(imPath);
    imPath = fullfile(p,f);
    [f, p] = uiputfile({'*.png'}, ['Save current view...'], imPath);
    if(isnumeric(f)), disp('dtiSaveImageSlices cancelled.'); fname = 'show';
    else [junk,f,e] = fileparts(f); fname = fullfile(p, f); end
end
imPath = fname;

% Start image processing code
upSamp = 2^round(log2(upSamp));

% Resizing the image
imX = imageResize(x,upSamp);
imY = imageResize(y,upSamp);
imZ = imageResize(z,upSamp);

% Which order?  Put down the ROI, then overlay the fibers on top of that.
if(~isempty(overlayROIs))
    [imX,imY,imZ] = dtiImageOverlayROIs(overlayROIs,upSamp,roiBlurSize,imX,imY,imZ,curPosImg,bg.acpcToImgXform);
end
if(~isempty(overlayFGs))
    [imX,imY,imZ] = dtiImageOverlayFGs(overlayFGs,upSamp,fgBlurSize,imX,imY,imZ,curPosImg,bg.acpcToImgXform);
end

imX = permute(imX,[2,1,3]);
imY = permute(imY,[2,1,3]);
imZ = permute(imZ,[2,1,3]);

for(ii=1:3)
    imX(:,:,ii) = flipud(imX(:,:,ii));
    imY(:,:,ii) = flipud(imY(:,:,ii));
    imZ(:,:,ii) = flipud(imZ(:,:,ii));
end

% Add a scale bar
cmBarLen = round(1/bg.mmPerVox(1) * 10 * upSamp);
cbarVal = max(imX(:));
imX(end-5, end-cmBarLen-5:end-5, :) = cbarVal;
imX(end-4, end-cmBarLen-5:end-5, :) = cbarVal;
cmBarLen = round(1/bg.mmPerVox(2) * 10 * upSamp);
cbarVal = max(imY(:));
imY(end-5, end-cmBarLen-5:end-5, :) = cbarVal;
imY(end-4, end-cmBarLen-5:end-5, :) = cbarVal;
cmBarLen = round(1/bg.mmPerVox(3) * 10 * upSamp);
cbarVal = max(imZ(:));
imZ(end-5, end-cmBarLen-5:end-5, :) = cbarVal;
imZ(end-4, end-cmBarLen-5:end-5, :) = cbarVal;

if(~isempty(fname))
    if(strcmp(fname,'show'))
        figure; image(imX./max(imX(:))); axis image; truesize;
        figure; image(imY./max(imY(:))); axis image; truesize;
        figure; image(imZ./max(imZ(:))); axis image; truesize;
    else
        imwrite(imX, [fname '_X.png']);
        disp(['Wrote X slice to ' fname '_X.png']);
        imwrite(imY, [fname '_Y.png']);
        disp(['Wrote Y slice to ' fname '_Y.png']);
        imwrite(imZ, [fname '_Z.png']);
        disp(['Wrote Z slice to ' fname '_Z.png']);
    end
end
return;

%------------------------------------------------
function imOut = imageResize(im,m)
%
%   imOut = imageResize(im,m)
%
%Author: Wandell, Dougherty
%Purpose:
%   Resize an RGB image.  Uses the local upSample/upConv code.
%

sz = size(im);
m = round(log2(m));
for ii=1:3, imOut(:,:,ii) = upSample(im(:,:,ii),m); end

% Old, slow code
% sz = size(im);
% newSize = [sz(1), sz(2)]*m;
% imOut = zeros(newSize);
% for ii=1:3
%     imOut(:,:,ii) = imresize(im(:,:,ii),newSize,'bilinear');
% end
% return;

return;

%-----------------------------------------------------
function [imX,imY,imZ] = dtiImageOverlayFGs(overlayFGs,upSamp,blurSize,imX,imY,imZ,curPosImg,acpcToImgXform)
%
%        [imX,imY,imZ] = dtiImageOverlayFGs(handles,upSamp,blurSize,imX,imY,imZ,curPosImg,acpcToImgXform)
%
%Author: Dougherty, Wandell
%Purpose:
%   Add the fiber group positions to the image
%   It might be possible to upsample differently in the three dimensions.
%   But for now, we only upsample the whole data set with a single upSamp
%   value.
%

if ieNotDefined('upSamp'), upSamp = 1; end
if ieNotDefined('blurSize'), blurSize = 0; end

fpX = []; fpColorX = [];
fpY = []; fpColorY = [];
fpZ = []; fpColorZ = [];
for(grpNum=1:length(overlayFGs))
    if(overlayFGs(grpNum).visible)
        fp = horzcat(overlayFGs(grpNum).fibers{:});
        fp = mrAnatXformCoords(acpcToImgXform, fp');
        fiberColor = overlayFGs(grpNum).colorRgb/255;
        if(~isempty(fp))
            % Select those fiber points that are in this slice
            sfpX = fp(round(fp(:,1))==round(curPosImg(1)), [2,3])-1;
            sfpX = unique(round(sfpX.*upSamp),'rows');
            if(~isempty(sfpX))
                [mem,loc] = ismember(sfpX, fpX, 'rows');
                if(any(mem))
                    overlap = loc(loc>0);
                    for(ii=1:3)
                        fpColorX(overlap,ii) = fpColorX(overlap,ii)*0.5 + fiberColor(ii);
                    end
                end
                fpX = vertcat(fpX,sfpX(~mem,:));
                fpColorX = vertcat(fpColorX, repmat(fiberColor, sum(~mem), 1));
            end

            sfpY = fp(round(fp(:,2))==round(curPosImg(2)), [1,3])-1;
            sfpY = unique(round(sfpY.*upSamp),'rows');
            if(~isempty(sfpY))
                [mem,loc] = ismember(sfpY, fpY, 'rows');
                if(any(mem))
                    overlap = loc(loc>0);
                    for(ii=1:3)
                        fpColorY(overlap,ii) = fpColorY(overlap,ii)*0.5 + fiberColor(ii);
                    end
                end
                fpY = vertcat(fpY,sfpY(~mem,:));
                fpColorY = vertcat(fpColorY, repmat(fiberColor, sum(~mem), 1));
            end

            sfpZ = fp(round(fp(:,3))==round(curPosImg(3)), [1,2])-1;
            sfpZ = unique(round(sfpZ.*upSamp),'rows');
            if(~isempty(sfpZ))
                [mem,loc] = ismember(sfpZ, fpZ, 'rows');
                if(any(mem))
                    overlap = loc(loc>0);
                    for(ii=1:3)
                        fpColorZ(overlap,ii) = fpColorZ(overlap,ii)*0.5 + fiberColor(ii);
                    end
                end
                fpZ = vertcat(fpZ,sfpZ(~mem,:));
                fpColorZ = vertcat(fpColorZ, repmat(fiberColor, sum(~mem), 1));
            end
        end
    end
end

imX = dtiAddImageOverlay(imX, fpX, fpColorX, blurSize);
imY = dtiAddImageOverlay(imY, fpY, fpColorY, blurSize);
imZ = dtiAddImageOverlay(imZ, fpZ, fpColorZ, blurSize);

return;

%-----------------------------------------------------
function [imX,imY,imZ] = dtiImageOverlayROIs(overlayROIs,upSamp,blurSize,imX,imY,imZ,curPosImg,acpcToImgXform)
%
%   [imX,imY,imZ] = dtiImageOverlayROIs(overlayROIs,upSamp,blurSize,imX,imY,imZ,curPosImg,acpcToImgXform)
%
%Author: Dougherty, Wandell
%Purpose:
%   Add the ROI positions to the image
%

if ieNotDefined('upSamp'), error('upSamp required.'); end
if ieNotDefined('blurSize'), error('blurSize required.');; end

for(roiNum=1:length(overlayROIs))
    if(overlayROIs(roiNum).visible)
        roiPos = mrAnatXformCoords(acpcToImgXform, overlayROIs(roiNum).coords);
        roiColor =  dtiRoiGetColor(overlayROIs(roiNum));

        sroiPos = roiPos(round(roiPos(:,1))==round(curPosImg(1)),[2,3])';
        sroiPos = sroiPos.*upSamp;
        %sroiPosDilate = zeros(size(sroiPos,1)*upSamp,3);
        if(~isempty(sroiPos))
            % dilate up and to the left
            sroiPosDilate = [];
            for(ii=0:upSamp)
                for(jj=0:upSamp)
                    sroiPosDilate = [sroiPosDilate, [sroiPos(1,:)-ii; sroiPos(2,:)-jj]];
                end
            end
            imX = dtiAddImageOverlay(imX, round(sroiPosDilate)', roiColor, blurSize);
        end

        sroiPos = roiPos(round(roiPos(:,2))==round(curPosImg(2)),[1,3])';
        sroiPos = sroiPos.*upSamp;
        if(~isempty(sroiPos))
            sroiPosDilate = [];
            for(ii=0:upSamp)
                for(jj=0:upSamp)
                    sroiPosDilate = [sroiPosDilate, [sroiPos(1,:)-ii; sroiPos(2,:)-jj]];
                end
            end
            imY = dtiAddImageOverlay(imY, round(sroiPosDilate)', roiColor, blurSize);
        end

        sroiPos = roiPos(round(roiPos(:,3))==round(curPosImg(3)),[1,2])';
        sroiPos = sroiPos.*upSamp;
        if(~isempty(sroiPos))
            sroiPosDilate = [];
            for(ii=0:upSamp)
                for(jj=0:upSamp)
                    sroiPosDilate = [sroiPosDilate, [sroiPos(1,:)-ii; sroiPos(2,:)-jj]];
                end
            end
            imZ = dtiAddImageOverlay(imZ, round(sroiPosDilate)', roiColor, blurSize);
        end

    end
end

return;

%-----------------------------------------------------------
function newPts = dtiOverlayCoordXform(ax,upSamp,pts)
% Transform from acpc coordinates into image coordinates
newPts(2,:) = (-(ax(1,1) - pts(2,:)) + 1) *upSamp;
newPts(1,:) =  (ax(2,2) + (pts(1,:)  + 1)) *upSamp;
return;


function [eta,etaf]=v_finishat(frac,tol,fmt)
%V_FINISHAT print estimated finish time of a long computation (FRAC,TOL,FMT)
% Usage:  (1)  for i=1:many
%                  v_finishat((i-1)/many);  % initializes on first pass when i=1
%                  ... computation ...
%              end
%
%         (2)  for i=1:many
%                  v_finishat([i-1 many]);  % alternative argument format
%                  ... computation ...
%              end
%
%         (3)  v_finishat(0);               % explicit initialization before loop
%              for i=1:many
%                  ... computation ...
%                  v_finishat(i/many);      % calculate fraction completed
%              end
%
%         (4)  for i=1:NI
%                  for j=1:NJ
%                      for k=1:NK
%                          v_finishat([i NI; j NJ; k-1 NK]); % one row per nested loop
%                          ... computation ...
%                      end
%                  end
%              end
%
% Inputs: FRAC = fraction of total comutation that has been completed
%                Alternatively at start of inner loop: [i NI; j NJ; k-1 NK ...] where i, j, k are
%                loop indices and NI, NJ, NK their limits. Use k instead of k-1 if placed at
%                the end of the inner loop. As a special case, FRAC=0 initializes the routine.
%         TOL  = Tolerance in minutes. If the estimated time has changed by less
%                than this, then nothing will be printed. [default 10% of remaining time]
%         FMT  = Format string which should include %s for estimated finish time, %d for remaining minutes and %f for fraction complete
%
% Output: ETA  = string containing the expected finish time
%                specifying this will suppress printing message to std err (fid=2)
%         ETAF = expected finish time as a daynumber
%
% Example:       v_finishat(0);
%                for i=1:many
%                    long computation;
%                    v_finishat(i/many);
%                end

%      Copyright (C) Mike Brookes 1998
%      Version: $Id: v_finishat.m 10865 2018-09-21 17:22:45Z dmb $
%
%   VOICEBOX is a MATLAB toolbox for speech processing.
%   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   This program is free software; you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation; either version 2 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You can obtain a copy of the GNU General Public License from
%   http://www.gnu.org/copyleft/gpl.html or by writing to
%   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

persistent oldt oldnw
if nargin<3
    fmt='Estimated finish at %s (%.2f done, %d min remaining)\n';

end
nf=size(frac,1);
if all(frac(:,1)<=[ones(nf-1,1); 0]) % initialize if fraction done is <=0
    oldt=0;
    eta='Unknown';
    tic;
else
    if size(frac,2)==2
        fp=cumprod(frac(:,2));
        frac=sum((frac(:,1)-1)./fp)+1/fp(end);
    end
    nw=now;                             % current time as serial number
    sectogo=(1/frac-1)*toc;      % seconds to go
    newt=nw+sectogo/86400;       % add estimated time in days
    if nargin<2 || ~numel(tol)
        tol=max(0.1*(newt-nw)*1440,1);
    end
    if ~exist('oldt','var') || oldt==0 || (abs(newt-oldt)>tol/1440 && (nw-oldnw)>10/86400) || (nw-oldnw)>10/1440 || nargout>0
        oldt=newt;
        if floor(oldt)==floor(nw)
            df='HH:MM';
        else
            df='HH:MM dd-mmm-yyyy';
        end
        eta=datestr(oldt,df);
        if ~nargout
            ix=find(fmt=='%',1);
            while ~isempty(ix)
                fprintf(2,fmt(1:ix-1));
                fmt=fmt(ix:end);
                ix=find(fmt>='a' & fmt<='z',1); % find letter
                switch fmt(ix)
                    case 's'
                        fprintf(2,fmt(1:ix),eta);
                    case 'd'
                        fprintf(2,fmt(1:ix),round(sectogo/60));
                    case 'f'
                        fprintf(2,fmt(1:ix),frac);
                end
                fmt=fmt(ix+1:end);
                ix=find(fmt=='%',1);
            end
            fprintf(2,fmt);
        end
        oldnw=nw;                           %
    end
end
etaf=oldt;


function numVax = freadVAXG(fid, number, method)
% FREADVAXG Converts a number read in IEEE-LE format to its VAXG
% floating point representation.
%
% Usage:
%    fid = fopen('file.vaxg', 'r', 'ieee-le');
%    num = freadVAXG(fid, numElements, 'format')
%
% 'format' options are the same as FREAD.
%
%  The function is intended to be called by the user.
%
%   See also UINT32LE_TO_VAXF, UINT64LE_TO_VAXG, FREADVAXD

%   Copyright 2009 The MathWorks, Inc.

switch method
    case {'float32', 'single'}
      rawUINT32 = fread(fid,number,'uint32=>uint32');
      numVax = uint32le_to_VAXF( rawUINT32 );

    case {'float64', 'double'}
      rawUINT32 = fread(fid,2*number,'uint32=>uint32');%read 2 32bit numbers
      numVax = uint64le_to_VAXG(rawUINT32);

    case {'float'}
      if intmax == 2147483647 %32bit OS float is 32 bits
	     rawUINT32 = fread(fid,  number,'uint32=>uint32');
         numVax = uint32le_to_VAXF(rawUINT32);
      else
         rawUINT32 = fread(fid,2*number,'uint32=>uint32');%read 2 32bit numbers
         numVax = uint64le_to_VAXG(rawUINT32);
      end

    otherwise
      numVax    = fread(fid, number, method);

end

end


addpath(genpath('../mutils/My/'));
addpath(genpath('../ptv'));

%%
basepth = '../../data_prj/dir_dataset/DIR_files/';

TRE = zeros(10,1);
TIME = zeros(10,1);
TREstd = zeros(10,1);
TREc = zeros(10, 3);
TREcstd = zeros(10, 3);
opts = [];
opts.grid_spacing = [4, 4, 3];  % grid spacing in pixels
opts.display = 'off';
opts.k_down = 0.7;
opts.interp_type = 0;
opts.metric = 'nuclear';
opts.max_iters =  10;
opts.max_iters = 110;
opts.check_gradients = 100*0;
opts.interp_type = 0;

opts.spline_order = 1;

% opts.singular_coefs = sqrt(1:6);
% opts.singular_coefs(1) = 0;
opts.spat_reg_p_val = 0.75;
opts.jac_reg = 10;

opts.D1Lp = 1e-5;
opts.D1Lp = 8e-6;
% opts.D1Lp = 3e-6*0;

% opts.D1Lp = 1e-4; opts.opt_method = 'adam'; % not distributed
opts.opt_method = 'lbfgs';
% opts.opt_method = 'adam';

opts.nlvl = [];

for idx = 8 %1:10
    pts_struct = DIR_get_all_points_for_the_case(idx, basepth);
    % read images
    [volmov, spc] = read_DIR_volume_4dCT(idx, 5, basepth);
    pts_mov = pts_struct.extreme.e;

    init_size = size(volmov);
    min_max1 = [ min(pts_struct.extreme.b, [], 1)', max(pts_struct.extreme.b, [], 1)'];
    min_max2 = [ min(pts_struct.extreme.e, [], 1)', max(pts_struct.extreme.e, [], 1)'];
    min_max = [ min(min_max1(:, 1), min_max2(:, 1)), max(min_max1(:, 2), min_max2(:, 2))];
    d = [10, 10, 5];
    crop_v = [ max(1, min_max(1,1) - d(1)), min(size(volmov, 1), min_max(1,2) + d(1)); ...
               max(1, min_max(2,1) - d(2)), min(size(volmov, 2), min_max(2,2) + d(2)); ...
               max(1, min_max(3,1) - d(3)), min(size(volmov, 3), min_max(3,2) + d(3));];

    spc_orig = spc;
    for i = 1 : 6
        [tmp, spc] = read_DIR_volume_4dCT(idx, i-1, basepth);
        tmp = crop_data(tmp, crop_v);
        bszv = size(tmp);
        spc_tmp = [1, 1, 1];
        tmpu = volresize(tmp, round(bszv .* spc .* spc_tmp), 1);
        spc = [1,1,1] ./ spc_tmp;

%         tmpu = tmp;
        if i == 1
            vols = zeros([size(tmpu), 6]);
        end
        vols(:,:,:, i) = tmpu;
    end
    pts_fix = pts_struct.extreme.b;
    vols = img_thr(vols, 50, 1100, 1);
    opts.pix_resolution = spc;
    opts.border_mask = 5;
    display('run')

    vols = reshape(vols, [size(vols,1),size(vols,2),size(vols,3), 1, size(vols, 4)]);
    tic
    [voldef, Tmin3_out, Kmin, itinfo] = ptv_register(vols, [], opts);
    toc
end

%
id1 = 1;
id2 = 6;
[Tnew, imgs_1] = remap_displacements( Tmin3_out, id1, vols, opts.pix_resolution);

Tptv_rsz = cat(4, volresize(Tnew(:,:,:,1,end), bszv), volresize(Tnew(:,:,:,2,end), bszv), volresize(Tnew(:,:,:,3,end), bszv));
voldef_rsz = volresize(voldef(:,:,:, 1), bszv);

[~, Tr] = uncrop_data(voldef_rsz(:,:,:,1), Tptv_rsz(:,:,:,:), crop_v, init_size);
[pt_errs_phys, pts_moved_pix, TRE_phys, TREstd_phys] = DIR_movepoints(pts_mov, pts_fix, Tr, spc_orig, [0,0,0]);
TRE(idx) = TRE_phys;
TREstd(idx) = TREstd_phys;
fprintf('$$$$$$$$ For idx=%d error = %.3f  std = %.3f,  time=%.1f\n', idx, TRE(idx), TREstd(idx), TIME(idx));

%%
imgs_exp = [];
Tpix = conv_3d_T_from_phys_to_pix(Tmin3_out(:,:,:,:, :), opts.pix_resolution);
for i = 1 : size(Tpix, 5)
    hold off;
    imagesc(squeeze(vols(:, round(end/2), :, :, i))');
    colormap gray;
    daspect([1,1,1]);
    hold on;
    plot_wiremesh(permute(squeeze(Tpix(:, round(end/2), :, [3,2], i)), [2,1,3]), 6, 'r-')

    F = getframe;
    imgs_exp = cat(4, imgs_exp, double(F.cdata));

    pause(0.1);
end
%%
implay_2d_deform( permute(squeeze(vols(:, round(end/2), :, :, :)), [2, 1, 3]),  permute(squeeze(imgs_1(:, round(end/2), :, :, :)), [2, 1, 3]), ...
    permute(squeeze(Tpix(:, round(end/2), :, :, :)), [2, 1, 3, 4]), 5, false, [0,1]);
%%
ima = permute(squeeze(voldef(:, round(end/2), :, :, :)), [2,1,3]);
savegif('results/DIR_group_track.gif', squeeze([imgs_exp]/250), 1/5);
savegif('results/DIR_group_stab.gif', ima, 1/5);


function f = hsvargplvmObjective(params, model)

% HSVARGPLVMOBJECTIVE Wrapper function for hierarchical var-GP-LVM objective.
% FORMAT
% DESC provides a wrapper function for the varihierarchical var-GP-LVM, it
% takes the negative of the log likelihood, feeding the parameters
% correctly to the model.
% ARG params : the parameters of the variational GP-LVM model.
% ARG model : the model structure in which the parameters are to be
% placed.
% RETURN f : the negative of the log likelihood of the model.
%
% SEEALSO : hsvargplvmCreate, hsvargplvmLogLikelihood, hsvargplvmExpandParam
%
% COPYRIGHT : Andreas C. Damianou 2012

% HSVARGPLVM

model = modelExpandParam(model, params);
f = - modelLogLikelihood(model);


% ------------------------------------------------------
% SwarmOps - Heuristic optimization for Matlab
% Copyright (C) 2003-2010 Magnus Erik Hvass Pedersen.
% Please see the file license.txt for license details.
% SwarmOps on the internet: http://www.Hvass-Labs.org/
% ------------------------------------------------------

% Behavioural parameters for Local Unimodal sampling
% from (1). The parameter-array consists of
% the following parameter:
% - gamma
%
% Literature references:
% (1) M.E.H. Pedersen. Tuning & Simplifying Heuristical
%     Optimization. PhD Thesis, University of Southampton,
%     2010.

LUS_DEFAULT = [3.0];

% ------------------------------------------------------


function []=ps_weed(all_da_flag,no_weed_adjacent,no_weed_noisy)
%PS_WEED weeds out neighboring PS and save those kept to new version
%   PS_weed(all_da_flag,no_weed_adjacent,no_weed_noisy)
%
%   Andy Hooper, June 2006
%
%   ===================================================================
%   09/2006 AH: create all workspace files directly
%   09/2006 AH: drop noisy pixels
%   09/2006 AH: add small baselines
%   01/2007 AH: drop pixels with duplicate lon/lat
%   05/2007 AH: optional weeding of pixels with zero elevation added
%   03/2009 AH: delete scla_smooth mat files
%   02/2010 AH: change smoothing of arcs to time domain
%   02/2010 AH: option to threshold on max arc noise in any ifg
%   02/2010 AH: Speed up of noise weeding
%   02/2010 AH: Leave out ifgs in drop_ifg_index from noise calculation
%   01/2011 AH: Correct arc DEM error estimation for small baselines
%   06/2011 AH: Add weed_neighbours parm (default still 'y')
%   12/2012 AH: weed very small heights if weed_zero_elevation='y'
%   09/2015 DB: Clean the command line output, store number of PS left.
%   09/2015 DB: Fix bug when no PS is left after weeding 0 elevation.
%   09/2015 AH: use matlab triangulation if triangle program not installed
%   01/2016 DB: Replace save with stamps_save which checks for var size when
%               saving
%   10/2017 DB: if inc is present also do weeding on it.
%   ===================================================================
logit;
logit('Weeding selected pixels...')

if nargin<1
    all_da_flag=0;
end

%weed_alpha=getparm('weed_alpha',1);
time_win=getparm('weed_time_win',1);
weed_standard_dev=getparm('weed_standard_dev',1);
weed_max_noise=getparm('weed_max_noise',1);
weed_zero_elevation=getparm('weed_zero_elevation',1);
weed_neighbours=getparm('weed_neighbours',1);
drop_ifg_index=getparm('drop_ifg_index');
small_baseline_flag=getparm('small_baseline_flag',1);

if nargin<2
    if strcmpi(weed_neighbours,'y')
        no_weed_adjacent=0;
    else
        no_weed_adjacent=1;
    end
end
if nargin<3
    if weed_standard_dev>=pi && weed_max_noise>=pi
        no_weed_noisy=1;
    else
        no_weed_noisy=0;
    end
end

load psver

psname=['ps',num2str(psver)];
pmname=['pm',num2str(psver)];
phname=['ph',num2str(psver)];
selectname=['select',num2str(psver)];
hgtname=['hgt',num2str(psver),'.mat'];
laname=['la',num2str(psver),'.mat'];
incname=['inc',num2str(psver),'.mat'];
bpname=['bp',num2str(psver),'.mat'];
psothername=['ps_other'];
psothername=['pm_other'];
selectothername=['select_other'];
hgtothername=['hgt_other'];
laothername=['la_other'];
incothername=['inc_other'];
bpothername=['bp_other'];

ps=load(psname);
ifg_index=setdiff([1:ps.n_ifg],drop_ifg_index);

sl=load(selectname);

if exist([phname,'.mat'],'file')
    phin=load(phname);
    ph=phin.ph;
    clear phin
else
    ph=ps.ph;
end

day=ps.day;
bperp=ps.bperp;
master_day=ps.master_day;

if isfield(sl,'keep_ix')
    ix2=sl.ix(sl.keep_ix);
    K_ps2=sl.K_ps2(sl.keep_ix);
    C_ps2=sl.C_ps2(sl.keep_ix);
    coh_ps2=sl.coh_ps2(sl.keep_ix);
else
    ix2=sl.ix2;
    K_ps2=sl.K_ps2;
    C_ps2=sl.C_ps2;
    coh_ps2=sl.coh_ps2;
end

ij2=ps.ij(ix2,:);
xy2=ps.xy(ix2,:);
ph2=ph(ix2,:);
lonlat2=ps.lonlat(ix2,:);

pm=load(pmname);
ph_patch2=pm.ph_patch(ix2,:); % use original patch phase, with PS left in
if isfield(sl,'ph_res2')
    ph_res2=sl.ph_res2(sl.keep_ix,:);
else
    ph_res2=[];
end
clear pm

clear sl

clear ph
if isfield(ps,'ph')
    ps=rmfield(ps,'ph');
end
ps=rmfield(ps,{'xy','ij','lonlat','sort_ix'});

if all_da_flag~=0
    pso=load(psothername);
    slo=load(selectothername);
    ix_other=slo.ix_other;
    n_ps_other=sum(ix_other);
    K_ps_other2=pso.K_ps_other(ix_other);
    C_ps_other2=pso.C_ps_other(ix_other);
    coh_ps_other2=pso.coh_ps_other(ix_other);
    ph_res_other2=pso.ph_res_other(ix_other,:);
    ij2=[ij2;pso.ij_other(ix_other,:)];
    xy2=[xy2;pso.xy_other(ix_other,:)];
    ph2=[ph2;pso.ph_other(ix_other,:)];
    lonlat2=[lonlat2;pso.lonlat_other(ix_other,:)];
    clear pso slo

    pmo=load(pmothername);
    ph_patch_other2=pmo.ph_patch_other(ix_other,:);
    clear pm

    K_ps2=[K_ps2;K_ps_other2];
    C_ps2=[C_ps2;C_ps_other2];
    coh_ps2=[coh_ps2;coh_ps_other2];
    ph_patch2=[ph_patch2;ph_patch_other2];
    ph_res2=[ph_res2;ph_res_other2];
else
    n_ps_other=0;
end

if exist(hgtname,'file')
    ht=load(hgtname);
    hgt=ht.hgt(ix2);
    clear ht
    if all_da_flag~=0
        hto=load(hgtothername);
        hgt=[hgt;hto.hgt_other(ix_other)];
        clear hto
    end
end

n_ps_low_D_A=length(ix2);
n_ps=n_ps_low_D_A + n_ps_other;
ix_weed=logical(ones(n_ps,1));
logit([num2str(n_ps_low_D_A),' low D_A PS, ',num2str(n_ps_other),' high D_A PS']);

if no_weed_adjacent==0
	step_name='INITIALISE NEIGHBOUR MATRIX';
    fprintf([step_name '\n'])

    ij_shift=ij2(:,2:3)+repmat([2,2]-min(ij2(:,2:3)),n_ps,1);
	neigh_ix=zeros(max(ij_shift(:,1))+1,max(ij_shift(:,2))+1);
    miss_middle=logical(ones(3));
    miss_middle(2,2)=0;

	for i=1:n_ps
        neigh_this=neigh_ix(ij_shift(i,1)-1:ij_shift(i,1)+1,ij_shift(i,2)-1:ij_shift(i,2)+1);
        neigh_this(neigh_this==0&miss_middle)=i;
        neigh_ix(ij_shift(i,1)-1:ij_shift(i,1)+1,ij_shift(i,2)-1:ij_shift(i,2)+1)=neigh_this;

        if i/100000==floor(i/100000)
            logit([num2str(i),' PS processed'],2)
            save log step_name i
            !sync
        end
    end

	step_name='FIND NEIGHBOURS';
    fprintf([step_name '\n'])

    neigh_ps=cell(n_ps,1);
	for i=1:n_ps
        my_neigh_ix=neigh_ix(ij_shift(i,1),ij_shift(i,2));
        if my_neigh_ix~=0
            neigh_ps{my_neigh_ix}=[neigh_ps{my_neigh_ix},i];
        end
        if i/100000==floor(i/100000)
            logit([num2str(i),' PS processed'],2)
            save log step_name i
            !sync
        end

    end

    clear neigh_ix

	step_name='SELECT BEST';
	fprintf([step_name '\n'])

	for i=1:n_ps
        if ~isempty(neigh_ps{i})
            same_ps=i;
            i2=1;
            while i2 <= length(same_ps)
                ps_i=same_ps(i2);
                same_ps=[same_ps,neigh_ps{ps_i}];
                neigh_ps{ps_i}=[];
                i2=i2+1;
            end
            same_ps=unique(same_ps);
            [dummy,high_coh]=max(coh_ps2(same_ps));
            low_coh_ix=logical(ones(size(same_ps)));
            low_coh_ix(high_coh)=0;
            ix_weed(same_ps(low_coh_ix))=0;
        end
        if i/100000==floor(i/100000)
            logit([num2str(i),' PS processed'],2)
            save log step_name i
            !sync
        end

	end
    logit([num2str(sum(ix_weed)),' PS kept after dropping adjacent pixels']);

end

% output how many PS are left after weeding zero elevations out
if strcmpi(weed_zero_elevation,'y') & exist('hgt','var')
    sea_ix=hgt<1e-6;
    ix_weed(sea_ix)=false;
    logit([num2str(sum(ix_weed)),' PS kept after weeding zero elevation']);
end
xy_weed=xy2(ix_weed,:);
% update PS inofmration
n_ps=sum(ix_weed);

%% Remove dupplicated points
% Some non-adjacent pixels are allocated the same lon/lat by DORIS.
% If duplicates occur, the pixel with the highest coherence is kept.
ix_weed_num=find(ix_weed);
[dummy,I]=unique(xy_weed(:,2:3),'rows');
dups=setxor(I,[1:sum(ix_weed)]'); % pixels with duplicate lon/lat

for i=1:length(dups)
    dups_ix_weed=find(xy_weed(:,2)==xy_weed(dups(i),2)&xy_weed(:,3)==xy_weed(dups(i),3));
    dups_ix=ix_weed_num(dups_ix_weed);
    [dummy,I]=max(coh_ps2(dups_ix));
    ix_weed(dups_ix([1:end]~=I))=0; % drop dups with lowest coh
end

if ~isempty(dups)
    xy_weed=xy2(ix_weed,:);
    logit(sprintf('%d PS with duplicate lon/lat dropped\n',length(dups)'))
end

% update PS inofmration
n_ps=sum(ix_weed);
ix_weed2=true(n_ps,1);

%% Weedign noisy pixels
ps_std=zeros(n_ps,1);
ps_max=zeros(n_ps,1);

% include a check to see if any points are actually left.
if n_ps~=0
    if no_weed_noisy==0

        step_name='DROP NOISY';
        arch=computer('arch');
        if strcmpi(arch(1:3),'win')
            use_triangle='n';
        else
            tripath=system('which triangle >& /dev/null');
            if tripath==0
                use_triangle='y';
            else
                use_triangle='n';
            end
        end

        if use_triangle=='y'
            nodename=['psweed.1.node'];
            fid=fopen(nodename,'w');
            fprintf(fid,'%d 2 0 0\n',n_ps);

            for i=1:n_ps
                fprintf(fid,'%d %f %f\n',i,xy_weed(i,2),xy_weed(i,3));
            end

            fclose(fid);

            system('triangle -e psweed.1.node > triangle_weed.log');

            fid=fopen('psweed.2.edge','r');
            header=str2num(fgetl(fid));
            N=header(1);
            edgs=zeros(N,4);
            for i=1:N
                edgs(i,:)=str2num(fgetl(fid));
            end
            fclose(fid);
            edgs=edgs(:,2:3);
        else
            xy_weed=double(xy_weed);
            tri=delaunay(xy_weed(:,2),xy_weed(:,3));
            tr=triangulation(tri,xy_weed(:,2),xy_weed(:,3));
            edgs=edges(tr);
        end
        n_edge=size(edgs,1);

        ph_weed=ph2(ix_weed,:).*exp(-j*(K_ps2(ix_weed)*bperp'));  % subtract range error
        ph_weed=ph_weed./abs(ph_weed);
        if ~strcmpi(small_baseline_flag,'y')
            ph_weed(:,ps.master_ix)=exp(j*(C_ps2(ix_weed)));  % add master noise
        end
        edge_std=zeros(n_edge,1);
        edge_max=zeros(n_edge,1);
        dph_space=(ph_weed(edgs(:,2),:).*conj(ph_weed(edgs(:,1),:)));
        dph_space=dph_space(:,ifg_index);
        n_use=length(ifg_index);
        for i=1:length(drop_ifg_index)
            if strcmpi(small_baseline_flag,'y')
                logit(sprintf('%s-%s dropped from noise estimation',datestr(ps.ifgday(drop_ifg_index(i),2)),datestr(ps.ifgday(drop_ifg_index(i),2))));
            else
                logit(sprintf('%s dropped from noise estimation',datestr(day(drop_ifg_index(i)))));
            end
        end

        if ~strcmpi(small_baseline_flag,'y')
          logit(sprintf('Estimating noise for all arcs...'))
          dph_smooth=zeros(n_edge,n_use,'single');
          dph_smooth2=zeros(n_edge,n_use,'single');
          for i1=1:n_use
            time_diff=(day(ifg_index(i1))-day(ifg_index))';
            weight_factor=exp(-(time_diff.^2)/2/time_win^2);
            weight_factor=weight_factor/sum(weight_factor);

            dph_mean=sum(dph_space.*repmat(weight_factor,n_edge,1),2);
            dph_mean_adj=angle(dph_space.*repmat(conj(dph_mean),1,n_use)); % subtract weighted mean
            G=[ones(n_use,1),time_diff'];
            m=lscov(double(G),double(dph_mean_adj)',weight_factor); % weighted least-sq to find best-fit local line
            dph_mean_adj=angle(exp(j*(dph_mean_adj-(G*m)'))); % subtract first estimate
            m2=lscov(double(G),double(dph_mean_adj)',weight_factor); % weighted least-sq to find best-fit local line
            dph_smooth(:,i1)=dph_mean.*exp(j*(m(1,:)'+m2(1,:)')); % add back weighted mean
             weight_factor(i1)=0; % leave out point itself
             dph_smooth2(:,i1)=sum(dph_space.*repmat(weight_factor,n_edge,1),2);
           end
           dph_noise=angle(dph_space.*conj(dph_smooth));
           dph_noise2=angle(dph_space.*conj(dph_smooth2));
           ifg_var=var(dph_noise2,0,1);
           K=lscov(bperp(ifg_index),double(dph_noise)',1./double(ifg_var))'; % estimate arc dem error
           dph_noise=dph_noise-K*bperp(ifg_index)';
           clear dph_space dph_smooth dph_smooth2 dph_noise2
           edge_std=std(dph_noise,0,2);
           edge_max=max(abs(dph_noise),[],2);
           clear dph_noise
        else
           ifg_var=var(dph_space,0,1);
           K=lscov(bperp(ifg_index),double(dph_space)',1./double(ifg_var))'; % estimate arc dem error
           dph_space=dph_space-K*bperp(ifg_index)';
           edge_std=std(angle(dph_space),0,2);
           edge_max=max(abs(angle(dph_space)),[],2);
           clear dph_space
        end

        logit(sprintf('Estimating max noise for all pixels...'))
        ps_std=inf(n_ps,1,'single');
        ps_max=inf(n_ps,1,'single');
        for i=1:n_edge
           ps_std(edgs(i,:))=min([ps_std(edgs(i,:)),[edge_std(i);edge_std(i)]],[],2);
           ps_max(edgs(i,:))=min([ps_max(edgs(i,:)),[edge_max(i);edge_max(i)]],[],2);
        end
        ix_weed2=ps_std<weed_standard_dev&ps_max<weed_max_noise;
        ix_weed(ix_weed)=ix_weed2;
        n_ps=sum(ix_weed);

        logit([num2str(n_ps),' PS kept after dropping noisy pixels']);
    end
end

%% Keep information about number of PS left.
if exist('no_ps_info.mat','file')~=2
   stamps_step_no_ps = zeros([5 1 ]);       % keep for the first 5 steps only
else
   load('no_ps_info.mat');
   % reset as we are currently re-processing
   stamps_step_no_ps(4:end)=0;
end
if n_ps==0
   fprintf('***No PS points left. Updating the stamps log for this****\n')
   % update the flag indicating no PS left in step 3
   stamps_step_no_ps(4)=1;
end
save('no_ps_info.mat','stamps_step_no_ps')

%% Saving the results
weedname=['weed',num2str(psver)];
% save(weedname,'ix_weed','ix_weed2','ps_std','ps_max','ifg_index')
stamps_save(weedname,ix_weed,ix_weed2,ps_std,ps_max,ifg_index)

coh_ps=coh_ps2(ix_weed);
K_ps=K_ps2(ix_weed);
C_ps=C_ps2(ix_weed);
ph_patch=ph_patch2(ix_weed,:);
if ~isempty(ph_res2)
    ph_res=ph_res2(ix_weed,:);
else
    ph_res=ph_res2;
end

pmname=['pm',num2str(psver+1)];
% save(pmname,'ph_patch','ph_res','coh_ps','K_ps','C_ps')
stamps_save(pmname,ph_patch,ph_res,coh_ps,K_ps,C_ps)

clear ph_patch ph_res coh_ps K_ps C_ps ph_patch2 ph_res2 coh_ps2 K_ps2 C_ps2

ph2=ph2(ix_weed,:);
ph=ph2;
phname=['ph',num2str(psver+1)];
% save(phname,'ph')
stamps_save(phname,ph)

clear ph

xy2=xy2(ix_weed,:);
ij2=ij2(ix_weed,:);
lonlat2=lonlat2(ix_weed,:);
ps.xy=xy2;
ps.ij=ij2;
ps.lonlat=lonlat2;
ps.n_ps=size(ph2,1);
psname=['ps',num2str(psver+1)];
save(psname,'-struct','ps');
clear ps xy2 ij2 lonlat2

if exist(hgtname,'file')
    hgt=hgt(ix_weed);
    % save(['hgt',num2str(psver+1),'.mat'],'hgt');
    stamps_save(['hgt',num2str(psver+1),'.mat'],hgt);

    clear hgt
end

if exist(laname,'file')
    la=load(laname);
    la=[la.la(ix2)];
    if all_da_flag~=0
        lao=load(laothername);
        la=[la;lao.la_other(ix_other)];
        clear lao
    end
    la=la(ix_weed);
%    save(['la',num2str(psver+1),'.mat'],'la');
    stamps_save(['la',num2str(psver+1),'.mat'],la);
    clear la
end

if exist(incname,'file')
    inc=load(incname);
    inc=[inc.inc(ix2)];
    if all_da_flag~=0
        inco=load(incothername);
        inc=[inc;inco.inc_other(ix_other)];
        clear inco
    end
    inc=inc(ix_weed);
    stamps_save(['inc',num2str(psver+1),'.mat'],inc);
    clear inc
end

if exist(bpname,'file')
    bp=load(bpname);
    bperp_mat=[bp.bperp_mat(ix2,:)];
    clear bp
    if all_da_flag~=0
        bpo=load(bpothername);
        bperp_mat=[bperp_mat;bpo.bperp_other(ix_other,:)];
        clear bpo
    end
    bperp_mat=bperp_mat(ix_weed,:);
    % save(['bp',num2str(psver+1),'.mat'],'bperp_mat');
    stamps_save(['bp',num2str(psver+1),'.mat'],bperp_mat);
end

if exist(['scla_smooth',num2str(psver+1),'.mat'],'file')
    delete(['scla_smooth',num2str(psver+1),'.mat'])
end
if exist(['scla',num2str(psver+1),'.mat'],'file')
    delete(['scla',num2str(psver+1),'.mat'])
end
if exist(['scla_smooth_sb',num2str(psver+1),'.mat'],'file')
    delete(['scla_smooth_sb',num2str(psver+1),'.mat'])
end
if exist(['scla_sb',num2str(psver+1),'.mat'],'file')
    delete(['scla_sb',num2str(psver+1),'.mat'])
end
if exist(['aps',num2str(psver+1),'.mat'],'file')
    delete(['aps',num2str(psver+1),'.mat'])
end
if exist(['scn',num2str(psver+1),'.mat'],'file')
    delete(['scn',num2str(psver+1),'.mat'])
end

setpsver(psver+1)
logit(1);


function [foodMenu] = extractDietFromModel(model)
%This function analysis an VMH model and extracts the diet based on the
%lower bound constraints.
%
% USAGE:
%   [foodMenu] = extractDietFromModel(model)
% INPUT:
%   model:     A human model (WBM)
% OUTPUT:
%   foodMenu:   A nx2 cell array containing n dietary metabolites and their
%               corresponding flux
% Authors:
%       Bronson R. Weston, 2022

%Identify food reactions
foodRxns=find(contains(model.rxns,'Food_EX_'));
foodRxns=foodRxns(model.lb(foodRxns)<0);

%Identify dietary metabolite reactions
metRxns=find(contains(model.rxns,'Diet_EX_'));
metRxns=metRxns(model.lb(metRxns)<0);
foodFlux=[];
metFlux=[];
metItems={};
foodItems={};

%Excract lower bound constraints of food and diet reactions
if length(foodRxns)>0
    foodItems = model.rxns(foodRxns);
    foodFlux = -1*model.lb(foodRxns);
end
if length(metRxns)>0
    metItems = model.rxns(metRxns);
    metFlux = -1*model.lb(metRxns);
end

%Specify foodMenu
foodMenu=[foodItems,num2cell(foodFlux);metItems,num2cell(metFlux)];
end


classdef Max < dagnn.ElementWise
  %SUM DagNN max layer
  %   The MAX layer takes the max of all its inputs and store the result
  %   as its only output.

  properties (Transient)
    numInputs
  end

  methods
    function outputs = forward(obj, inputs, params)
      obj.numInputs = numel(inputs) ;
      outputs{1} = vl_nnmax(obj.numInputs, inputs{:}) ;
    end

    function [derInputs, derParams] = backward(obj, inputs, params, derOutputs)
      derInputs = vl_nnmax(obj.numInputs, inputs{:}, derOutputs{1}) ;
      keyboard
      derParams = {} ;
    end

    function outputSizes = getOutputSizes(obj, inputSizes)
      outputSizes{1} = inputSizes{1} ;
      for k = 2:numel(inputSizes)
        if all(~isnan(inputSizes{k})) && all(~isnan(outputSizes{1}))
          if ~isequal(inputSizes{k}, outputSizes{1})
            warning('Max layer: the dimensions of the input variables is not the same.') ;
          end
        end
      end
    end

    function rfs = getReceptiveFields(obj)
      numInputs = numel(obj.net.layers(obj.layerIndex).inputs) ;
      rfs.size = [1 1] ;
      rfs.stride = [1 1] ;
      rfs.offset = [1 1] ;
      rfs = repmat(rfs, numInputs, 1) ;
    end

    function obj = Max(varargin)
      obj.load(varargin) ;
    end
  end
end


function G = ipopt_callback_dg(x,model)%returnStructOnly,model)

global latest_x_g
global latest_G
global latest_g

x = x(:);
if isequal(x,latest_x_g)
    % Jacobian was computed already in the call for constraints
    G = latest_G;
else
    % Compute the nonlinear terms in the constraints
    [g,geq,dg,dgeq] = fmincon_con_liftlayer(x,model);

    % Append with linear terms
    if isempty(dg)
        G = dgeq';
    else
        G = [dg';dgeq'];
    end

    if ~isempty(model.A)
        G = [G;model.A];
    end
    if ~isempty(model.Aeq)
        G = [G;model.Aeq];
    end
    G = sparse(G);
end
if model.dense
    G = full(G);
end


% This file is designed for customer testing. Users can put their target
% images into the folder "dataset/test/images". This file supports testing
% images with arbitrary resolution

function testGAIC_qualitative_customer()

imDir = dir(fullfile('dataset','test','images','*.*'));
imDir = imDir(3:end);
imList = fullfile('dataset','test','images',{imDir.name});

load(['imdb_GAIC1000.mat'],'imdb');
gt_scores = cat(2,imdb.bbox.gt_scores{imdb.images.set==1});
gt_scores_means = mean(gt_scores);
gt_scores_stds = std(gt_scores);

netStruct = load(fullfile('data','pretrained_models','net-epoch-37.mat'),'net');
net = dagnn.DagNN.loadobj(netStruct.net) ;
net.mode = 'test' ;
net.move('gpu') ;
probVarI = net.getVarIndex('predcls');
net.vars(probVarI).precious = 1;
minScale = net.meta.minScale;

for aspect_ratios = {'1_1','4_3','16_9','2_3','4_5','5_7'}

    for i = 1:numel(imList)
        try
            img = imread(imList{i});
        catch
            continue
        end

        [x1,x2,x3] = size(img);

        imre = single(imresize(img,minScale/min([x1,x2]),'bilinear'));
        imre = bsxfun(@minus,imre,net.meta.normalization.averageImage);

        [r1,r2,r3] = size(imre);
        r1 = 32*round(r1/32);
        r2 = 32*round(r2/32);
        imre = imresize(imre,[r1,r2],'bilinear');

        boxes = generateBoxes(imre,aspect_ratios{1});
        if isempty(boxes)
            continue;
        end

        inputs = {'input', gpuArray(imre), 'rois', gpuArray(single([ones(1,size(boxes,2));boxes]))} ;

        net.eval(inputs) ;
        preds = squeeze(gather(net.vars(probVarI).value)) ;
        preds = preds * gt_scores_stds + gt_scores_means;
        [~,id_preds] = sort(preds,'descend');

        predBox = boxes(:,id_preds(1));

        scale1 = x1/r1;
        scale2 = x2/r2;
        boxes_s(1,:) = max(floor(predBox(1,:) * scale1),1);
        boxes_s(2,:) = max(floor(predBox(2,:) * scale2),1);
        boxes_s(3,:) = min(ceil(predBox(3,:) * scale1),x1);
        boxes_s(4,:) = min(ceil(predBox(4,:) * scale2),x2);

        outDir = fullfile('dataset','test','result');
        mkdir(outDir);

        imwrite(img(boxes_s(1):boxes_s(3),boxes_s(2):boxes_s(4),:),...
            fullfile(outDir,[imDir(i).name(1:end-4) '_preds_' aspect_ratios{1} '.jpg']));

    end

end

function boxes = generateBoxes(im,aspect_ratios)

switch aspect_ratios
    case '1_1'
        boxes = generateBoxes_1_1(im);
    case '4_3'
        boxes = generateBoxes_4_3(im);
    case '16_9'
        boxes = generateBoxes_16_9(im);
    case '2_3'
        boxes = generateBoxes_2_3(im);
    case '4_5'
        boxes = generateBoxes_4_5(im);
    case '5_7'
        boxes = generateBoxes_5_7(im);
    case '1_2'
        boxes = generateBoxes_1_2(im);
    case '1_3'
        boxes = generateBoxes_1_3(im);
    case '1_4'
        boxes = generateBoxes_1_4(im);
    case '2_1'
        boxes = generateBoxes_2_1(im);
    case '3_1'
        boxes = generateBoxes_3_1(im);
    case '4_1'
        boxes = generateBoxes_4_1(im);
end
boxes = round(boxes);

function boxes = generateBoxes_16_9(im)

boxes = [];
[s1,s2,s3] = size(im);
id = floor(max(s1,s2)/8);
out_Dim = [16*(14:id)',9*(14:id)'];
out_Dim = out_Dim(out_Dim(:,1)<=s2,:);
out_Dim = out_Dim(out_Dim(:,2)<=s1,:);

cnt = 0;
if out_Dim(end,1)*out_Dim(end,2)>0.4*s1*s2
for scale = 1:size(out_Dim,1)
    if out_Dim(1,1)*out_Dim(1,2)<0.4*s1*s2
        out_Dim = out_Dim(2:end,:);
    end
end
end

for scale = 1:size(out_Dim,1)
    step_x = 1:16:(s1-out_Dim(scale,2)+1);
    step_y = 1:9:(s2-out_Dim(scale,1)+1);
    for x1 = step_x
        for y1 = step_y
            cnt = cnt + 1;
            boxes(1,cnt) = x1;
            boxes(2,cnt) = y1;
            boxes(3,cnt) = x1+out_Dim(scale,2)-1;
            boxes(4,cnt) = y1+out_Dim(scale,1)-1;
        end
    end
end
boxes = round(boxes);

function boxes = generateBoxes_4_3(im)

boxes = [];
[s1,s2,s3] = size(im);
id = floor(max(s1,s2)/8);
out_Dim = [8*(25:id)',6*(25:id)'];
out_Dim = out_Dim(out_Dim(:,1)<=s2,:);
out_Dim = out_Dim(out_Dim(:,2)<=s1,:);

cnt = 0;
if out_Dim(end,1)*out_Dim(end,2)>0.4*s1*s2
for scale = 1:size(out_Dim,1)
    if out_Dim(1,1)*out_Dim(1,2)<0.4*s1*s2
        out_Dim = out_Dim(2:end,:);
    end
end
end

for scale = 1:size(out_Dim,1)
    step_x = 1:16:(s1-out_Dim(scale,2)+1);
    step_y = 1:12:(s2-out_Dim(scale,1)+1);
    for x1 = step_x
        for y1 = step_y
            cnt = cnt + 1;
            boxes(1,cnt) = x1;
            boxes(2,cnt) = y1;
            boxes(3,cnt) = x1+out_Dim(scale,2)-1;
            boxes(4,cnt) = y1+out_Dim(scale,1)-1;
        end
    end
end
boxes = round(boxes);

function boxes = generateBoxes_1_1(im)

boxes = [];
[s1,s2,s3] = size(im);

out_Dim = [4*(40:2:64)',4*(40:2:64)'];

cnt = 0;
if out_Dim(end,1)*out_Dim(end,2)>0.4*s1*s2
for scale = 1:size(out_Dim,1)
    if out_Dim(1,1)*out_Dim(1,2)<0.4*s1*s2
        out_Dim = out_Dim(2:end,:);
    end
end
end

for scale = 1:size(out_Dim,1)
    step_x = 1:12:(s1-out_Dim(scale,2)+1);
    step_y = 1:12:(s2-out_Dim(scale,1)+1);
    for x1 = step_x
        for y1 = step_y
            cnt = cnt + 1;
            boxes(1,cnt) = x1;
            boxes(2,cnt) = y1;
            boxes(3,cnt) = x1+out_Dim(scale,2)-1;
            boxes(4,cnt) = y1+out_Dim(scale,1)-1;
        end
    end
end
boxes = round(boxes);

function boxes = generateBoxes_2_3(im)

boxes = [];

[s1,s2,s3] = size(im);
id = floor(max(s1,s2)/8);
out_Dim = [8*(18:id)',12*(18:id)'];
out_Dim = out_Dim(out_Dim(:,1)<=s2,:);
out_Dim = out_Dim(out_Dim(:,2)<=s1,:);

cnt = 0;
if out_Dim(end,1)*out_Dim(end,2)>0.4*s1*s2
for scale = 1:size(out_Dim,1)
    if out_Dim(1,1)*out_Dim(1,2)<0.4*s1*s2
        out_Dim = out_Dim(2:end,:);
    end
end
end

for scale = 1:size(out_Dim,1)
    step_x = 1:8:(s1-out_Dim(scale,2)+1);
    step_y = 1:12:(s2-out_Dim(scale,1)+1);
    for x1 = step_x
        for y1 = step_y
            cnt = cnt + 1;
            boxes(1,cnt) = x1;
            boxes(2,cnt) = y1;
            boxes(3,cnt) = x1+out_Dim(scale,2)-1;
            boxes(4,cnt) = y1+out_Dim(scale,1)-1;
        end
    end
end
boxes = round(boxes);

function boxes = generateBoxes_4_5(im)

boxes = [];

[s1,s2,s3] = size(im);
id = floor(max(s1,s2)/8);
out_Dim = [8*(20:id)',10*(20:id)'];
out_Dim = out_Dim(out_Dim(:,1)<=s2,:);
out_Dim = out_Dim(out_Dim(:,2)<=s1,:);

if out_Dim(end,1)*out_Dim(end,2)>0.4*s1*s2

for scale = 1:size(out_Dim,1)
    if out_Dim(1,1)*out_Dim(1,2)<0.4*s1*s2
        out_Dim = out_Dim(2:end,:);
    end
end

end

cnt = 0;
for scale = 1:size(out_Dim,1)
    step_x = 1:8:(s1-out_Dim(scale,2)+1);
    step_y = 1:10:(s2-out_Dim(scale,1)+1);
    for x1 = step_x
        for y1 = step_y
            cnt = cnt + 1;
            boxes(1,cnt) = x1;
            boxes(2,cnt) = y1;
            boxes(3,cnt) = x1+out_Dim(scale,2)-1;
            boxes(4,cnt) = y1+out_Dim(scale,1)-1;
        end
    end
end
boxes = round(boxes);

function boxes = generateBoxes_5_7(im)

boxes = [];

[s1,s2,s3] = size(im);
id = floor(max(s1,s2)/8);
out_Dim = [10*(15:id)',14*(15:id)'];
out_Dim = out_Dim(out_Dim(:,1)<=s2,:);
out_Dim = out_Dim(out_Dim(:,2)<=s1,:);
cnt = 0;

if out_Dim(end,1)*out_Dim(end,2)>0.4*s1*s2
for scale = 1:size(out_Dim,1)
    if out_Dim(1,1)*out_Dim(1,2)<0.4*s1*s2
        out_Dim = out_Dim(2:end,:);
    end
end
end

for scale = 1:size(out_Dim,1)
    step_x = 1:8:(s1-out_Dim(scale,2)+1);
    step_y = 1:14:(s2-out_Dim(scale,1)+1);
    for x1 = step_x
        for y1 = step_y
            cnt = cnt + 1;
            boxes(1,cnt) = x1;
            boxes(2,cnt) = y1;
            boxes(3,cnt) = x1+out_Dim(scale,2)-1;
            boxes(4,cnt) = y1+out_Dim(scale,1)-1;
        end
    end
end
boxes = round(boxes);

function boxes = generateBoxes_1_2(im)

boxes = [];

[s1,s2,s3] = size(im);
% id = floor(max(s1,s2)/8);
out_Dim = [6*(18:100)',12*(18:100)'];
out_Dim = out_Dim(out_Dim(:,1)<=s2,:);
out_Dim = out_Dim(out_Dim(:,2)<=s1,:);

cnt = 0;
if out_Dim(end,1)*out_Dim(end,2)>0.4*s1*s2
for scale = 1:size(out_Dim,1)
    if out_Dim(1,1)*out_Dim(1,2)<0.4*s1*s2
        out_Dim = out_Dim(2:end,:);
    end
end
end

for scale = 1:size(out_Dim,1)
    step_x = 1:8:(s1-out_Dim(scale,2)+1);
    step_y = 1:16:(s2-out_Dim(scale,1)+1);
    for x1 = step_x
        for y1 = step_y
            cnt = cnt + 1;
            boxes(1,cnt) = x1;
            boxes(2,cnt) = y1;
            boxes(3,cnt) = x1+out_Dim(scale,2)-1;
            boxes(4,cnt) = y1+out_Dim(scale,1)-1;
        end
    end
end
boxes = round(boxes);

function boxes = generateBoxes_1_3(im)

boxes = [];

[s1,s2,s3] = size(im);
out_Dim = [4*(18:100)',12*(18:100)'];
out_Dim = out_Dim(out_Dim(:,1)<=s2,:);
out_Dim = out_Dim(out_Dim(:,2)<=s1,:);

cnt = 0;
if out_Dim(end,1)*out_Dim(end,2)>0.4*s1*s2
for scale = 1:size(out_Dim,1)
    if out_Dim(1,1)*out_Dim(1,2)<0.4*s1*s2
        out_Dim = out_Dim(2:end,:);
    end
end
end

for scale = 1:size(out_Dim,1)
    step_x = 1:8:(s1-out_Dim(scale,2)+1);
    step_y = 1:16:(s2-out_Dim(scale,1)+1);
    for x1 = step_x
        for y1 = step_y
            cnt = cnt + 1;
            boxes(1,cnt) = x1;
            boxes(2,cnt) = y1;
            boxes(3,cnt) = x1+out_Dim(scale,2)-1;
            boxes(4,cnt) = y1+out_Dim(scale,1)-1;
        end
    end
end
boxes = round(boxes);

function boxes = generateBoxes_1_4(im)

boxes = [];

[s1,s2,s3] = size(im);
out_Dim = [3*(18:100)',12*(18:100)'];
out_Dim = out_Dim(out_Dim(:,1)<=s2,:);
out_Dim = out_Dim(out_Dim(:,2)<=s1,:);

cnt = 0;
if out_Dim(end,1)*out_Dim(end,2)>0.4*s1*s2
for scale = 1:size(out_Dim,1)
    if out_Dim(1,1)*out_Dim(1,2)<0.4*s1*s2
        out_Dim = out_Dim(2:end,:);
    end
end
end

for scale = 1:size(out_Dim,1)
    step_x = 1:8:(s1-out_Dim(scale,2)+1);
    step_y = 1:16:(s2-out_Dim(scale,1)+1);
    for x1 = step_x
        for y1 = step_y
            cnt = cnt + 1;
            boxes(1,cnt) = x1;
            boxes(2,cnt) = y1;
            boxes(3,cnt) = x1+out_Dim(scale,2)-1;
            boxes(4,cnt) = y1+out_Dim(scale,1)-1;
        end
    end
end
boxes = round(boxes);

function boxes = generateBoxes_2_1(im)

boxes = [];

[s1,s2,s3] = size(im);
out_Dim = [12*(18:100)',6*(18:100)'];
out_Dim = out_Dim(out_Dim(:,1)<=s2,:);
out_Dim = out_Dim(out_Dim(:,2)<=s1,:);

cnt = 0;
if out_Dim(end,1)*out_Dim(end,2)>0.4*s1*s2
for scale = 1:size(out_Dim,1)
    if out_Dim(1,1)*out_Dim(1,2)<0.4*s1*s2
        out_Dim = out_Dim(2:end,:);
    end
end
end

for scale = 1:size(out_Dim,1)
    step_x = 1:16:(s1-out_Dim(scale,2)+1);
    step_y = 1:8:(s2-out_Dim(scale,1)+1);
    for x1 = step_x
        for y1 = step_y
            cnt = cnt + 1;
            boxes(1,cnt) = x1;
            boxes(2,cnt) = y1;
            boxes(3,cnt) = x1+out_Dim(scale,2)-1;
            boxes(4,cnt) = y1+out_Dim(scale,1)-1;
        end
    end
end
boxes = round(boxes);

function boxes = generateBoxes_3_1(im)

boxes = [];

[s1,s2,s3] = size(im);
out_Dim = [12*(18:100)',4*(18:100)'];
out_Dim = out_Dim(out_Dim(:,1)<=s2,:);
out_Dim = out_Dim(out_Dim(:,2)<=s1,:);

cnt = 0;
if out_Dim(end,1)*out_Dim(end,2)>0.4*s1*s2
for scale = 1:size(out_Dim,1)
    if out_Dim(1,1)*out_Dim(1,2)<0.4*s1*s2
        out_Dim = out_Dim(2:end,:);
    end
end
end

for scale = 1:size(out_Dim,1)
    step_x = 1:16:(s1-out_Dim(scale,2)+1);
    step_y = 1:8:(s2-out_Dim(scale,1)+1);
    for x1 = step_x
        for y1 = step_y
            cnt = cnt + 1;
            boxes(1,cnt) = x1;
            boxes(2,cnt) = y1;
            boxes(3,cnt) = x1+out_Dim(scale,2)-1;
            boxes(4,cnt) = y1+out_Dim(scale,1)-1;
        end
    end
end
boxes = round(boxes);

function boxes = generateBoxes_4_1(im)

boxes = [];

[s1,s2,s3] = size(im);
out_Dim = [12*(18:100)',3*(18:100)'];
out_Dim = out_Dim(out_Dim(:,1)<=s2,:);
out_Dim = out_Dim(out_Dim(:,2)<=s1,:);

cnt = 0;
if out_Dim(end,1)*out_Dim(end,2)>0.4*s1*s2
for scale = 1:size(out_Dim,1)
    if out_Dim(1,1)*out_Dim(1,2)<0.4*s1*s2
        out_Dim = out_Dim(2:end,:);
    end
end
end

for scale = 1:size(out_Dim,1)
    step_x = 1:16:(s1-out_Dim(scale,2)+1);
    step_y = 1:8:(s2-out_Dim(scale,1)+1);
    for x1 = step_x
        for y1 = step_y
            cnt = cnt + 1;
            boxes(1,cnt) = x1;
            boxes(2,cnt) = y1;
            boxes(3,cnt) = x1+out_Dim(scale,2)-1;
            boxes(4,cnt) = y1+out_Dim(scale,1)-1;
        end
    end
end
boxes = round(boxes);


function test_ft_volumelookup

% MEM 2gb
% WALLTIME 00:10:00
% DEPENDENCY ft_volumelookup ft_read_atlas atlas_lookup

atlasfilename = dccnpath('/home/common/matlab/fieldtrip/template/atlas/afni/TTatlas+tlrc.BRIK');
mrifilename   = dccnpath('/home/common/matlab/fieldtrip/external/spm8/templates/T1.nii');

mri = ft_read_mri(mrifilename);
mri.coordsys = 'mni';

cfg       = [];
cfg.atlas = atlasfilename;
cfg.roi   = {'Precentral Gyrus'};
mask1     = ft_volumelookup(cfg,mri);
cfg.roi   = {'Brodmann area 47'};
mask2     = ft_volumelookup(cfg,mri);
cfg.roi   = {'Precentral Gyrus';'Brodmann area 47'};
mask3     = ft_volumelookup(cfg,mri);

assert(isequal(sum(mask1(:)),8144));%8213));
assert(isequal(sum(mask2(:)),2096));%2093));
assert(isequal(sum(mask3(:)&(mask2(:)|mask1(:))),sum(mask3(:))));

% the following is just to check whether the functionality does not crash
% no idea who would use it anyway
cfg       = [];
cfg.roi   = [15 30 40;-40 -20 80];
cfg.sphere = [10 8];
mask4     = ft_volumelookup(cfg,mri);

mri.mask  = mask4;

cfg       = [];
cfg.atlas = atlasfilename;
cfg.maskparameter = 'mask';
mask5     = ft_volumelookup(cfg, mri);

atlasfilename = dccnpath('/home/common/matlab/fieldtrip/template/atlas/aal/ROI_MNI_V4.nii');
cfg       = [];
cfg.atlas = atlasfilename;
cfg.roi = 'Calcarine_R'; % right V1
mask6 = ft_volumelookup(cfg, mri);
assert(isequal(sum(mask6(:)),1861));

atlas_MNI = ft_read_atlas(atlasfilename);
atlas_MNI.coordsys = 'mni';
cfg = [];
cfg.roi = [52 -9 -45; 73 -37 -8];
cfg.atlas = atlasfilename;
cfg.output = 'single';
cfg.maxqueryrange = 29;
label_MNI = ft_volumelookup(cfg, atlas_MNI);
assert(size(label_MNI, 1) == 1);
cfg.output = 'label';
label_MNI = ft_volumelookup(cfg, atlas_MNI);
assert(size(label_MNI, 1) == 1);
cfg.output = 'multiple';
label_MNI = ft_volumelookup(cfg, atlas_MNI);
assert(size(label_MNI, 1) == 2);


function [net,net_asdn,poss,hardnegs] = mdnet_finetune_hnm_update(net,net_asdn,pos_data,neg_data,varargin)
%
%
global gpu;

opts.useGpu = gpu;
opts.conserveMemory = true ;
opts.sync = true ;

opts.maxiter = 30;
opts.learningRate = 0.001;
opts.weightDecay = 0.0005 ;
opts.momentum = 0.9 ;

opts.batchSize_hnm = 256;
opts.batchAcc_hnm = 4;

opts.batchSize = 128;
opts.batch_pos = 32;
opts.batch_neg = 96;

opts = vl_argparse(opts, varargin) ;
% -------------------------------------------------------------------------
%                                                    Network initialization
% -------------------------------------------------------------------------

for i=1:numel(net.layers)
    if strcmp(net.layers{i}.type,'conv')
        net.layers{i}.filtersMomentum = zeros(size(net.layers{i}.filters), ...
            class(net.layers{i}.filters)) ;
        net.layers{i}.biasesMomentum = zeros(size(net.layers{i}.biases), ...
            class(net.layers{i}.biases)) ; %#ok<*ZEROLIKE>

        if opts.useGpu
            net.layers{i}.filtersMomentum = gpuArray(net.layers{i}.filtersMomentum);
            net.layers{i}.biasesMomentum = gpuArray(net.layers{i}.biasesMomentum);
        end
    end
end

for i=1:numel(net_asdn.layers)
    if strcmp(net_asdn.layers{i}.type,'conv')
        net_asdn.layers{i}.filtersMomentum = zeros(size(net_asdn.layers{i}.filters), ...
            class(net_asdn.layers{i}.filters)) ;
        net_asdn.layers{i}.biasesMomentum = zeros(size(net_asdn.layers{i}.biases), ...
            class(net_asdn.layers{i}.biases)) ; %#ok<*ZEROLIKE>

        if opts.useGpu
            net_asdn.layers{i}.filtersMomentum = gpuArray(net_asdn.layers{i}.filtersMomentum);
            net_asdn.layers{i}.biasesMomentum = gpuArray(net_asdn.layers{i}.biasesMomentum);
        end
    end
end

%% initilizing
if opts.useGpu
    one = gpuArray(single(1)) ;
else
    one = single(1) ;
end
res = [] ;
res_asdn=[];
res_test=[];

n_pos = size(pos_data,4);
n_neg = size(neg_data,4);
train_pos_cnt = 0;
train_neg_cnt = 0;

% extract positive batches
train_pos = [];
remain = opts.batch_pos*opts.maxiter;
while(remain>0)
    if(train_pos_cnt==0)
        train_pos_list = randperm(n_pos)';
    end
    train_pos = cat(1,train_pos,...
        train_pos_list(train_pos_cnt+1:min(end,train_pos_cnt+remain)));
    train_pos_cnt = min(length(train_pos_list),train_pos_cnt+remain);
    train_pos_cnt = mod(train_pos_cnt,length(train_pos_list));
    remain = opts.batch_pos*opts.maxiter-length(train_pos);
end

% extract negative batches
train_neg = [];
remain = opts.batchSize_hnm*opts.batchAcc_hnm*opts.maxiter;
while(remain>0)
    if(train_neg_cnt==0)
        train_neg_list = randperm(n_neg)';
    end
    train_neg = cat(1,train_neg,...
        train_neg_list(train_neg_cnt+1:min(end,train_neg_cnt+remain)));
    train_neg_cnt = min(length(train_neg_list),train_neg_cnt+remain);
    train_neg_cnt = mod(train_neg_cnt,length(train_neg_list));
    remain = opts.batchSize_hnm*opts.batchAcc_hnm*opts.maxiter-length(train_neg);
end

% learning rate
lr = opts.learningRate ;
lr_asdn = opts.learningRate*5;

% for saving positives
poss = [];

% for saving hard negatives
hardnegs = [];

% objective fuction
objective = zeros(1,opts.maxiter);

%% training on training set
% fprintf('\n');
for t=1:opts.maxiter
%     fprintf('\ttraining batch %3d of %3d ... ', t, opts.maxiter) ;
    iter_time = tic ;

    % ----------------------------------------------------------------------
    % hard negative mining
    % ----------------------------------------------------------------------
    score_hneg = zeros(opts.batchSize_hnm*opts.batchAcc_hnm,1);
    hneg_start = opts.batchSize_hnm*opts.batchAcc_hnm*(t-1);
    for h=1:opts.batchAcc_hnm
        batch = neg_data(:,:,:,...
            train_neg(hneg_start+(h-1)*opts.batchSize_hnm+1:hneg_start+h*opts.batchSize_hnm));
        if opts.useGpu
            batch = gpuArray(batch) ;
        end

        % backprop
        net.layers{end}.class = ones(opts.batchSize_hnm,1,'single') ;
        res = vl_simplenn(net, batch, [], res, ...
            'disableDropout', true, ...
            'conserveMemory', opts.conserveMemory, ...
            'sync', opts.sync) ;

        score_hneg((h-1)*opts.batchSize_hnm+1:h*opts.batchSize_hnm) = ...
            squeeze(gather(res(end-1).x(1,1,2,:)));
    end
    [~,ord] = sort(score_hneg,'descend');
    hnegs = train_neg(hneg_start+ord(1:opts.batch_neg));
    im_hneg = neg_data(:,:,:,hnegs);
%     fprintf('hnm: %d/%d, ', opts.batch_neg, opts.batchSize_hnm*opts.batchAcc_hnm) ;
    hardnegs = [hardnegs; hnegs];

%----------------------------yb added---------------------------
    batch_asdn=pos_data(:,:,:,train_pos((t-1)*opts.batch_pos+1:t*opts.batch_pos));
    if opts.useGpu
        batch_asdn = gpuArray(batch_asdn) ;
    end

    res_asdn=vl_simplenn(net_asdn,batch_asdn,[],res_asdn,...
            'disableDropout', true, ...
            'conserveMemory', opts.conserveMemory, ...
            'sync', opts.sync);
    feat_asdn=squeeze(gather(res_asdn(end-1).x(:,:,1,:)));

    num=size(feat_asdn,3);
    mask_asdn=ones(3,3,512,num,'single');
    for i=1:num
        feat_=feat_asdn(:,:,i);
        featlist=reshape(feat_,9,1);
        [~,idlist]=sort(featlist,'ascend');
        idxlist=idlist(1:3);

        for k=1:length(idxlist)
            idx=idxlist(k);
            row=floor((idx-1)/3)+1;
            col=mod((idx-1),3)+1;
            mask_asdn(col,row,:,i)=0;
        end
    end
    batch_asdn=batch_asdn.*mask_asdn;
%---------------------------------------------------------------

    % ----------------------------------------------------------------------
    % get next image batch and labels
    % ----------------------------------------------------------------------
    poss = [poss; train_pos((t-1)*opts.batch_pos+1:t*opts.batch_pos)];

    %batch = cat(4,pos_data(:,:,:,train_pos((t-1)*opts.batch_pos+1:t*opts.batch_pos)),...
        %im_hneg);
    batch = cat(4,batch_asdn,im_hneg);
    labels = [2*ones(opts.batch_pos,1,'single');ones(opts.batch_neg,1,'single')];
    if opts.useGpu
        batch = gpuArray(batch) ;
    end

    % backprop
    net.layers{end}.class = labels ;
    res = vl_simplenn(net, batch, one, res, ...
        'conserveMemory', opts.conserveMemory, ...
        'sync', opts.sync) ;

    % gradient step
    for l=1:numel(net.layers)
        if ~strcmp(net.layers{l}.type, 'conv'), continue ; end

        net.layers{l}.filtersMomentum = ...
            opts.momentum * net.layers{l}.filtersMomentum ...
            - (lr * net.layers{l}.filtersLearningRate) * ...
            (opts.weightDecay * net.layers{l}.filtersWeightDecay) * net.layers{l}.filters ...
            - (lr * net.layers{l}.filtersLearningRate) / opts.batchSize * res(l).dzdw{1} ;

        net.layers{l}.biasesMomentum = ...
            opts.momentum * net.layers{l}.biasesMomentum ...
            - (lr * net.layers{l}.biasesLearningRate) * ....
            (opts.weightDecay * net.layers{l}.biasesWeightDecay) * net.layers{l}.biases ...
            - (lr * net.layers{l}.biasesLearningRate) / opts.batchSize * res(l).dzdw{2} ;

        net.layers{l}.filters = net.layers{l}.filters + net.layers{l}.filtersMomentum ;
        net.layers{l}.biases = net.layers{l}.biases + net.layers{l}.biasesMomentum ;
    end

    % print information
    objective(t) = gather(res(end).x)/opts.batchSize ;
    iter_time = toc(iter_time);
    fprintf('objective %.3f, %.2f s\n', mean(objective(1:t)), iter_time) ;

%%-------------------yb added----------------------
    iter_time = tic;
    net_fc=net;
    net_fc.layers=net_fc.layers(1:end-1);
    prob_k=zeros(9,1);
    for i=1:9
        row=floor((i-1)/3)+1;
        col=mod((i-1),3)+1;
        batch=pos_data(:,:,:,train_pos((t-1)*opts.batch_pos+1:t*opts.batch_pos));
        batch(col,row,:,:)=0;

        if opts.useGpu
            batch = gpuArray(batch) ;
        end

        res_test = vl_simplenn(net_fc, batch, [], res_test, ...
            'disableDropout', true, ...
            'conserveMemory', true, ...
            'sync', true) ;

        feat = gather(res_test(end).x) ;

        X=feat;
        E = exp(bsxfun(@minus, X, max(X,[],3))) ;
        L = sum(E,3) ;
        Y = bsxfun(@rdivide, E, L) ;
        prob_k(i)=sum(Y(1,1,1,:));
    end
    [~,idx]=min(prob_k);
    row=floor((idx-1)/3)+1;
    col=mod((idx-1),3)+1;

    batch=pos_data(:,:,:,train_pos((t-1)*opts.batch_pos+1:t*opts.batch_pos));
    labels = ones(3,3,1,opts.batch_pos,'single');
    labels(col,row,:)=0;

    if opts.useGpu
        batch = gpuArray(batch) ;
    end

    net_asdn.layers{end}.class = labels ;
    res_asdn = vl_simplenn(net_asdn, batch, one, res_asdn, ...
        'conserveMemory', opts.conserveMemory, ...
        'sync', opts.sync) ;

    for l=1:numel(net_asdn.layers)
        if ~strcmp(net_asdn.layers{l}.type, 'conv'), continue ; end

        net_asdn.layers{l}.filtersMomentum = ...
            opts.momentum * net_asdn.layers{l}.filtersMomentum ...
            - (lr_asdn * net_asdn.layers{l}.filtersLearningRate) * ...
            (opts.weightDecay * net_asdn.layers{l}.filtersWeightDecay) * net_asdn.layers{l}.filters ...
            - (lr_asdn * net_asdn.layers{l}.filtersLearningRate) / opts.batchSize * res_asdn(l).dzdw{1} ;

        net_asdn.layers{l}.biasesMomentum = ...
            opts.momentum * net_asdn.layers{l}.biasesMomentum ...
            - (lr_asdn * net_asdn.layers{l}.biasesLearningRate) * ...
            (opts.weightDecay * net_asdn.layers{l}.biasesWeightDecay) * net_asdn.layers{l}.biases ...
            - (lr_asdn * net_asdn.layers{l}.biasesLearningRate) / opts.batchSize * res_asdn(l).dzdw{2} ;

        net_asdn.layers{l}.filters = net_asdn.layers{l}.filters + net_asdn.layers{l}.filtersMomentum ;
        net_asdn.layers{l}.biases = net_asdn.layers{l}.biases + net_asdn.layers{l}.biasesMomentum ;
    end
    objective(t) = gather(res_asdn(end).x)/opts.batchSize ;
    iter_time = toc(iter_time);
    fprintf('asdn objective %.3f, %.2f s\n', mean(objective(1:t)), iter_time) ;

%------------------------------------------------------------
end % next batch


function [dynpcm2] = atm2dynpcm2(atm)
% Convert pressure from atmospheres to dynes per square centimeter.
%
% So I watched that movie "Winnebago Man" last night.  It was pretty good.
% I didn't expect much from a low-budget documentary about the guy from
% some novelty viral internet videos to be very good or entertaining.  And
% I expected the first half the be good, then the second half to drag, as
% happens to so many indie docs.  But in fact it was funny at the
% beginning, then became MORE engaging in the second half.  That was a nice
% surprise.
% Chad A. Greene
dynpcm2 = atm*1.01325e+6;


function Retain_Img = RemoveMinorCC(SegImg,reject_T)
    if nargin < 2
        reject_T = 0.2;
    end
    Retain_Img = zeros(size(SegImg));

    % class 2
    Img_C2 = (SegImg==2);
    Retain_C2 = Connection_Judge_3D(Img_C2,reject_T);
    Retain_C2 = imfill(Retain_C2,'hole');
    Retain_Img(Retain_C2) = 2;

    % class 1
    Img_C1 = (SegImg==1);
    Retain_C1 = Connection_Judge_3D(Img_C1,reject_T);
    Retain_C1 = imfill(Retain_C1,'hole');
    Retain_Img(Retain_C1) = 1;
end


function [c,G] = PAES(Problem,c,G,H,N,l_fails,l_opt,div)
% PAES local search

%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

    fails = 0;
    moves = 0;
    while fails < l_fails && moves < l_opt
        m = OperatorFEP(Problem,c);
        if all(c.obj<=m.obj)
            fails = fails + 1;
        else
            [H,dominated,~,mCrowd,cCrowd] = UpdateArchive(H,m,c,N,div);
            if all(c.obj>=m.obj)
                c = m;
                fails = 0;
            elseif ~dominated && mCrowd < cCrowd
                c = m;
            end
        end
        G     = UpdateArchive(G,m,SOLUTION(),N,div);
        moves = moves + 1;
    end
end


% This script file load a data set using fscanf
% The default reads Northern California Hypoellipse Format
%

report_this_filefun(mfilename('fullpath'));
disp('Please make sure the has 88 characters for each line')
disp('and all blanks have been substituted by zeros')

% Lets make sure the file is closed...
safe_fclose(fid);

% reset paramteres
a = []; b = []; n = 0;

if inda == 1
    % initial selection option
    tmin   = 1910.0001;
    tmax   = 2010;
    lonmin = -180.0;
    lonmax =  180.0;
    latmin =  -90.00;
    latmax =  90.0 ;
    Mmin   = -4.0;
    Mmax   = 10.;
    mindep = -10;
    maxdep = 700;

    % call the pre-selection window
    call = 'myloadncal2000'; % this callback is needed so presel know where to return to
    presel
    return
end

% open the file and read 10000 lines at a time
[file1,path1] = uigetfile([ '*.dat'],' Earthquake Datafile');
if length(file1) >1
    fid = fopen([path1 file1],'r') ;
else
    disp('Data import canceled'); return
end

while  ferror(fid) == ''
    n = n+1;
    % this is the new Y2K compliant fornat
    % vari name   yr mo da hr mi se lat   la  lon    lo de ma1     ma he   hz
    % variabl #   1  2  3  4  5  6  7      8  9      10 11 12      13 14   15
    % position    2  4  6  8  10 14 16 17  21 24 25  29 34 36 67   69 84   88
    l = fscanf(fid,'%4d%2d%2d%2d%2d%4d%2d%*1c%4d%3d%*1c%4d%5f%2d%*32c%2d%*15c%4d',...
        [14 10000]) ;
    %if ferror(fid) ~= '' ; break; end

    b = [ -l(9,:)-l(10,:)/6000 ; l(7,:)+l(8,:)/6000 ; l(1,:);l(2,:);l(3,:);
        l(13,:)/10;l(11,:)/100;l(4,:);l(5,:); l(14,:)/100;l(12,:)/10];
    b = b';
    l =  b(:,6) >= Mmin & b(:,1) >= lonmin & b(:,1) <= lonmax & ...
        b(:,2) >= latmin & b(:,2) <= latmax & b(:,3) <= tmax  & ...
        b(:,3) >= tmin  ;
    a = [a ; b(l,:)];

    disp([ num2str(n*10000) ' earthquakes scanned, ' num2str(length(a)) ' EQ found'])
    if max(b(:,3)) >  tmax ; break; end

end
ferror(fid)
fclose(fid);

% Convert the third column into time in decimals
if length(a(1,:))== 7
    a.Date = decyear(a(:,3:5));
elseif length(a(1,:))>=9       %if catalog includes hr and minutes
    a.Date = decyear(a(:,[3:5 8 9]));
end

dep1 = 0.3*(max(a.Depth)-min(a.Depth))+min(a.Depth);
dep2 = 0.6*(max(a.Depth)-min(a.Depth))+min(a.Depth);
dep3 = max(a.Depth);

stri1 = [file1];
tim1 = minti;
tim2 = maxti;
minma2 = minma;
maxma2 = maxma;
minde = min(a.Depth);
maxde = max(a.Depth);
rad = 50.;
ic = 0;
ya0 = 0.;
xa0 = 0.;
iwl3 = 1.;
step = 3;
t1p(1) = 80.;
t2p(1) = 85.;
t3p(1) = 90.;
t4p(1) = 93.;
tresh = 10;

% save the data
[file1,path1] = uiputfile(fullfile(hodi, 'eq_data', '*.mat'), 'Save Earthquake Datafile');
sapa2 = ['save ' path1 file1 ' a'];
if length(file1) > 1; eval(sapa2);end

% call the map window
update(mainmap())


function [status,results] = mrtrix_brainmask_generate(in_file, out_file, verbose)

%
% Generate a brain mask in .mif format from a diffusion file in .mif format
%
% Parameters
% ----------
% in_file: string, full-path to a dwi file from which the
% out_file: the name of the resulting brain-mask file
%
% Returns
% -------
% status: return value from the system call; 0 (success), non-zero
% (failure)
% results: the results of the operation in stdout
%
% Notes
% -----
% http://www.brain.org.au/software/mrtrix/tractography/preprocess.html
%
%

if notDefined('verbose')
    verbose = true;
end

% This command string generates a brain-mask (quite liberal):
cmd_str = sprintf('mrconvert %s -coord 3 0 - | threshold - - | median3D - - | median3D - %s',...
                  in_file, out_file);

% Send the command to mrtrix:
[status, results] = mrtrix_cmd(cmd_str, verbose);


classdef testMaterialInsertingLpBall < testShowingError

    properties (Access = protected)
        tol = 5e-2;
        testName = 'testMaterialInsertingLpBall';
    end

    properties (Access = private)
        vadSAcomparator
        plotter
    end

    methods (Access = public)

        function obj = testMaterialInsertingLpBall()
            obj.computeVademecumAndSimpAllValues();
            obj.plotVademecumAndSimpAllValues();
        end

    end

    methods (Access = protected)

        function computeError(obj)
            obj.error = 0;
        end

    end

    methods (Access = private)

        function computeVademecumAndSimpAllValues(obj)
            s.fileName =  'VademecumSmoothCorner';
            v = VademecumSimpAllComparator(s);
            v.calculate();
            obj.vadSAcomparator = v;
        end

        function plotVademecumAndSimpAllValues(obj)
            s.vadSAcomparator = obj.vadSAcomparator;
            obj.plotter = VademecumComparatorPlotter(s);
            obj.plotter.plot();
        end

    end

end


function [featureshape,trials,vectorize_trials] = utl_determine_featureshape(trials,shape,multitask)
% Uniformize the given trials and shape information.
% [FeatureShape,Trials,VectorizeTrials] = utl_determine_featureshape(Trials,Shape,Multitask)
%
% This function deals with the fact that trials can be represented either as [NxF] matrix of
% vectorized features (N=#observations, F=#features), or as [AxBxCx...xN] array of tensor-shaped
% features (A,B,C, ... = #elements in the respective dimension), which is a bit inconsistent for
% historical reasons.
%
% Takes trials in a variety of shapes, and an (optionally non-empty) desired shape vector and
% uniformizes them into a [#trials x #features] matrix of vectorized trials, the deduced feature
% shape, and a boolean flag of whether trials had to be vectorized. By default also handles a cell
% array of multiple trial arrays, which are assumed to stem from multiple compatibly shaped tasks.
%
% In:
%   Trials : A NxF matrix of observations with pre-vectorized features, or a [AxBxCx...xN] array
%            of tensor-shaped features. Can also be a cell array of multiple such arrays where all
%            dimensions except N must be identical.
%
%   Shape : A vector that is the desired output of size() applied to a single observation, that is,
%           a vector of sizes. If [], shape information will be deduced from Trials, otherwise
%           overrides the shape of Trials.
%
%   Multitask : If true, the output will be a cell array of trial matrices. Otherwise it will be
%               a matrix (and an error will be thrown if there was more than one task in the
%               input).
%
% Out:
%   FeatureShape : Final 1xD vector that describes the feature shape (same as size(one_trial)).
%
%   Trials : Vectorized version of input Trials (#trials x #features).
%
%   VectorizeTrials : whether trials had to be vectorized.
%
%                                Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
%                                2013-02-04

% Copyright (C) Christian Kothe, SCCN, 2013, christian@sccn.ucsd.edu
%
% This program is free software; you can redistribute it and/or modify it under the terms of the GNU
% General Public License as published by the Free Software Foundation; either version 2 of the
% License, or (at your option) any later version.
%
% This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
% even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
% General Public License for more details.
%
% You should have received a copy of the GNU General Public License along with this program; if not,
% write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
% USA

if ~iscell(trials)
    trials = {trials}; end
featureshape = cell(1,length(trials));
vectorize_trials = cell(1,length(trials));
% for each task (each of which has multiple trials)...
for t=1:length(trials)
    if ndims(trials{t}) > 2 %#ok<ISMAT>
        featureshape{t} = size(trials{t}); featureshape{t} = featureshape{t}(1:end-1);
        if ~isempty(shape) && ~isequal(shape,featureshape{t})
            if prod(featureshape{t}) == prod(shape)
                warning('You are specifying a shape property but also multidimensional features of a different shape; using the explicit shape parameter.');
                featureshape{t} = shape;
            else
                error('You are specifying a shape property but also features with an incompatible number of elements. Please correct.');
            end
        end
        trials{t} = double(reshape(trials{t},[],size(trials{t},ndims(trials{t})))');
        vectorize_trials{t} = true;
    else
        if ~isempty(shape)
            if size(shape,1) > 1
                if all(all(bsxfun(@eq,shape(1,:),shape)))
                    featureshape{t} = [shape(1,1),shape(1,2),size(shape,1)];
                    if prod(featureshape{t}) == size(trials{t},2)
                        % the reason is that it is much more efficient to operate on a dense 3d array than a very sparse 2d array
                        warn_once('This method will by convention reshape block-diagonalized feature matrices with identical blocks into a 3d tensor. This warning will only come up once.');
                    else
                        error('Your shape parameter has a different number of features than your data.');
                    end
                else
                    % we don't implement block-diagonalization in here
                    error('This method does not handle implicitly block-diagonal features; please either reformulate in tensor form or pass a large sparse data matrix (pre-blockdiagonalized). Note that the tensor form is likely several times faster.');
                end
            elseif prod(shape) ~= size(trials{t},2)
                error('Your shape parameter has a different number of features than data.');
            else
                featureshape{t} = shape;
            end
        else
            featureshape{t} = [size(trials{t},2),1];
        end
        vectorize_trials{t} = false;
    end
end
vectorize_trials = unique([vectorize_trials{:}]);
if length(vectorize_trials)>1 || ~all(cellfun(@(x)isequal(x,featureshape{1}),featureshape))
    error('The number or shape of features must be the same for each task.'); end
featureshape = featureshape{1};
if nargin >=3 && ~multitask
    if length(trials) > 1
        error('Multi-task learning is disabled by multiple tasks were given.');
    else
        trials = trials{1};
    end
end


classdef(Abstract) AbstractOptimizationVariable < matlab.mixin.SetGet & matlab.mixin.Heterogeneous
    %AbstractOptimizationVariable Summary of this class goes here
    %   Detailed explanation goes here

    properties
        id(1,1) double
    end

    methods
        x = getXsForVariable(obj)

        [lb, ub] = getBndsForVariable(obj)

        [lb, ub] = getAllBndsForVariable(obj)

        setBndsForVariable(obj, lb, ub)

        useTf = getUseTfForVariable(obj)

        setUseTfForVariable(obj, useTf)

        updateObjWithVarValue(obj, x)

        nameStrs = getStrNamesOfVars(obj, evtNum, varLocType)

        function [xS, lbS, ubS] = getScaledXsForVariable(obj)
            x = obj.getXsForVariable();
            [lb, ub] = obj.getBndsForVariable();

            xS = x;
            lbS = lb;
            ubS = ub;
            for(i=1:length(x))
                xi = x(i);
                lbi = lb(i);
                ubi = ub(i);

                bndDiff = ubi - lbi;
                bndCenter = (lbi + ubi)/2;
                if(bndDiff > 1E-10)
                    xS(i) = (xi - bndCenter)/(bndDiff/2);
                    lbS(i) = -1;
                    ubS(i) = 1;
                else
                    xS(i) = xi;
                    lbS(i) = lbi;
                    ubS(i) = ubi;
                end
            end
        end

        function updateObjWithScaledVarValue(obj, xS)
            [lb, ub] = obj.getBndsForVariable();

            x = xS;
            for(i=1:length(xS))
                xSi = xS(i);
                lbi = lb(i);
                ubi = ub(i);

                bndDiff = ubi - lbi;
                bndCenter = (lbi + ubi)/2;

                if(bndDiff > 1E-10)
                    x(i) = xSi * (bndDiff/2) + bndCenter;
                else
                    x(i) = xSi;
                end
            end

            obj.updateObjWithVarValue(x);
        end

        function perturbVar(obj, pPct)
            x = obj.getXsForVariable();
            [lb, ub] = obj.getBndsForVariable();

            if(isempty(x))
                return;
            end

            for(i=1:length(x)) %#ok<*NO4LP>
                xi = x(i);
                lbi = lb(i);
                ubi = ub(i);

                fact = xi;
                if(abs(fact) < 1E-10)
                    fact = 1;
                end

                p1 = xi - (pPct/100)*fact;
                p2 = xi + (pPct/100)*fact;

                lbRnd = max(min(p1,p2),lbi);
                ubRnd = min(max(p1,p2),ubi);

                xRnd = lbRnd + (ubRnd - lbRnd)*rand();
                x(i) = xRnd;
            end

            obj.updateObjWithVarValue(x);
        end

        function varsStoredInRad = getVarsStoredInRad(obj)
            useTf = obj.getUseTfForVariable();
            varsStoredInRad = false(size(useTf));
        end
    end

    methods(Sealed)
        function numVars = getNumOfVars(obj)
            [lb,~] = obj.getBndsForVariable();
            numVars = numel(lb);
        end

        function tf = eq(A,B)
            tf = [A.id] == [B.id];
        end

        function tf = ne(A,B)
            tf = [A.id] ~= [B.id];
        end
    end
end


function LeftStanceConstraints(nlp, bounds, varargin)
    domain = nlp.Plant;

    ip = inputParser;
    ip.addParameter('LoadPath',[],@ischar);
    ip.parse(varargin{:});

    %% virtual constraints
    opt.constraint.virtual_constraints(nlp, bounds, ip.Results.LoadPath);
    %% foot clearance
    [right_foot_frame] = sys.frames.RightFoot(domain);
    opt.constraint.foot_clearance(nlp, bounds, right_foot_frame);

    %% swing toe position
    opt.constraint.step_distance(nlp, bounds);

    %% swing foot orientation
    %     opt.constraint.foot_orientation(nlp, bounds, 'Right');
    %% swing foot velocity
    opt.constraint.impact_velocity(nlp, bounds, right_foot_frame);

    %% feet distance
    %     opt.constraint.feet_distance(nlp, bounds);

    opt.constraint.yaw_start(nlp, bounds);

    opt.constraint.knee_angle(nlp, bounds);

    opt.constraint.average_velocity(nlp, bounds);

end


% Synchronoise the streams such that they will work with the network.
% Things did in this function:
%   1. upsample streams to match other streams of higher frame rate. This
%   is only done when streams are specified by DataSyncSet to have the same
%   frame rate. Also discarded last frames longer streams to make the
%   streams have the same number of frames.
%   2. apply VAD to some streams. Here VAD is stored in one stream
%   (normally the last stream). We first upsample/downsample VAD framerate
%   to match the stream to be VADed. Then remove nonspeech segments. VAD
%   should be stored as 1-D feature stream.
%
% Author: Xiong Xiao, Temasek labs, NTU, Singapore.
% Date Created: 10 Oct 2015
% Last Modified: 21 Apr 2016
%
function [data_sync, isVAD] = SynchronizeDataStreams3(alldata, para)
[nStream, nUtt] = size(alldata);

isTensor = para.IO.isTensor;
isVAD = zeros(nStream,1);
data_sync = alldata;

ApplyVADSet = para.IO.ApplyVADSet;
DataSyncSet = para.IO.DataSyncSet;

for vi=1:length(ApplyVADSet)
    if ~isempty(ApplyVADSet{vi})
        isVAD(ApplyVADSet{vi}(end))=1;      % set whether a stream is VAD stream or not
    end
end

if isempty(DataSyncSet) && isempty(ApplyVADSet)
    return;
end

for utt_i = 1:nUtt
    % Apply VAD and segmentation first, if required
    for vi=1:length(ApplyVADSet)
        curr_vad_set = ApplyVADSet{vi};
        if isempty(curr_vad_set); continue; end
        data_sync{curr_vad_set(1), utt_i} = SynchronizeStreamsVAD( data_sync(curr_vad_set, utt_i), para.IO.vadAction{vi} );
    end

    % Apply Frame rate synchronization to all Sync Sets
    for di=1:length(DataSyncSet)
        curr_sync_set = DataSyncSet{di};
        if isempty(curr_sync_set); continue; end
        data_sync(curr_sync_set, utt_i) = SynchronizeStreamsFrameRate2(  data_sync(curr_sync_set, utt_i) , para.IO.frame_rate(curr_sync_set) , isTensor(curr_sync_set)  );
    end
end
end