function model = createToyModelForConstraints()
% createToyModelForConstraints creates a toy model for
% including coupling constraints for functional testing.
% The model created looks as follows:
%
%
%   <-> A -----> B ---> C --> E <->
%        \       ^      ^
%         \     /      /
%          -> D  ---> F
%
%      H -> I -> J
%       ^        /
%        \      /
%           ---
%
model = createModel();
%Reactions in {Rxn Name, MetaboliteNames, Stoichiometric coefficient} format
Reactions = {'R1',{'A','B'},[-1 1],-1000,1000;...
             'R2',{'A', 'D'},[-1 2],0,1000;...
             'R3',{'D','B'},[-1 1 ],0,30;...
             'R4',{'B','C'},[-1 1],0,20;...
             'R5',{'C','E'},[-1 1],0,1000;...
             'R6',{'D','F'},[-1 1],0,20;...
             'R7',{'F','C'},[-1 1],0,30;...
             'R8',{'H','I'},[-1 1],0,1000;...
             'R9',{'I','J'},[-1 1],0,1000;...
             'R10',{'J','H'},[-1 1],0,1000;...
             };
ExchangedMets = {'A','E'};
%Add Reactions
for i = 1:size(Reactions,1)
    %All reactions are irreversible
    model = addReaction(model,Reactions{i,1},'metaboliteList',Reactions{i,2},'stoichCoeffList',Reactions{i,3},'lowerBound',Reactions{i,4},'upperBound',Reactions{i,5});
end
model = changeGeneAssociation(model,'R3','G1 or G2');
model = changeGeneAssociation(model,'R4','G3 or G5');
model = changeGeneAssociation(model,'R7','G4 and (G1 or G2)');
model = changeGeneAssociation(model,'R4','(G3 or G5) and G6');

%Add Exchangers
model = addExchangeRxn(model,ExchangedMets,-1000*ones(numel(ExchangedMets),1),1000*ones(numel(ExchangedMets),1));
model = changeObjective(model,'EX_E',1);
model = addCOBRAConstraints(model,{'R3','R7'},5, 'c',[1,1],'dsense','G','ConstraintID','R3_and_R7_above_5');
model = addCOBRAConstraints(model,{'R4','R6'},30, 'c',[1,1],'dsense','L','ConstraintID','R4_and_R6_lowerthan_30');


classdef test_net < matlab.unittest.TestCase

  properties
    num_output
    model_file
    net
  end

  methods (Static)
    function model_file = simple_net_file(num_output)
      model_file = tempname();
      fid = fopen(model_file, 'w');
      fprintf(fid, [ ...
        'name: "testnet" force_backward: true\n' ...
        'layer { type: "DummyData" name: "data" top: "data" top: "label"\n' ...
        'dummy_data_param { num: 5 channels: 2 height: 3 width: 4\n' ...
        '    num: 5 channels: 1 height: 1 width: 1\n' ...
        '    data_filler { type: "gaussian" std: 1 }\n' ...
        '    data_filler { type: "constant" } } }\n' ...
        'layer { type: "Convolution" name: "conv" bottom: "data" top: "conv"\n' ...
        '  convolution_param { num_output: 11 kernel_size: 2 pad: 3\n' ...
        '    weight_filler { type: "gaussian" std: 1 }\n' ...
        '    bias_filler { type: "constant" value: 2 } }\n' ...
        '    param { decay_mult: 1 } param { decay_mult: 0 }\n' ...
        '    }\n' ...
        'layer { type: "InnerProduct" name: "ip" bottom: "conv" top: "ip"\n' ...
        '  inner_product_param { num_output: ' num2str(num_output) ...
        '    weight_filler { type: "gaussian" std: 2.5 }\n' ...
        '    bias_filler { type: "constant" value: -3 } } }\n' ...
        'layer { type: "SoftmaxWithLoss" name: "loss" bottom: "ip" bottom: "label"\n' ...
        '  top: "loss" }' ]);
      fclose(fid);
    end
  end
  methods
    function self = test_net()
      self.num_output = 13;
      self.model_file = caffe.test.test_net.simple_net_file(self.num_output);
      self.net = caffe.Net(self.model_file, 'train');
      % also make sure get_solver runs
      caffe.get_net(self.model_file, 'train');

      % fill in valid labels
      self.net.blobs('label').set_data(randi( ...
        self.num_output - 1, self.net.blobs('label').shape));

      delete(self.model_file);
    end
  end
  methods (Test)
    function self = test_blob(self)
      self.net.blobs('data').set_data(10 * ones(self.net.blobs('data').shape));
      self.verifyEqual(self.net.blobs('data').get_data(), ...
        10 * ones(self.net.blobs('data').shape, 'single'));
      self.net.blobs('data').set_diff(-2 * ones(self.net.blobs('data').shape));
      self.verifyEqual(self.net.blobs('data').get_diff(), ...
        -2 * ones(self.net.blobs('data').shape, 'single'));
      original_shape = self.net.blobs('data').shape;
      self.net.blobs('data').reshape([6 5 4 3 2 1]);
      self.verifyEqual(self.net.blobs('data').shape, [6 5 4 3 2 1]);
      self.net.blobs('data').reshape(original_shape);
      self.net.reshape();
    end
    function self = test_layer(self)
      self.verifyEqual(self.net.params('conv', 1).shape, [2 2 2 11]);
      self.verifyEqual(self.net.layers('conv').params(2).shape, 11);
      self.verifyEqual(self.net.layers('conv').type(), 'Convolution');
    end
    function test_forward_backward(self)
      self.net.forward_prefilled();
      self.net.backward_prefilled();
    end
    function test_inputs_outputs(self)
      self.verifyEqual(self.net.inputs, cell(0, 1))
      self.verifyEqual(self.net.outputs, {'loss'});
    end
    function test_save_and_read(self)
      weights_file = tempname();
      self.net.save(weights_file);
      model_file2 = caffe.test.test_net.simple_net_file(self.num_output);
      net2 = caffe.Net(model_file2, 'train');
      net2.copy_from(weights_file);
      net3 = caffe.Net(model_file2, weights_file, 'train');
      delete(model_file2);
      delete(weights_file);
      for l = 1:length(self.net.layer_vec)
        for i = 1:length(self.net.layer_vec(l).params)
          self.verifyEqual(self.net.layer_vec(l).params(i).get_data(), ...
            net2.layer_vec(l).params(i).get_data());
          self.verifyEqual(self.net.layer_vec(l).params(i).get_data(), ...
            net3.layer_vec(l).params(i).get_data());
        end
      end
    end
  end
end


filename='Bridge_hexahedra_coarse';
 ptype = 'MACRO';
method = 'SIMPALL';
materialType = 'ISOTROPIC';
initial_case = 'full';
cost = {'compliance';'perimeter'};
weights = [1, 0.1];
constraint = {'volumeConstraint'};
optimizer = 'SLERP'; incrementFactor = 1;
filterType = 'P1';

nsteps = 5;
Vfrac_final = 0.05;
Perimeter_target = 1;
optimality_final = 1e-3;
constr_final =1e-3;

Vfrac_initial = 1;
optimality_initial = 1e-2;
constr_initial = 1e-3;
TOL.rho_plus = 1;
TOL.rho_minus = 0;
TOL.E_plus = 1;
TOL.E_minus = 1e-3;
TOL.nu_plus = 1/3;
TOL.nu_minus = 1/3;


function Mh = hmxHorzcat(varargin)
%+========================================================================+
%|                                                                        |
%|         OPENHMX - LIBRARY FOR H-MATRIX COMPRESSION AND ALGEBRA         |
%|           openHmx is part of the GYPSILAB toolbox for Matlab           |
%|                                                                        |
%| COPYRIGHT : Matthieu Aussal (c) 2017-2018.                             |
%| PROPERTY  : Centre de Mathematiques Appliquees, Ecole polytechnique,   |
%| route de Saclay, 91128 Palaiseau, France. All rights reserved.         |
%| LICENCE   : This program is free software, distributed in the hope that|
%| it will be useful, but WITHOUT ANY WARRANTY. Natively, you can use,    |
%| redistribute and/or modify it under the terms of the GNU General Public|
%| License, as published by the Free Software Foundation (version 3 or    |
%| later,  http://www.gnu.org/licenses). For private use, dual licencing  |
%| is available, please contact us to activate a "pay for remove" option. |
%| CONTACT   : matthieu.aussal@polytechnique.edu                          |
%| WEBSITE   : www.cmap.polytechnique.fr/~aussal/gypsilab                 |
%|                                                                        |
%| Please acknowledge the gypsilab toolbox in programs or publications in |
%| which you use it.                                                      |
%|________________________________________________________________________|
%|   '&`   |                                                              |
%|    #    |   FILE       : hmxHorzcat.m                                  |
%|    #    |   VERSION    : 0.42                                          |
%|   _#_   |   AUTHOR(S)  : Matthieu Aussal                               |
%|  ( # )  |   CREATION   : 14.03.2017                                    |
%|  / 0 \  |   LAST MODIF : 15.07.2018                                    |
%| ( === ) |   SYNOPSIS   : H-Matrix horizontal concatenation             |
%|  `---'  |                                                              |
%+========================================================================+

%%% Input analysis
Ml = varargin{1};
Mr = varargin{2};
if (nargin == 2)
    if isequal(Ml.pos{1},Mr.pos{1})
        Ix = (1:size(Ml,1))';
        Iy = (1:size(Ml,2)+size(Mr,2))';
    else
        error('hmxHorzcat.m : unavailable case');
    end
else
    Ml = varargin{1};
    Mr = varargin{2};
    Ix = varargin{3};
    Iy = varargin{4};
end

%%% Preparation
% Particles
X = Ml.pos{1}(Ix,:);
Y = [Ml.pos{2} ; Mr.pos{2}];
Y = Y(Iy,:);

% Accuracy
tol = max(Ml.tol,Mr.tol);

% Initialiation
Mh = hmx(X,Y,tol);

% Admissibility
[isfar,Xdim,Ydim] = hmxFar(Mh);

% Y Indices
bool = (Iy<=size(Ml,2));
Iyl  = Iy(bool);
Iyr  = Iy(~bool)-size(Ml,2);

% Compression for far distances
if isfar
    % Compression
    [Al,Bl] = lowrank(Ml,Ix,Iyl);
    [Ar,Br] = lowrank(Mr,Ix,Iyr);

    % Concatenation
    A = [Al,Ar];
    B = zeros(size(A,2),length(Iy));
    B(1:size(Al,2),bool)      = Bl;
    B(size(Al,2)+1:end,~bool) = Br;

    % Recompression
    [A,B] = hmxQRSVD(A,B,Mh.tol);

    % Validation
    flag = (numel(A)+numel(B)) <= prod(size(Mh));

else
    flag = 0;
end

%%% Compression
if flag
    % Type
    Mh.typ = 1;

    % Low-rank
    Mh.dat = {A,B};

%%%% Full or sparse for smallest box (stopping criterion)
elseif (min(size(Mh)) < 100)
    % Type
    Mh.typ = 2;

    % Full
    Mh.dat = zeros(size(Mh));

    % Fill data
    Mh.dat(:,bool)  = full(Ml,Ix,Iyl);
    Mh.dat(:,~bool) = full(Mr,Ix,Iyr);

%%% H-Matrix (recursion)
else
    % Type
    Mh.typ = 0;

    % Subdivision for X
    [I1,I2] = hmxSubdivide(X,Xdim);
    Mh.row  = {I1 , I1 , I2 , I2};

    % Subdivision for Y
    [I1,I2] = hmxSubdivide(Y,Ydim);
    Mh.col  = {I1 , I2 , I1 , I2};

    % H-Matrix (recursion)
    for i = 1:4
        % Coordinates
        Ir = Mh.row{i};
        Ic = Mh.col{i};

        % Recursion
        Mh.chd{i} = hmxHorzcat(Ml,Mr,Ix(Ir),Iy(Ic));
    end

    % Fusion
    Mh = hmxFusion(Mh);
end
end

% function Mh = hmxHorzcat(Ml,Mr)
% %+========================================================================+
% %|                                                                        |
% %|         OPENHMX - LIBRARY FOR H-MATRIX COMPRESSION AND ALGEBRA         |
% %|           openHmx is part of the GYPSILAB toolbox for Matlab           |
% %|                                                                        |
% %| COPYRIGHT : Matthieu Aussal (c) 2017-2018.                             |
% %| PROPERTY  : Centre de Mathematiques Appliquees, Ecole polytechnique,   |
% %| route de Saclay, 91128 Palaiseau, France. All rights reserved.         |
% %| LICENCE   : This program is free software, distributed in the hope that|
% %| it will be useful, but WITHOUT ANY WARRANTY. Natively, you can use,    |
% %| redistribute and/or modify it under the terms of the GNU General Public|
% %| License, as published by the Free Software Foundation (version 3 or    |
% %| later,  http://www.gnu.org/licenses). For private use, dual licencing  |
% %| is available, please contact us to activate a "pay for remove" option. |
% %| CONTACT   : matthieu.aussal@polytechnique.edu                          |
% %| WEBSITE   : www.cmap.polytechnique.fr/~aussal/gypsilab                 |
% %|                                                                        |
% %| Please acknowledge the gypsilab toolbox in programs or publications in |
% %| which you use it.                                                      |
% %|________________________________________________________________________|
% %|   '&`   |                                                              |
% %|    #    |   FILE       : hmxHorzcat.m                                  |
% %|    #    |   VERSION    : 0.40                                          |
% %|   _#_   |   AUTHOR(S)  : Matthieu Aussal                               |
% %|  ( # )  |   CREATION   : 14.03.2017                                    |
% %|  / 0 \  |   LAST MODIF : 14.03.2018                                    |
% %| ( === ) |   SYNOPSIS   : Concatenate H-Matrix along 2nd dimension      |
% %|  `---'  |                with the rule                                 |
% %|         |                H-Matrix > Full > Compr                       |
% %+========================================================================+
%
% % Check dimensions
% if ~(isa(Ml,'hmx') && isa(Mr,'hmx'))
%     error('hmxHorzcat.m : unavailable case')
% elseif (size(Ml,1)~=size(Mr,1))
%     error('hmxHorzcat.m : Dimensions of matrices being concatenated are not consistent')
% elseif norm(Ml.pos{1}-Mr.pos{1},'inf') > 1e-12
%     error('hmxHorzcat.m : unavailable case')
% end
%
% % Initialization
% Mh = hmx(Ml.pos{1},[Ml.pos{2};Mr.pos{2}],Ml.tol);
%
%
% %%% [H-Matrix & H-Matrix] -> H-Matrix
% if (Ml.typ == 0) && (Mr.typ == 0)
%     % Particles distance average
%     Yl1 = mean(Ml.chd{1}.pos{2},1);
%     Yl2 = mean(Ml.chd{2}.pos{2},1);
%     Yr1 = mean(Mr.chd{1}.pos{2},1);
%     Yr2 = mean(Mr.chd{2}.pos{2},1);
%
%     % Concatenation pairs
%     D     = [norm(Yl1-Yr1) norm(Yl1-Yr2) norm(Yl2-Yr1) norm(Yl2-Yr2)];
%     [r,d] = min(D);
%     if (d == 1) || (d == 4)
%         I = [1 1 ; 2 2 ; 3 3 ; 4 4];
%     else
%         I = [1 2 ; 2 1 ; 3 4 ; 4 3];
%     end
%
%     % Construction (recursion)
%     Mh.typ = 0;
%     for i = 1:4
%         Mh.chd{i} = hmxHorzcat(Ml.chd{I(i,1)},Mr.chd{I(i,2)});
%         Mh.row{i} = Ml.row{i};
%         Mh.col{i} = [Ml.col{I(i,1)};size(Ml,2)+Mr.col{I(i,2)}];
%     end
%
% %     % Construction (recursion)
% %     Mh.typ = 0;
% %     for i = 1:4
% %         Mh.chd{i} = hmxHorzcat(Ml.chd{i},Mr.chd{i});
% %         Mh.row{i} = Ml.row{i};
% %         Mh.col{i} = [Ml.col{i};size(Ml,2)+Mr.col{i}];
% %     end
%
%
% %     % Split for too big full leaf
% %     for i = 1:4
% %         if (Mh.chd{i}.typ == 2) && (min(size(Mh.chd{i})) > 100)
% %             tmp       = Mh.chd{i}
% %             Mh.chd{i} = hmxBuilder(tmp.pos{1},tmp.pos{2},tmp.dat,tmp.tol);
% %         end
% %     end
% %
% %     % Fusion
% %     Mh = hmxFusion(Mh);
%
% % [H-Matrix & Compr] -> H-Matrix
% elseif (Ml.typ == 0) && (Mr.typ == 1)
%     Mr = hmxSplit(Ml.row,Mr);
%     Mh = hmxHorzcat(Ml,Mr);
%
% % [H-Matrix & Full] -> H-Matrix
% elseif (Ml.typ == 0) && (Mr.typ == 2)
%     Mr = hmxSplit(Ml.row,Mr);
%     Mh = hmxHorzcat(Ml,Mr);
%
%
% %%% [Compr & H-matrix] -> H-Matrix
% elseif (Ml.typ == 1) && (Mr.typ == 0)
%     Ml = hmxSplit(Mr.row,Ml);
%     Mh = hmxHorzcat(Ml,Mr);
%
% % [Compr & Compr] -> Compr
% elseif (Ml.typ == 1) && (Mr.typ == 1)
%     % Concatenation
%     nl = size(Ml.dat{1},2);
%     nr = size(Mr.dat{1},2);
%     A  = [Ml.dat{1} , Mr.dat{1}];
%     B  = [Ml.dat{2} , zeros(nl,size(Mr,2)) ;
%         zeros(nr,size(Ml,2)) , Mr.dat{2}] ;
%
%     % Recompression
%     [A,B] = hmxQRSVD(A,B,Ml.tol);
%
%     % Update
%     Mh.typ = 1;
%     Mh.dat = {A,B};
%
%
% % [Compr & Full] -> Full
% elseif (Ml.typ == 1) && (Mr.typ == 2)
%     Mh.typ = 2;
%     Mh.dat = [Ml.dat{1}*Ml.dat{2} , Mr.dat];
%
%
% %%% [Full & H-matrix] -> H-Matrix
% elseif (Ml.typ == 2) && (Mr.typ == 0)
%     Ml = hmxSplit(Mr.row,Ml);
%     Mh = hmxHorzcat(Ml,Mr);
%
% % [Full & Compr] -> Full
% elseif (Ml.typ == 2) && (Mr.typ == 1)
%     Mh.typ = 2;
%     Mh.dat = [Ml.dat , Mr.dat{1}*Mr.dat{2}];
%
% % [Full & Full] -> Full
% elseif (Ml.typ == 2) && (Mr.typ == 2)
%     Mh.typ = 2;
%     Mh.dat = [Ml.dat,Mr.dat];
%
% else
%     error('hmxHorzcat.m : unavailable case')
% end
% end
%
%
% function Mh = hmxSplit(row,Mh)
% % Subdivision for X
% Mh.row = row;
%
% % Subdivision for Y
% [~,~,Ydim] = hmxFar(Mh);
% [I1,I2]    = hmxSubdivide(Mh.pos{2},Ydim);
% Mh.col     = {I1 , I2 , I1 , I2};
%
% % H-Matrix (recursion)
% for i = 1:4
%     % Initialization
%     Mh.chd{i} = hmx(Mh.pos{1}(Mh.row{i},:),Mh.pos{2}(Mh.col{i},:),Mh.tol);
%
%     % H-Matrix
%     if (Mh.typ == 0)
%         error('hmxSplit.m : unavailable case')
%
%     % Compressed leaf
%     elseif (Mh.typ == 1)
%         % Subdivision
%         A = Mh.dat{1}(Mh.row{i},:);
%         B = Mh.dat{2}(:,Mh.col{i});
%
%         % Recompression
%         [A,B] = hmxQRSVD(A,B,Mh.tol);
%
%         % Update
%         Mh.chd{i}.typ = 1;
%         Mh.chd{i}.dat = {A,B};
%         Mh.chd{i}.tol = Mh.tol;
%
%     % Full leaf
%     elseif (Mh.typ == 2)
%         Mh.chd{i}.typ = 2;
%         Mh.chd{i}.dat = Mh.dat(Mh.row{i},Mh.col{i});
%         Mh.chd{i}.tol = Mh.tol;
%     end
% end
%
% % Erase data
% Mh.typ = 0;
% Mh.dat = [];
% end


function [CTTraceS, RTOGPBVectorsM, RTOGPBVectorsM_MC, PBMaskM, rowPBV, colPBV, xPBPosV, yPBPosV, beamlet_delta_x, beamlet_delta_y] = ...
   getPBRayData_cerr3(sourceS, numSamplePts, xySampleRate,planC, xPosV, yPosV, beamlet_delta_x, beamlet_delta_y, gA);
% function [CTTraceS, RTOGPBVectorsM, RTOGPBVectorsM_MC, PBMaskM, rowPBV, colPBV, xPBPosV, yPBPosV, beamlet_delta_x, beamlet_delta_y] = ...
%    getPBRayData_cerr3(edgeS, sourceS, numSamplePts, xySampleRate,planC, xPosV, yPosV, beamlet_delta_x, beamlet_delta_y, gA);
%JOD
% global planC
%
% indexS=planC{end};

water = 1000; %Assumes water equals 1000.

%-----------Get CT scan---------------------%

% [CTUniform3D, CTUniformInfoS] = getUniformizedCTScan(1,planC);
scanNum = 1;
[CTUniform3D, CTUniformInfoS] = getUniformizedCTScan(1,scanNum);

xOffset = CTUniformInfoS.xOffset;
yOffset = CTUniformInfoS.yOffset;

%-----------Fix source characteristics---------------------%

orgV   = [sourceS.isocenter.x, sourceS.isocenter.y, sourceS.isocenter.z];

%-----------Get ray parameters---------------------%

% [RTOGPBVectorsM, RTOGPBVectorsM_MC, PBMaskM, rowPBV, colPBV, xPBPosV, yPBPosV] = ...
%       getPBRays(edgeS, sourceS, xySampleRate);
% [RTOGPBVectorsM, RTOGPBVectorsM_MC, PBMaskM, rowPBV, colPBV, xPBPosV, yPBPosV, beamlet_delta_x, beamlet_delta_y] = ...
%       getPBRays(xPosV, yPosV, beamlet_delta_x, beamlet_delta_y, gA);
[RTOGPBVectorsM, RTOGPBVectorsM_MC, PBMaskM, rowPBV, colPBV, xPBPosV, yPBPosV, beamlet_delta_x, beamlet_delta_y] = ...
      getPBRays_planChk(xPosV, yPosV, beamlet_delta_x, beamlet_delta_y, sourceS);

rayLength = 500;  %in cm.  This is the length of the rays which are passed
                  %through the CT matrix to determine cumulative CT densities.

numSlices = size(CTUniform3D,3);

zFirst = CTUniformInfoS.firstZValue;

sliceThickness = CTUniformInfoS.sliceThickness;

%minBox an maxBox containt coordinates of the corners of the CT box as used
%by the ray intersection routine.

maxBoxS.z = (numSlices - 1) * sliceThickness + zFirst + sliceThickness/2;

minBoxS.z = zFirst - sliceThickness/2;

delta_xy = CTUniformInfoS.grid1Units;

imageWidth = CTUniformInfoS.size(1);

minBoxS.x = - imageWidth/2 * delta_xy + xOffset;
maxBoxS.x =   imageWidth/2 * delta_xy + xOffset;

minBoxS.y = - imageWidth/2 * delta_xy + yOffset;
maxBoxS.y =   imageWidth/2 * delta_xy + yOffset;

imageWidth = CTUniformInfoS.sizeOfDimension1;

CTTraceS = struct('CTNumsRay',[],'CTCumNumsRay',[],'distSamplePts',[]);

for i = 1 : size(RTOGPBVectorsM,1)

  rayDeltaS.x = RTOGPBVectorsM(i,1) * rayLength;
  rayDeltaS.y = RTOGPBVectorsM(i,2) * rayLength;
  rayDeltaS.z = RTOGPBVectorsM(i,3) * rayLength;

  %are the components of the ray's direction and maximum length.

  deltaV = [rayDeltaS.x, rayDeltaS.y, rayDeltaS.z];

  t_entrance = rayBoxIntersection(sourceS,rayDeltaS,minBoxS,maxBoxS);

  %The entrance point is therefore
  entranceV = orgV + t_entrance * deltaV;

  %Reflect to find exit point (assume length of ray is long enough that ray does exit):

  if t_entrance ~= -1

    %find exit point
    %get end of ray
    rayOrgS2.xRel = sourceS.xRel + rayDeltaS.x;  %reflected source positions
    rayOrgS2.yRel = sourceS.yRel + rayDeltaS.y;
    rayOrgS2.zRel = sourceS.zRel + rayDeltaS.z;

    rayDeltaS2.x = - rayDeltaS.x;
    rayDeltaS2.y = - rayDeltaS.y;
    rayDeltaS2.z = - rayDeltaS.z;

    rayOrgS2.isocenter = sourceS.isocenter;

    t = rayBoxIntersection(rayOrgS2,rayDeltaS2,minBoxS,maxBoxS);

    t_exit = 1 - t;

    exitV = orgV + t_exit * deltaV;

else
    error('PB Ray does not intersect CT scan.');
end

  %Now produce a set of sampling points between the entrance and the exit

  nV = 1 : numSamplePts;

  delta_t  = (t_exit - t_entrance)/(numSamplePts - 1);

  tV = t_entrance + (nV - 1) * delta_t;

  CTTraceS(i).distSamplePts = tV * sum(deltaV.^2).^0.5;

  sampleV.x =  sourceS.xRel + tV * deltaV(1);

  sampleV.y =  sourceS.yRel + tV * deltaV(2);

  sampleV.z =  sourceS.zRel + tV * deltaV(3);

  sampleRTOGV.x = sampleV.x + sourceS.isocenter.x;
  sampleRTOGV.y = sampleV.y + sourceS.isocenter.y;
  sampleRTOGV.z = sampleV.z + sourceS.isocenter.z;

  %---------Sample CT densities----------%

  %To go from sample points in RTOG system to CT densities, we convert as follows:

  %What is the slice number?
  sliceV = 1 + (sampleRTOGV.z - zFirst)/sliceThickness;

  %Now do 3-D interpolation:
  zFieldV = [minBoxS.z + 0.5 * sliceThickness:sliceThickness:maxBoxS.z - 0.5 * sliceThickness];
  xFieldV = [minBoxS.x + 0.5 * delta_xy, delta_xy, maxBoxS.x - 0.5 * delta_xy];
  yFieldV = [minBoxS.y + 0.5 * delta_xy, delta_xy, maxBoxS.y - 0.5 * delta_xy];

  [CTNumsV] = finterp3(sampleRTOGV.x, sampleRTOGV.y, sampleRTOGV.z, CTUniform3D, xFieldV, yFieldV, zFieldV, 0);

%   [CTNumsV] = finterp3(sampleRTOGV.x, sampleRTOGV.y, sampleRTOGV.z, CTUniform3D, xFieldV, yFieldV, zFieldV, 0);

  CTTraceS(i).densityRay = delta_t * norm(deltaV) * CTNumsV/water;
  CTTraceS(i).cumDensityRay = cumsum(CTTraceS(i).densityRay);  %Account for sampling rate to convert to g/cm^2.

  if any(CTTraceS(i).cumDensityRay > 50)
      warning('Cumulative density ray appears to exceed maximum length.');
  end

end

%-----------fini---------------------%


%  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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
%function gdpowert
%GDPOWERT Unit test for the function GDPOWER.

%	O. Lemoine - August 1996.

N=256;

% K=1 : constant group delay
[sig,gd]=gdpower(N,1);
t0=N; t=(1:N);
if any(gd~=t0),
 error('gdpower test 1 failed');
end
if any(sig(t~=t0)>sqrt(eps)),
 error('gdpower test 2 failed');
end

% K=2 : linear group delay
[sig,gd]=gdpower(N,2);
ifl=instfreq(sig);
[s,iflaw]=fmlin(N);
if any(abs(ifl(3:N-2)-iflaw(3:N-2))>5e-2),
 error('gdpower test 3 failed');
end

% K=1/2
[sig,gpd]=gdpower(N,1/2);
fnorm=linspace(0.01,0.45,108);
fnorm=fnorm(2:108);
gd=sgrpdlay(sig,fnorm);
if any(abs(gd-gpd(4:110)')/N>5e-2),
 error('gdpower test 4 failed');
end;

% K=0
[sig,gpd]=gdpower(N,0);
fnorm=linspace(0.01,0.45,108);
fnorm=fnorm(2:108);
gd=sgrpdlay(sig,fnorm);
if any(abs(gd-gpd(4:110)')/N>5e-2),
 error('gdpower test 5 failed');
end;

% K=-1
[sig,gpd]=gdpower(N,-1);
fnorm=linspace(0.01,0.45,108);
fnorm=fnorm(2:108);
gd=sgrpdlay(sig,fnorm);
if any(abs(gd-gpd(4:110)')/N>5e-2),
 error('gdpower test 6 failed');
end;

N=221;

% K=1 : constant group delay
[sig,gd]=gdpower(N,1);
t0=N; t=(1:N);
if any(gd~=t0),
 error('gdpower test 7 failed');
end
if any(sig(t~=t0)>sqrt(eps)),
 error('gdpower test 8 failed');
end

% K=2 : linear group delay
[sig,gd]=gdpower(N,2);
ifl=instfreq(sig);
[s,iflaw]=fmlin(N);
if any(abs(ifl(5:N-2)-iflaw(5:N-2))>5e-2),
 error('gdpower test 9 failed');
end

% K=1/2
[sig,gpd]=gdpower(N,1/2);
fnorm=linspace(0.01,0.45,108);
fnorm=fnorm(2:108);
gd=sgrpdlay(sig,fnorm);
if any(abs(gd-gpd(4:110)')/N>5e-2),
 error('gdpower test 10 failed');
end;

% K=0
[sig,gpd]=gdpower(N,0);
fnorm=linspace(0.01,0.45,108);
fnorm=fnorm(2:108);
gd=sgrpdlay(sig,fnorm);
if any(abs(gd-gpd(4:110)')/N>5e-2),
 error('gdpower test 11 failed');
end;

% K=-1
[sig,gpd]=gdpower(N,-1);
fnorm=linspace(0.01,0.45,108);
fnorm=fnorm(2:108);
gd=sgrpdlay(sig,fnorm);
if any(abs(gd-gpd(4:110)')/N>5e-2),
 error('gdpower test 12 failed');
end;


function Z = ge(X,Y)
%GE Greater than or equal (>=) for tensors.
%
%   See also TENSOR.
%
%MATLAB Tensor Toolbox.
%Copyright 2012, Sandia Corporation.

% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others.
% http://www.sandia.gov/~tgkolda/TensorToolbox.
% Copyright (2012) Sandia Corporation. Under the terms of Contract
% DE-AC04-94AL85000, there is a non-exclusive license for use of this
% work by or on behalf of the U.S. Government. Export of this data may
% require a license from the United States Government.
% The full license terms can be found in the file LICENSE.txt

Z = tenfun(@ge,X,Y);


%% Housekeeping
clear
close all
clc
%%
tic
%% create data

run('tut01_data')

%% estimate models

run('tut02_estimation')

%% compare residuals

run('tut03_compare_residuals')

%% set identification

run('tut04_identification')

%% Compare structural shocks

run('tut04b_compare_structural_shocks')
%% simple choleski IRFs

run('tut05_compare_choleski_irfs')

%% more involved restrictions

run('tut06_compare_combos_irfs')

%% variance decomposition

run('tut07_variance_decomposition')

%% historical decomposition

run('tut08_historical_decomposition')

%% sample distribution of parameters

run('tut09_bootstrap')

%% distribution of variance decomposition

run('tut10_variance_decomposition_distribution')

%% distribution of historical decomposition

run('tut11_historical_decomposition_distribution')

%% distribution of IRFs

run('tut12_irf_distribution')

%% Bayesian estimation

run('tut13_bayestimation')

%% forecast

run('tut14_bayesforecast')

%% conditional forecast

run('tut15_conditionalforecast')

%% entropic tilting

%% clean up
toc

delete *.mat


%% Data Sturcture for Degree of Freedom (DOF)
%
% For various elements, dofs could be associated to vertices, edges, or
% faces with apporipate orientation. In this doc, we collect data
% structures for commonly used elements.
%
% * <dofedgedoc.html Dof on edges: 2-D>
% * <dof3edgedoc.html Dof on edges: 3-D>
% * <dofP2doc.html Dof of P2 elements>


function z = times( x, y, oper )

%   Disciplined convex programming information for TIMES:
%      In general, disciplined convex programs must obey the "no-product
%      rule" which states that two non-constant expressions cannot be
%      multiplied together. Under this rule, the following combinations
%      are allowed:
%         {constant} .* {non-constant}  {non-constant} .* {constant}
%      Furthermore, if the non-constant expression is nonlinear, then
%      the constant term must be real.
%
%      A lone exception to the no-product rule is made for quadratic
%      forms: two affine expressions may be multiplied together if the
%      result is convex or concave. For example, the construction
%         variable x(n)
%         x.*x  <= 1;
%      would be permitted because each element of x.*x is convex.
%
%   Disciplined geometric programming information for TIMES:
%      Both terms in a multiplication must have the same log-curvature,
%      so the following products are permitted:
%         {log-convex} .* {log-convex}  {log-concave} .* {log-concave}
%         {log-affine} .* {log-affine}
%      Note that log-affine expressions are both log-convex and
%      log-concave.
%
%   For vectors, matrices, and arrays, these rules are verified
%   indepdently for each element.

persistent P
if isempty( P ),
    P.map = cvx_remap( ...
        ... % Invalid combinations: negative of log-concave, gp term
        { { 'negative' },   { 'l_concave_', 'g_valid' } }, ...
        { { 'l_concave_', 'g_valid' }, { 'negative' }   }, ...
        ... % Left-multiply by constant
        { { 'constant' },   { 'affine' }     }, ...
        { { 'real' },       { 'valid'  }     }, ...
        ... % Right-multiply by constant
        { { 'affine' },     { 'constant' }   }, ...
        { { 'valid' },      { 'real'  }      }, ...
        ... % Geometric
        { { 'l_convex' } }, ...
        { { 'l_concave' } }, ...
        ... % Potential quadratic form
        { { 'affine', 'p_convex', 'n_concave' } }, ...
        [ 0, 0, 1, 1, 2, 2, 3, 3, 4 ] );
    P.funcs = { @times_l, @times_r, @times_g, @times_q };
    P.constant = [];
end
if nargin < 3, oper = '.*'; end
P.name = oper;
z = cvx_binary_op( P, x, y );

function z = times_l( x, y )
% constant .* something
z = bsxfun( @times, cvx_constant( x ).', cvx_basis( y ) );
z = cvx( size(z,2), z );

function z = times_r( x, y )
% constant .* something
z = bsxfun( @times, cvx_basis( x ), cvx_constant( y ).' );
z = cvx( size(z,2), z );

function z = times_g( x, y )
% geom .* geom
z = exp( plus_nc( log( x ), log( y ) ) );

function z = times_q( x, y )
% affine .* affine
% p_convex .* p_convex
% n_concave .* n_concave
xA = x.basis_;
yA = y.basis_;
mm = max( size( xA, 1 ), size( yA, 1 ) );
xA( end + 1 : mm, : ) = 0;
yA( end + 1 : mm, : ) = 0;
xB  = xA( 2 : end, : );
yB  = yA( 2 : end, : );
cyB = conj( yB );
alpha = sum( yB .* cyB, 1 );
alpha = sum( bsxfun( @times, xB, yB ), 1 ) ./ max( alpha, realmin );
if nnz( xB - bsxfun( @times, alpha, cyB ) > 2 * eps * sqrt( conj( xB ) .* xB ) ),
    cvx_throw( 'Disciplined convex programming error:\n    Invalid quadratic form(s): not a square.' );
elseif any( abs(imag(alpha)) > 2 * eps * abs(real(alpha)) ),
    cvx_throw( 'Disciplined convex programming error:\n    Invalid quadratic form(s): not real.' );
else
    if isreal( xB ),
        z = square( y );
    else
        z = square( abs( y ) );
    end
    z.basis_ = bsxfun( @times, alpha, z.basis_ );
    offset = xA(1,:) - alpha .* conj( yA(1,:) );
    if any( offset ),
        z = z + offset.' .* y;
    end
end

% Copyright 2005-2014 CVX Research, Inc.
% See the file LICENSE.tx for full copyright information.
% The command 'cvx_where' will show where this file is located.


function F = asin(F, varargin)
%ASIN   Inverse sine of a CHEBFUN.
%   ASIN(F) computes the inverse sine of the CHEBFUN F.
%
%   ASIN(F, PREF) does the same but uses the CHEBFUNPREF object PREF when
%   computing the composition.
%
% See also SIN, ASIND.

% Copyright 2017 by The University of Oxford and The Chebfun Developers. See
% http://www.chebfun.org/ for Chebfun information.

% Call the compose method:
F = compose(F, @asin, varargin{:});

end


function i4_is_even_test ( )

%*****************************************************************************80
%
%% I4_IS_EVEN_TEST tests I4_IS_EVEN.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    15 December 2014
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'I4_IS_EVEN_TEST\n' );
  fprintf ( 1, '  I4_IS_EVEN reports whether an I4 is even.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  I     I4_IS_EVEN(I)\n' );
  fprintf ( 1, '\n' );

  for i = -2 : 25
    fprintf ( 1, '  %6d  %1d\n', i, i4_is_even ( i ) );
  end

  return
end


% out2 = readtimeseries('/afs/inf.ed.ac.uk/user/s08/s0880377/project/data/qdots/R1/100222/7W5UG85Y_F00000014.tif','',[],1,1);
% out14=squeeze(out2(:,:,:,0));
% o=dip_image(out14);
o=dip_image(data_out);
box1=4;
box2=2;
nclick = 10;
dipshow(7,mean(o,[],3));
coords = dipgetcoords(7,nclick);
box1x1 = coords(:,1) - box1;
box1x2 = coords(:,1) + box1;
box1y1 = coords(:,2) - box1;
box1y2 = coords(:,2) + box1;
for ii=1: 7%length(coords)
    oroi1 = o(box1x1(ii):box1x2(ii), box1y1(ii):box1y2(ii),:);
    [maxval, maxcoord] = max(max(oroi1,[],3));
    box2x1 = maxcoord(1)-box2;
    box2x2 = maxcoord(1)+box2;
    box2y1 = maxcoord(2)-box2;
    box2y2 = maxcoord(2)+box2;
    oroi2= oroi1(box2x1:box2x2,box2y1:box2y2,:);
    f(ii,:) = squeeze(double(sum(oroi2,[],[1 2])));

end

index=1;
figure(1)
for ii=1:N
    subplot(N,2,index)
    plot(f(ii,:))
      if ii<N
        set(gca,'xtick',[],'ytick',[])
    else
        set(gca,'ytick',[])
    end
    index = index +1;
    subplot(N,2,index)
    hist(f(ii,:),50);
    xlim([1.5,4]*10^5)
    if ii<N
        set(gca,'xtick',[],'ytick',[])
    else
        set(gca,'ytick',[])
    end
    index = index +1;
end
SaveImageFULL(['block' num2str(q) '_timeprofilesingledot'])
figure(2)
bar(max(f,[],2),'r')
hold on
bar(mean(f,2),'g')
bar(min(f,[],2),'b')
errorbar([1:8], mean(f,2), sqrt(var(f,[],2)),'+k')
l{1}='max';
l{2}='mean';
l{3}='min';
l{4}='sqrt(var)';
legend(l);
grid on
hold off
SaveImageFULL(['block' num2str(q) '_statistics'])


%         TestTags are useful for identifying what kind of test you're coding, as you might only want to run certain tests that are related.
classdef (TestTags = {'T1', 'Demo', 'Integration'}) fitT1_IR_Test < matlab.unittest.TestCase % It's convention to name the test file (filename being tested)_Test.m

    properties % Test class variabes; useful for common parameters between tests.
        IRdata
        Mask
        TI
    end

    methods (TestClassSetup) % Usually used to setup common testing variables, or loading data.
        function load_test_data(testCase)
            testData = load('Data/IR_demo/IR_demo.mat'); % Place full relative path, in case the file goes missing or there is a conflict

            % Set class properties
            testCase.IRdata = testData.IRdata;
            testCase.Mask = testData.Mask;
            testCase.TI = testData.TI;

        end
    end

    methods (TestClassTeardown) % This could be used to delete any files created during the test execution.
    end

    methods (Test) % Each test is it's own method function, and takes testCase as an argument.

        function test_IRfun_returns_near_expected_median_of_test_data(testCase) % Use very descriptive test method names
            %% Prepare for test
            %
            method='Magnitude';

            T1 = zeros(size(testCase.IRdata,1), size(testCase.IRdata,2));

            %% Fit voxels
            %
            for xx = 1:size(testCase.IRdata,1)
                for yy = 1:size(testCase.IRdata,2)

                    if testCase.Mask(xx,yy) % Skip masked voxels
                        [T1(xx, yy), ~, ~, ~] = fitT1_IR(testCase.IRdata(xx, yy, :), testCase.TI, method);
                    end

                end
            end

            %% Check the fit
            %

            % Mask data
            maskedT1 = T1(:).*testCase.Mask(:);
            maskedT1(maskedT1 == 0) =[];

            expectedMedian = 748; % in s, Value was identified under stable working conditions.
            actualMedian = median(maskedT1(:));

            % Assert functions are the core of unit tests; if it fails,
            % test log will return failed tests and details.
            assertTrue(testCase, abs(actualMedian-expectedMedian) < 50); % This will alert us if a code change ever produces a fit
                                                                         % with a median lower than 700 or greater than 800, signaling
                                                                         % a potential bug.
        end
    end

end


function movie_sound_field_mono_wfs(X,Y,Z,xs,src,f,outfile,conf)
%MOVIE_SOUND_FIELD_MONO_WFS movie of a WFS sound field
%
%   Usage: movie_sound_field_mono_wfs(X,Y,Z,xs,src,f,outfile,conf)
%
%   Input parameters:
%       X           - x-axis / m; single value or [xmin,xmax]
%       Y           - y-axis / m; single value or [ymin,ymax]
%       Z           - z-axis / m; single value or [zmin,zmax]
%       xs          - position of point source / m
%       src         - sourcetype of the virtual source:
%                         'pw' - plane wave (xs, ys are the direction of the
%                                plane wave in this case)
%                         'ps' - point source
%                         'fs' - focused source
%       f           - monochromatic frequency / Hz
%       outfile     - name for the movie file
%       conf        - configuration struct (see SFS_config)
%
%   MOVIE_SOUND_FIELD_MONO_WFS(X,Y,Z,xs,src,f,L,outfile,conf) generates a
%   movie of simulations of a sound field of the given source positioned at xs
%   using a WFS driving function in the temporal domain with different phase.
%
%   See also: sound_field_mono_wfs, plot_sound_field

%*****************************************************************************
% The MIT License (MIT)                                                      *
%                                                                            *
% Copyright (c) 2010-2019 SFS Toolbox Developers                             *
%                                                                            *
% Permission is hereby granted,  free of charge,  to any person  obtaining a *
% copy of this software and associated documentation files (the "Software"), *
% to deal in the Software without  restriction, including without limitation *
% the rights  to use, copy, modify, merge,  publish, distribute, sublicense, *
% and/or  sell copies of  the Software,  and to permit  persons to whom  the *
% Software is furnished to do so, subject to the following conditions:       *
%                                                                            *
% The above copyright notice and this permission notice shall be included in *
% all copies or substantial portions of the Software.                        *
%                                                                            *
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
% IMPLIED, INCLUDING BUT  NOT LIMITED TO THE  WARRANTIES OF MERCHANTABILITY, *
% FITNESS  FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT. IN NO EVENT SHALL *
% THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
% LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT, TORT  OR OTHERWISE, ARISING *
% FROM,  OUT OF  OR IN  CONNECTION  WITH THE  SOFTWARE OR  THE USE  OR OTHER *
% DEALINGS IN THE SOFTWARE.                                                  *
%                                                                            *
% The SFS Toolbox  allows to simulate and  investigate sound field synthesis *
% methods like wave field synthesis or higher order ambisonics.              *
%                                                                            *
% https://sfs.readthedocs.io                            sfstoolbox@gmail.com *
%*****************************************************************************

%% ===== Checking of input  parameters ==================================
nargmin = 8;
nargmax = 8;
narginchk(nargmin,nargmax);
isargvector(X,Y,Z);
isargxs(xs);
isargpositivescalar(f);
isargchar(src,outfile);
isargstruct(conf);

%% ===== Configuration ==================================================
% Plotting
useplot = conf.plot.useplot;
% Temporary dir
tmpdir = conf.tmpdir;

%% ===== Simulation =====================================================
phase = linspace(2*pi,0,25);
% Generate a random number string for the tmp files
rn = sprintf('%04.0f',10000*rand);
% Simulate the time by different phase values
for ii = 1:length(phase)-1
    conf.phase = phase(ii);
    conf.plot.useplot = 0;
    % Calculate sound field for the given phase
    [P,x,y,z,x0] = sound_field_mono_wfs(X,Y,Z,xs,src,f,conf);

    % === Save temporary data ===
    if ~exist(tmpdir,'dir')
        mkdir(tmpdir);
    end
    conf.plot.file = sprintf('%s/%s_%04.0f.png',tmpdir,rn,ii);
    plot_sound_field(P,x,y,z,x0,conf);
end

%% ===== Create movie ====================================================
conf.plot.useplot = useplot;
generate_movie(outfile,tmpdir,rn);

% Clean up tmp files
delete([tmpdir,'/',rn,'*.png']);

%% ===== Show movie ======================================================
if useplot
    status = system('which mplayer');
    if status
        error('%s: mplayer is needed to show this movie.',upper(mfilename));
    else
        cmd = sprintf('mplayer %s -loop 0',outfile);
        system(cmd);
    end
end


function p = addComplementarityCuts(p)

if size(p.complementary,1)>0
    p_cut = emptyNumericalModel;
    for i = 1:size(p.complementary,1)
        variables = p.complementary(i,:);
        if p.lb(variables(1))>0 & p.lb(variables(2))>0
            p_cut.F_struc(end+1,1)=p.ub(variables(2));
            p_cut.F_struc(end,1+variables(1))=-p.ub(variables(2))/p.ub(variables(1));
            p_cut.F_struc(end,1+variables(2))=-1;
            p_cut.K.l = p_cut.K.l + 1;
        end
    end
    p = mergeNumericalModels(p,p_cut);
end


function Lxx = nlp_hessfcn(om, x, lambda, cost_mult, Hs)
%NLP_HESSFCN  Evaluates Hessian of Lagrangian.
%   LXX = NLP_HESSFCN(OM, X, LAMBDA, COST_MULT)
%   LXX = NLP_HESSFCN(OM, X, LAMBDA, COST_MULT, HS)
%
%   Hessian evaluation function, suitable for use with MIPS, FMINCON, etc.
%
%   Inputs:
%     OM : Opt-Model object
%     X : optimization vector
%     LAMBDA (struct)
%       .eqnonlin : Lagrange multipliers on equality constraints
%       .ineqnonlin : Kuhn-Tucker multipliers on inequality constraints
%     COST_MULT : (optional) Scale factor to be applied to the cost
%          (default = 1).
%     HS : (optional) sparse matrix with tiny non-zero values specifying
%          the fixed sparsity structure that the resulting LXX should match
%
%   Outputs:
%     LXX : Hessian of the Lagrangian.
%
%   Examples:
%       Lxx = nlp_hessfcn(om, x, lambda, cost_mult);
%       Lxx = nlp_hessfcn(om, x, lambda, cost_mult, Hs);
%
%   See also NLP_COSTFCN, NLP_CONSFCN.

%   MP-Opt-Model
%   Copyright (c) 1996-2020, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MP-Opt-Model.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://github.com/MATPOWER/mp-opt-model for more info.

%% ----- evaluate d2f -----
[f, df, d2f] = nlp_costfcn(om, x);
d2f = d2f * cost_mult;

%%----- evaluate Hessian of equality constraints -----
d2G = om.eval_nln_constraint_hess(x, lambda.eqnonlin, 1);

%%----- evaluate Hessian of inequality constraints -----
d2H = om.eval_nln_constraint_hess(x, lambda.ineqnonlin, 0);

%%-----  do numerical check using (central) finite differences  -----
if 0
    nx = length(x);
    step = 1e-5;
    num_d2f = sparse(nx, nx);
    num_d2G = sparse(nx, nx);
    num_d2H = sparse(nx, nx);
    for i = 1:nx
        xp = x;
        xm = x;
        xp(i) = x(i) + step/2;
        xm(i) = x(i) - step/2;
        % evaluate cost & gradients
        [fp, dfp] = nlp_costfcn(om, xp);
        [fm, dfm] = nlp_costfcn(om, xm);
        % evaluate constraints & gradients
        [Hp, Gp, dHp, dGp] = nlp_consfcn(om, xp);
        [Hm, Gm, dHm, dGm] = nlp_consfcn(om, xm);
        num_d2f(:, i) = cost_mult * (dfp - dfm) / step;
        num_d2G(:, i) = (dGp - dGm) * lambda.eqnonlin   / step;
        num_d2H(:, i) = (dHp - dHm) * lambda.ineqnonlin / step;
    end
    d2f_err = full(max(max(abs(d2f - num_d2f))));
    d2G_err = full(max(max(abs(d2G - num_d2G))));
    d2H_err = full(max(max(abs(d2H - num_d2H))));
    if d2f_err > 1e-6
        fprintf('Max difference in d2f: %g\n', d2f_err);
    end
    if d2G_err > 1e-5
        fprintf('Max difference in d2G: %g\n', d2G_err);
    end
    if d2H_err > 1e-6
        fprintf('Max difference in d2H: %g\n', d2H_err);
    end
end

Lxx = d2f + d2G + d2H;

%% force specified sparsity structure
if nargin > 4
    %% add sparse structure (with tiny values) to current matrices to
    %% ensure that sparsity structure matches that supplied
    Lxx = Lxx + Hs;

%     %% check sparsity structure against that supplied
%     if nnz(Lxx) ~= nnz(Hs)
%         fprintf('=====> nnz(Lxx) is %d, expected %d <=====\n', nnz(Lxx), nnz(Hs));
%     else
%         [iHs, jHs] = find(Hs);
%         [iH, jH] = find(Lxx);
%         if any(iH ~= iHs) || any(jH ~= jHs)
%             fprintf('=====> structure of Lxx is not as expected <=====\n');
%         end
%     end
end


% Copyright (C) 1993-2011, by Peter I. Corke
%
% This file is part of The Machine Vision Toolbox for Matlab (MVTB).
%
% MVTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% MVTB 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 Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with MVTB.  If not, see <http://www.gnu.org/licenses/>.
function xyz = xy2xyz(xy, Y)

    x = xy(:,1);
    y = xy(:,2);
    iy = 1 ./ (y + 1e-6);

    X = x .* Y .* iy;
    Z = Y .* (1-x-y) .* iy;

    Y = ones(X) * Y;

    xyz = [X Y Z];


filename='Cantileverbeam_Tetrahedra_Linear_Structured_SYM';
 ptype = 'MACRO';
method = 'SIMPALL';
materialType = 'ISOTROPIC';
initial_case = 'holes';
cost = {'compliance'};
weights = [1];
constraint = {'volume'};
optimizer = 'HAMILTON-JACOBI';
incrementFactor = 1;
designVariable = 'LevelSet';
filterType = 'P1';
constraint_case = 'INEQUALITY';
line_search_initiator = 'INCREASING LAST STEP';
showBC = true;

HJiter0 = 1;
e2 = 100;
N_holes = [12 5 5];
R_holes = 0.7;
phase_holes = [0 0 0];
nsteps = 10;
Vfrac_final = 0.1;
Perimeter_target = 1;
optimality_final = 1e-3;
constr_final =1e-3;

Vfrac_initial = 0.7;
optimality_initial = 5e-2;
constr_initial = 5e-2;
TOL.rho_plus = 1;
TOL.rho_minus = 0;
TOL.E_plus = 1;
TOL.E_minus = 1e-3;
TOL.nu_plus = 1/3;
TOL.nu_minus = 1/3;


% TIME = EPOCH2DATENUM(EPOCH) translates Unix epoch date format into Matlab
% numeric date format.

% Author: Michael West, Modified by Glenn Thompson
% $Date$
% $Revision$

function time = epoch2datenum(epoch)
    if admin.antelope_exists()
        % check ANTELOPE installation if this line segfaults
        time = datenum(epoch2str(epoch,'%m %d %Y %H %M %S.%s'),'mm dd yyyy HH MM SS.FFF');
    else % does not handle leap seconds
        time = datenum(1970,1,1,0,0,epoch);
    end
end


function x0 = opti_guessX0(prob,ndec)
%Try choose a better x0 than zeros() if we have all finite bounds

if(~isempty(prob.lb) && ~isempty(prob.ub) && all(~isinf(prob.lb)) && all(~isinf(prob.ub)))
    x0 = (prob.ub-prob.lb)./2;
else
    x0 = zeros(ndec,1);
end


function a = double(s)
%DOUBLE Converts a sparse tensor to a dense multidimensional array.
%
%  See also SPTENSOR, SPTENSOR/FULL.
%
%MATLAB Tensor Toolbox.
%Copyright 2012, Sandia Corporation.

% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others.
% http://www.sandia.gov/~tgkolda/TensorToolbox.
% Copyright (2012) Sandia Corporation. Under the terms of Contract
% DE-AC04-94AL85000, there is a non-exclusive license for use of this
% work by or on behalf of the U.S. Government. Export of this data may
% require a license from the United States Government.
% The full license terms can be found in the file LICENSE.txt

a = zeros([size(s) 1 1]);
if nnz(s) > 0
    a(tt_sub2ind(size(s),s.subs)) = s.vals;
end


function x = vec(X)
% x = vec(X)
%
% Y = VEC(x)  Given an m x n matrix x, this produces the vector Y of length
%   m*n that contains the columns of the matrix x, stacked below each other.
%
% See also mat.

% This file is part of SeDuMi 1.1 by Imre Polik and Oleksandr Romanko
% Copyright (C) 2005 McMaster University, Hamilton, CANADA  (since 1.1)
%
% Copyright (C) 2001 Jos F. Sturm (up to 1.05R5)
%   Dept. Econometrics & O.R., Tilburg University, the Netherlands.
%   Supported by the Netherlands Organization for Scientific Research (NWO).
%
% Affiliation SeDuMi 1.03 and 1.04Beta (2000):
%   Dept. Quantitative Economics, Maastricht University, the Netherlands.
%
% Affiliations up to SeDuMi 1.02 (AUG1998):
%   CRL, McMaster University, Canada.
%   Supported by the Netherlands Organization for Scientific Research (NWO).
%
% 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.,  51 Franklin Street, Fifth Floor, Boston, MA
% 02110-1301, USA

x = reshape(X,numel(X),1);


%Develop by Renoald
%Email:Renoald@live.com
%11/2/2013
%This function can used to view 3D point clouds
%Format of 3D point clouds
%Xi Yi Zi Ri Gi Bi
function ViewPointCloud(file)
%read File
p=dlmread(file);
[i,j]=size(p);
dist=ones(i,1);
if j==6
    %scatter3(p(:,1),p(:,2),p(:,3),'Marker','o')

else
    for i=1 : i
    dist(i,1)=Dist3D(0,0,0,p(i,1),p(i,2),p(i,3));
end
    figure(1);
    %Plot point clouds
    fname=strcat('Number of points:',num2str(i));
    scatter3(p(:,1),p(:,2),p(:,3),1,dist(:,1))
    title(fname);
    xlabel('x axis');
    ylabel('y axis');
    zlabel('z axis');
end


function a = double(s)
%DOUBLE Converts a sparse tensor to a dense multidimensional array.
%
%  See also SPTENSOR, SPTENSOR/FULL.
%
%MATLAB Tensor Toolbox.
%Copyright 2015, Sandia Corporation.

% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others.
% http://www.sandia.gov/~tgkolda/TensorToolbox.
% Copyright (2015) Sandia Corporation. Under the terms of Contract
% DE-AC04-94AL85000, there is a non-exclusive license for use of this
% work by or on behalf of the U.S. Government. Export of this data may
% require a license from the United States Government.
% The full license terms can be found in the file LICENSE.txt

a = zeros([size(s) 1 1]);
if nnz(s) > 0
    a(tt_sub2ind(size(s),s.subs)) = s.vals;
end


function out = horzcat(varargin)
%HORZCAT   Horizontal concatenation.
%   [A B] horizontally concatenates the CHEBTECH objects A and B to form an
%   array-valued CHEBTECH. [A,B] does the same. Any number of CHEBTECH objects
%   can be concatenated within one pair of brackets. Vertical concatenation is
%   not supported.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

% Remove empties:
empties = cellfun(@isempty, varargin);
if ( all(empties) )
    out = varargin{1};
    return
else
    varargin(empties) = [];
end

% Check that all objects are CHEBTECHs. If not we cannot concatenate.
if ( ~all( cellfun(@(f) isa(f, 'chebtech'), varargin) ) )
    error('CHEBFUN:CHEBTECH:horzcat:typeMismatch', ...
    'Incompatible concatenation. Ensure discretizations are of the same type.');
end

% Prolong each Chebtech to the same length:
n = max(cellfun(@length, varargin));
F = cellfun(@(f) prolong(f, n), varargin, 'UniformOutput', false);

% Extract the data and collate the an array-valued CHEBTECH:
out = varargin{1};

% Coeffs:
out.coeffs = cell2mat(cellfun(@(f) f.coeffs, F, 'UniformOutput', false));

end


function display_results_registration2d(moving,fixed,...
    displacementField,originalSize,gamma)
% DISPLAY_RESULTS_REGISTRATION2D Displays registration results for 2D
%
% display_results_registration3d(moving,fixed,displacementField,originalSize,gamma)
%
% INPUT ARGUMENTS
% moving                - Moving image
% fixed                 - Fixed image
% displacementField     - Displacement field
% originalSize          - Original data size, data is resampled to this
%                         size before display
% gamma                 - Gamma to use for display
%
% OPTIONAL INPUT ARGUMENTS
% N/A
%
% OUTPUT ARGUMENTS
% N/A

% Copyright (c) 2012 Daniel Forsberg
% danne.forsberg@outlook.com
%
% 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 3 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, see <http://www.gnu.org/licenses/>.

moving = moving/max(moving(:));
fixed = fixed/max(fixed(:));
displacementField = resampler(displacementField, originalSize, 'relativeValues', true);
deformed = deformation(moving,displacementField,'linear');

%**************** Display fixed ******************************
display_image(fixed,1,'fixed','gamma',gamma);

%**************** Display moving ******************************
display_image(moving,2,'moving','gamma',gamma);

%**************** Display deformed ******************************
display_image(deformed,3,'deformed','gamma',gamma);

%**************** Display (moving - fixed) *****************
display_images(moving,fixed,4,'moving-fixed','gamma',gamma)

%**************** Display (deformed - fixed) *****************
display_images(deformed,fixed,5,'deformed-fixed','gamma',gamma)

%**************** Display displacement ******************************
display_displacement_grid(displacementField,6,'grid');

%************ Display accumulated motion field ********
if exist('display_motion_field','file')
    display_motion_field(displacementField,7,'Acc motion field',false)
end

%************ Display det of acc motion field **********
if exist('display_determinant_of_motion_field','file')
    display_determinant_of_motion_field(displacementField,8,'Det of jacobian of acc motion field',gamma)
end


function [ ltri, ledg, rtri, redg ] = vbedg ( x, y, node_num, node_xy, ...
  triangle_num, triangle_node, triangle_neighbor, ltri, ledg, rtri, redg )

%*****************************************************************************80
%
%% VBEDG determines which boundary edges are visible to a point.
%
%  Discussion:
%
%    The point (X,Y) is assumed to be outside the convex hull of the
%    region covered by the 2D triangulation.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    30 September 2008
%
%  Author:
%
%    Original FORTRAN77 version by Barry Joe,
%    MATLAB version by John Burkardt
%
%  Reference:
%
%    Barry Joe,
%    GEOMPACK - a software package for the generation of meshes
%    using geometric algorithms,
%    Advances in Engineering Software,
%    Volume 13, pages 325-331, 1991.
%
%  Parameters:
%
%    Input, real X, Y, the coordinates of a point outside the
%    convex hull of the current triangulation.
%
%    Input, integer NODE_NUM, the number of points.
%
%    Input, real NODE_XY(2,NODE_NUM), the coordinates of the
%    vertices.
%
%    Input, integer TRIANGLE_NUM, the number of triangles.
%
%    Input, integer TRIANGLE_NODE(3,TRIANGLE_NUM), the triangle incidence list.
%
%    Input, integer TRIANGLE_NEIGHBOR(3,TRIANGLE_NUM), the triangle neighbor list; negative
%    values are used for links of a counter clockwise linked list of boundary
%    edges;
%      LINK = -(3*I + J-1) where I, J = triangle, edge index.
%
%    Input/output, integer LTRI, LEDG.  If LTRI /= 0 then these values are
%    assumed to be already computed and are not changed, else they are updated.
%    On output, LTRI is the index of boundary triangle to the left of the
%    leftmost boundary triangle visible from (X,Y), and LEDG is the boundary
%    edge of triangle LTRI to the left of the leftmost boundary edge visible
%    from (X,Y).  1 <= LEDG <= 3.
%
%    Input/output, integer RTRI.  On input, the index of the boundary triangle
%    to begin the search at.  On output, the index of the rightmost boundary
%    triangle visible from (X,Y).
%
%    Input/output, integer REDG, the edge of triangle RTRI that is visible
%    from (X,Y).  1 <= REDG <= 3.
%
  dim_num = 2;
%
%  Find the rightmost visible boundary edge using links, then possibly
%  leftmost visible boundary edge using triangle neighbor information.
%
  if ( ltri == 0 )
    ldone = 0;
    ltri = rtri;
    ledg = redg;
  else
    ldone = 1;
  end

  while ( 1 )

    l = -triangle_neighbor(redg,rtri);
    t = floor ( l / 3 );
    e = mod ( l, 3 ) + 1;
    a = triangle_node(e,t);

    if ( e <= 2 )
      b = triangle_node(e+1,t);
    else
      b = triangle_node(1,t);
    end

    lr = lrline ( x, y, node_xy(1,a), node_xy(2,a), node_xy(1,b), ...
      node_xy(2,b), 0.0 );

    if ( lr <= 0 )
      break;
    end

    rtri = t;
    redg = e;

  end

  if ( ldone )
    return
  end

  t = ltri;
  e = ledg;

  while ( 1 )

    b = triangle_node(e,t);
    e = i4_wrap ( e-1, 1, 3 );

    while ( 0 < triangle_neighbor(e,t) )

      t = triangle_neighbor(e,t);

      if ( triangle_node(1,t) == b )
        e = 3;
      elseif ( triangle_node(2,t) == b )
        e = 1;
      else
        e = 2;
      end

    end

    a = triangle_node(e,t);

    lr = lrline ( x, y, node_xy(1,a), node_xy(2,a), node_xy(1,b), ...
      node_xy(2,b), 0.0 );

    if ( lr <= 0 )
      break
    end

  end

  ltri = t;
  ledg = e;

  return
end


function value = r8vec_in_ab ( n, x, a, b )

%*****************************************************************************80
%
%% R8VEC_IN_AB is TRUE if the entries of an R8VEC are in the range [A,B].
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    26 March 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the number of entries in the vector.
%
%    Input, real X(N), the vector.
%
%    Input, real A, B, the limits, with A <= B.
%
%    Output, logical VALUE, is TRUE if every entry is
%    between A and B.
%
  if ( any ( x(1:n) < a | b < x(1:n) ) )
    value = 0;
  else
    value = 1;
  end

  return
end


function c = diag(a,k)
%DIAG         Implements  diag(a,k)  for hessians
%
%   c = diag(a,k)
%
% functionality as Matlab function diag for matrices
%

% written  04/04/04     S.M. Rump
% modified 04/06/05     S.M. Rump  rounding unchanged
% modified 08/26/12     S.M. Rump  global variables removed
%

  INTLAB_HESSIAN_NUMVAR = getappdata(0,'INTLAB_HESSIAN_NUMVAR');

  if nargin==1
    k = 0;
  end

  [m n] = size(a.x);
  c.x = diag(a.x,k);
  if m==1 | n==1
    index = diag(ones(1,m*n),k);
    if issparse(a.hx)
      c.dx = sparse([],[],[],INTLAB_HESSIAN_NUMVAR,prod(size(index)),0);
      c.hx = sparse([],[],[],INTLAB_HESSIAN_NUMVAR^2,prod(size(index)),0);
    else
      c.dx = zeros(INTLAB_HESSIAN_NUMVAR,prod(size(index)));
      c.hx = zeros(INTLAB_HESSIAN_NUMVAR^2,prod(size(index)));
    end
    if isa(a.x,'intval')
      c.dx = intval(c.dx);
      c.hx = intval(c.hx);
    end
    c.dx(:,index~=0) = a.dx;
    c.hx(:,index~=0) = a.hx;
  else
    index = diag( reshape( 1:(m*n) , m , n ) , k );
    c.dx = a.dx(:,index(:));
    c.hx = a.hx(:,index(:));
  end

  c = class(c,'hessian');


function varargout = flipud(varargin)
%FLIPUD   Flip/reverse a CHEBFUN2 in the y-direction.
%   G = FLIPUD(F) returns a CHEBFUN2 G with the same domain as F but reversed;
%   that is, G(x,y) = F(x, c+d-y), where the domain is [a, b, c, d].
%
% See also FLIPLR, FLIPDIM.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

[varargout{1:nargout}] = flipud@separableApprox(varargin{:});

end


function X = stack2vecs(S)
%STACK2VECS Convert stack to observation-by-features matrix.
% Usage:
%   X = stack2vecs(S)
%
% Args:
%   S: 4-d array of size [h, w, c, n]
%
% Returns:
%   X: 2-d array of size [n, (h * w * c)]
%
% See also: vecs2stack

if ndims(S) == 3; S = permute(S,[1 2 4 3]); end

X = reshape(S,[],size(S,4))';

end


function varargout = plot3(f, g, h, varargin)
%PLOT3   Plot for FUN objects in 3-D space.
%   PLOT3() is a three-dimensional analogue of PLOT().
%
%   PLOT3(X, Y, Z), where Z, Y, and Z are three CHEBTECH objects, plots a line
%   in 3-space. X, Y, and Z may be array-valued, but must have the same number
%   of columns.
%
%   Various line types, plot symbols, and colors may be obtained with PLOT3(X,
%   Y, Z, S) where s is a 1, 2 or 3 character string made from the characters
%   listed under the PLOT command.
%
%   H1 = PLOT3(X, Y, Z) returns a column vector of handles to lineseries
%   objects, one handle per plotted line (in the case of vector-valued CHEBTECH
%   objects). [H1, H2] returns a second vector of column handles, this time for
%   each of the marker plots.
%
% See also PLOT, PLOTDATA.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

% Deal with an empty input:
if ( isempty(f) )
    if ( nargout == 1 )
        varargout{1} = plot([]);
    end
    return
end

% Store the hold state of the current axis:
holdState = ishold;

%%
% We can only plot real data in this way:
f = real(f);
g = real(g);
h = real(h);

% Get the data for plotting from PLOTDATA():
data = plotData(f, g, h);

%%
% Plot the curve:
h1 = plot3(data.xLine, data.yLine, data.zLine);
set(h1, 'Marker', 'none')
hold on

%%
% Plot the points:
h2 = plot3(data.xPoints, data.yPoints, data.zPoints, varargin{:});

% Change the style accordingly:
set(h2,'LineStyle', 'none')
if ( all(strcmp(get(h2, 'Marker'), 'none')) && (length(f) < 257) )
    set(h2, 'Marker', 'o')
end

%%

% Return hold state to what it was before:
if ( ~holdState )
    hold off
end

% Give an output if one was requested:
if ( nargout > 0 )
    varargout{1} = h1;
    varargout{2} = h2;
end

end


classdef DisjointSet < handle
%%DISJOINTSET A disjoint set class that can be used for partitioning a
%             general set. It can be used to cluster targets given
%             measurements. If one also wishes to keep track of which
%             measurements are associated with which target clusters, then
%             the subclass DisjointSetM should be used.
%
%Disjoint sets are described in Chapter 8 of [1], in Chapter 21 of [2], and
%Chapter 12.4 of [3].
%
%The main point of this class is to bring together cluster data so that a
%ClusterSet class can be created. A ClusterSet class allows the clusters to
%be indexed by a cluster number and the elements of the clusters to be
%subsequently indexed with another number. The algorithms here use path
%compression in the find algorithm and a union by rank algorithm to process
%things quickly.
%
%REFERENCES:
%[1] M. A. Weiss, Data Structures and Algorithm Analysis in C++, 2nd ed.
%    Reading, MA: Addison-Wesley, 1999.
%[2] T. H. Cormen, C. E. Leiserson, R. L. Rivest, and C. Stein,
%    Introduction to Algorithms, 2nd ed. Cambridge, MA: The MIT Press,
%    2001.
%[3] B. R. Preiss, Data Structures and Algorithms with Object-Oriented
%    Design Patterns in C++. New York, NY: John Wiley & Sons, Inc., 1999.
%
%November 2013 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

    properties
        numberOfSets
        setArray
        numInTree
    end
    methods
        function newSet=DisjointSet(setSize)
            %The constructor method
            newSet.setArray=-1*ones(setSize,1);
            newSet.numInTree=ones(setSize,1);
            newSet.numberOfSets=setSize;
        end

        function unionFromList(DSObj,uList)
        %%UNIONFROMLIST Given a list of targets in the same cluster, such
        %               as a list of targets that gate with a common
        %               measurement, cluster them together.
        %
        %INPUTS: DSObj The implicitly passed calling object.
        %        uList A one-dimensional list of indices of targets to
        %              merge into one cluster

            numInList=length(uList);
            if(numInList==0)
                return;
            end

            rootIdx1=DSObj.find(uList(1));
            for curTar=2:numInList
                rootIdx2=DSObj.find(uList(curTar));
                rootIdx1=DSObj.unionRoots(rootIdx1,rootIdx2);
            end
        end

        function unionFromBinMat(DSObj,binMat)
        %%UNIONFROMBINMAT Given a binary matrix specifying which
        %                 measurements gate with which targets, cluster
        %                 together all targets that gate with each other.
        %
        %INPUTS: DSObj The implicitly passed calling object.
        %        binMat A numTarXnumMeas binary matrix where numTar is
        %               the same as the length of setArray in DSObj and
        %               numMeas is an arbitrary number. If an empty matrix
        %               is passed, nothing is done.
        %
        %This algorithm takes the union of all elements of setArray in each
        %column corresponding to ones in the column. Thus, if this is a
        %gating matrix for targets and measurements, this will create all
        %of the target clusters.
        %
            if(isempty(binMat))
                return;
            end

            numTar=size(binMat,1);
            numMeas=size(binMat,2);

            %Check for input validity
            assert(numTar==length(DSObj.setArray))

            for curMeas=1:numMeas
                rootIdx1=0;
                for curTar=1:numTar
                    if(binMat(curTar,curMeas)~=0)
                        if(rootIdx1==0)
                            rootIdx1=DSObj.find(curTar);
                        else
                            rootIdx2=DSObj.find(curTar);
                            rootIdx1=DSObj.unionRoots(rootIdx1,rootIdx2);
                        end
                    end
                end
            end
        end

        function newCSet=createClusterSet(DSObj)
        %%CREATECLUSTERSET Turn the DisjointSet object into a ClusterSet
        %                  so that targets in each cluster can be easily
        %                  addressed.
        %
        %OUTPUTS: newCSet A ClusterSet object representing the clustering
        %                 given by this DisjointSet object.

            numTar=length(DSObj.setArray);

            rootIdxList=zeros(DSObj.numberOfSets,1);
            curNumAdded=zeros(DSObj.numberOfSets,1);

            rootRankList=zeros(DSObj.numberOfSets,1);
            clusterEls=zeros(numTar,1);

            %First, record the indices and ranks of all of the root nodes.
            rootNodesFound=0;
            for curItem=1:length(DSObj.setArray)
                if(DSObj.setArray(curItem)<0)
                    rootNodesFound=rootNodesFound+1;
                    rootIdxList(rootNodesFound)=curItem;
                    rootRankList(rootNodesFound)=DSObj.numInTree(curItem);
                    if(rootNodesFound==DSObj.numberOfSets)
                        break;
                    end
                end
            end

            %Next, sort the root nodes by their index, so that children can
            %be efficiently assigned to them.
            [rootIdxList,idx] = sort(rootIdxList,1,'ascend');
            rootRankList=rootRankList(idx);

            %rootRankList currently holds all of the ranks of the root
            %indices in rootIdxList for the clusters. The elements of the
            %clusters are going to be put in one big array, clusterEls.
            %We are going to  create another array, offsetArray from
            %rootRankList such that each element is the offset needed to
            %access the first element of a given cluster in clusterEls. The
            %first element of offsetArray consequently is zero. The others
            %are a cumulative sum of the previous elements in rootRankList.
            offsetArray=zeros(DSObj.numberOfSets,1);
            offsetArray(2:end)=cumsum(rootRankList(1:(end-1)));

            %Now, we shall scan though all of the elements in
            %DSObj.setArray and add then to the appropriate cluster in
            %clusterEls depending on their rank.
            for curItem=1:numTar
                %Find the root node for the given node.
                rootNode=DSObj.find(curItem);
                %Find the index of the cluster corresponding to that root
                %node.
                [~, clusterIdx]=binSearch(rootIdxList,rootNode);
                %Add the node to the cluster.
                clusterEls(1+offsetArray(clusterIdx)+curNumAdded(clusterIdx))=curItem;
                curNumAdded(clusterIdx)=curNumAdded(clusterIdx)+1;
            end

            newCSet=ClusterSet(clusterEls,rootRankList,offsetArray);
        end

        function mergedRootIdx=unionRoots(DSObj,rootIdx1,rootIdx2)
        %%UNIONROOTS Merge two sets given their root nodes. If one wishes
        %            to merge sets given arbitrary (not necessarily root)
        %            nodes in the sets, then the function union should be
        %            used.
        %
        %INPUTS: DSObj      The implicitly passed calling object.
        %        rootIdx1   The root index of the first set to merge.
        %        rootIdx2   The root index of the second set to merge.
        %
        %OUTPUTS: mergedRootIdx The index of the root of the merged
        %                       cluster. It will either be rootIdx1 or
        %                       rootIdx2.
        %
        %This is a union-by-rank algorithm.
        %
            %If the roots are the same, then there is nothing to merge.
            if(rootIdx1==rootIdx2)
                %Do measurement bookeeping, if desired.
                mergedRootIdx=rootIdx1;
                return;
            end

            %If root 2 is deeper, than make root2 the new root.
            if(DSObj.setArray(rootIdx2)< DSObj.setArray(rootIdx1))
                DSObj.setArray(rootIdx1)=rootIdx2;
                DSObj.numInTree(rootIdx2)=DSObj.numInTree(rootIdx1)+DSObj.numInTree(rootIdx2);
                mergedRootIdx=rootIdx2;
            else
                %If they are the same height, then update the height of
                %rootIdx1.
                if(DSObj.setArray(rootIdx1)== DSObj.setArray(rootIdx2))
                    DSObj.setArray(rootIdx1)=DSObj.setArray(rootIdx1)-1;
                end
                DSObj.setArray(rootIdx2)=rootIdx1;
                DSObj.numInTree(rootIdx1)=DSObj.numInTree(rootIdx1)+DSObj.numInTree(rootIdx2);
                mergedRootIdx=rootIdx1;
            end

            %Merging reduces the number of sets by one.
            DSObj.numberOfSets=DSObj.numberOfSets-1;
        end

        function rootIdx=find(DSObj,idx)
        %FIND Perform a search with path compression. That is, all nodes
        %     traversed are set to point directly to the root of the tree.
        %     This means that future searches will be faster.
        %
        %INPUTS:  DSObj     The implicitly passed calling object.
        %         idx       The index of a node.
        %
        %OUTPUTS: rootIdx  The index of the root node of the cluster to
        %                  which the node with index idx belongs.
        %
        %The use of path compression would imply that the ranks associated
        %with the root nodes should be recalculated. However, it is noted
        %in Chapters 8.5 and 8.6 of
        %M. A. Weiss, Data Structures and Algorithms for C++, 2nd ed.
        %Reading, MA: Addison-Wesley, 1999.
        %that failing to update the rank does not worsen the theoretical
        %worst-case run time.
        %
            if(DSObj.setArray(idx)<0)
                rootIdx=idx;
            else
                rootIdx=DSObj.find(DSObj.setArray(idx));
                DSObj.setArray(idx)=rootIdx;
            end

        end
    end
end

%LICENSE:
%
%The source code is in the public domain and not licensed or under
%copyright. The information and software may be used freely by the public.
%As required by 17 U.S.C. 403, third parties producing copyrighted works
%consisting predominantly of the material produced by U.S. government
%agencies must provide notice with such work(s) identifying the U.S.
%Government material incorporated and stating that such material is not
%subject to copyright protection.
%
%Derived works shall not identify themselves in a manner that implies an
%endorsement by or an affiliation with the Naval Research Laboratory.
%
%RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE
%SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY THE NAVAL
%RESEARCH LABORATORY FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE ACTIONS
%OF RECIPIENT IN THE USE OF THE SOFTWARE.


function [clout]=cl_cl_intersect(clin1,clin2,varargin)

% Usage:
% clout=cl_cl_intersect(clin1,clin2)
% clout=cl_cl_intersect(clin1,clin2,'switch')
%
% clout is a cl structure containing clusters of only those voxels that
% exist in both cl structures clin1 and clin2.
%
% If the clin1 and clin2 are not in the same image space, clin2 will be
% converted to the space of clin1 by finding the nearest mm point in the
% space of clin1 to each mm point in clin2. NOTE: ***** This may be
% undiserable if the voxel sizes in clin1 are substantially smaller than
% those in clin2--eg., a 4x4x4 voxel will be translated into a single 2x2x2
% voxel, resulting in 3 'empty' 2x2x2 voxels in the space covered by the
% 4x4x4 voxel. For this reason, it is recommended that you place the lowest
% resolution cl structure in the first input.
%
% The cl.Z values and the threshold field are taken from clin1, and the
% values from clin2 are dropped. If the string 'switch' is included as in
% input, the Z values from clin2 will be used instead.
%

sw=0;
if ~isempty(varargin)
    for k=1:length(varargin)
        if strcmp(varargin{k},'switch')
            sw=1;
        end
    end
end

XYZmm1=[];
XYZmm2=[];
Z=[];
for k=1:length(clin1)
    if size(clin1(k).XYZmm,1)==3
        XYZmm1(:,end+1:end+clin1(k).numVox)=clin1(k).XYZmm;
    else
        XYZmm1(:,end+1:end+clin1(k).numVox)=clin1(k).XYZmm';
    end
    if ~sw
        Z(end+1:end+clin1(k).numVox)=clin1(k).Z;
    end
end

for k=1:length(clin2)
    if size(clin2(k).XYZmm,1)==3
        XYZmm2(:,end+1:end+clin2(k).numVox)=clin2(k).XYZmm;
    else
        XYZmm2(:,end+1:end+clin2(k).numVox)=clin2(k).XYZmm';
    end
    if sw
        Z(end+1:end+clin2(k).numVox)=clin2(k).Z;
    end
end

if clin1(1).voxSize(:)~=clin2(1).voxSize(:)
    [XYZmm2,p_ind]=mmToVoxel(XYZmm2,clin1(1).M,'valid');
    if sw
        for m=1:length(p_ind)
            ind=find(p_ind(:)==p_ind(m));
            Z(ind)=mean(Z(ind));
        end
        Z=Z(unique(p_ind));
    end
    XYZmm2=voxelToMm(XYZmm2,clin1(1).M);
end

XYZmm_out=[];
Zout=[];

for k=1:size(XYZmm1,2)
    a=find(XYZmm2(1,:)==XYZmm1(1,k));
    if ~isempty(a)
        b=find(XYZmm2(2,a)==XYZmm1(2,k));
        if ~isempty(b)
            c=find(XYZmm2(3,a(b))==XYZmm1(3,k));
            if ~isempty(c)
                XYZmm_out(:,end+1)=XYZmm2(:,a(b(c)));
                Zout(:,end+1)=Z(a(b(c)));
            end
        end
    end
end
if isempty(XYZmm_out)
	clout=struct('XYZ',{},'XYZmm',{},'name',{},'numVox',{},'M',{},'voxSize',{},'dim',{},'title',{},'threshold',{},'Z',{},'mm_center',{});
else
    XYZout=mmToVoxel(XYZmm_out,clin1(1).M,'valid');
    cl_ind=spm_clusters(XYZout);
    for k=1:max(cl_ind)
        clout(k).XYZ=XYZout(:,cl_ind==k);
        clout(k).XYZmm=voxelToMm(clout(k).XYZ,clin1(1).M);
        clout(k).name='';
        clout(k).numVox=length(find(cl_ind==k));
        clout(k).M=clin1(1).M;
        clout(k).voxSize=clin1(1).voxSize;
        clout(k).dim=clin1(1).dim;
        clout(k).title=['Cluster of ' num2str(clout(k).numVox) ' voxels from the intersection of two clusters, created by cl_cl_intersect.m.'];
        clout(k).threshold=clin1(1).threshold;
        clout(k).Z=Zout(cl_ind==k);
        clout(k).mm_center=center_of_mass(clout(k).XYZmm,clout(k).Z);
    end
end


function [Problem] = CMATpick_point(...
    Problem,Constraints,Spec,Objectives,Haxes)
satisfied = false;
while ~satisfied
    disp('Choose new point by clicking')
    [x,y] = ginput(1);
    newpth = plot(gca,x,y,'*k','MarkerEdgeColor','k',...
        'MarkerFaceColor','b','MarkerSize',9);

    %%  Change deceision vector to new point
    TestProb = Problem;
    ind = Haxes==gca;
    [ii,jj] = find(ind);
    testsolX = Problem.x0(Problem.activeX);
    testsolX(ii) = y;
    testsolX(jj) = x;
    TestProb.x0(Problem.activeX) = testsolX;
    %%
    commandwindow;
    if get_yes_or_no(...
            'New design point plotted. Evaluate chosen point? [Y]/N: ',true)
        ITERevaluate_X0(TestProb,Constraints,Spec,Objectives,false);
    end
    whattodo = txtmenu('',...
        'Choose new point (zoom/pan now)','Use chosen point',...
        'Cancel - use old design point');
    switch whattodo
        case 1 %satisfied
            Problem.x0 = TestProb.x0;
            satisfied = true;
        case 0 %try again
            delete(newpth);
        case 2 %use old
            delete(newpth);
            satisfied = true;
    end
end

end


%                               431-400 Year Long Project
%                           LA1 - Medical Image Processing 2003
%  Supervisor     :  Dr Lachlan Andrew
%  Group Members  :  Alister Fong    78629   a.fong1@ugrad.unimelb.edu.au
%                    Lee Siew Teng   102519  s.lee1@ugrad.unimelb.edu.au
%                    Loh Jien Mei    103650  j.loh1@ugrad.unimelb.edu.au
%
%  File and function name : test_sort_coord.m
%  Version                : 2.0
%  Date of completion     : 18 December 2003
%  Written by    :   Alister Fong    78629   a.fong1@ugrad.unimelb.edu.au
%
% Inputs :
%           None
%
% Outputs :
%           None
%
% Description :
%   Test the clockwise and anti-clockwise sorting function on a circle
%
% Usage >> test_sort_coord

function test_sort_coord
clc
outlined_image = zeros(100);
outlined_image_coord = plot_circle(50,50,20,'bresenham');
assigned_values = outlined_image_coord(:,1);
assigned_values(:) = 1;
outlined_image = place_values(outlined_image_coord,assigned_values,outlined_image);

[Ycoord,Xcoord] = find(outlined_image>0);

disp(' ');
disp('--------------');
disp(strcat('Number of pixels :',num2str(length(Ycoord))));
disp('--------------');
disp(' ');

temp_image = zeros(size(outlined_image));

% -------------------------------------------------------------------
disp('Display the image via the "find" function');
f = figure;
for n = 1:1:length(Ycoord)
    temp_image(Ycoord(n),Xcoord(n)) = 1;
    imshow(temp_image);
    title('"find" function');
    pause(0.01);
end

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

% Clockwise rotation
disp('Press any key to continue....');
pause;

disp('sort_coord_pixels clockwise');
tic
output_coord = sort_coord_pixel([Xcoord,Ycoord],'clockwise');
toc

disp('Press any key to continue....');
pause;
disp('Display the image via "sort_coord_pixel" function');
temp_image(:) = 0;
for n = 1:1:length(output_coord(:,1))
    temp_image(output_coord(n,2),output_coord(n,1)) = 1;
    imshow(temp_image);
    title('"sort-coord-pixel" function - clockwise');
    pause(0.01);
end

% -------------------------------------------------------------------
% Anti-clockwise rotation
disp('Press any key to continue....');
pause;

disp('sort_coord_pixels anti-clockwise');
tic
output_coord = sort_coord_pixel([Xcoord,Ycoord],'anti-clockwise');
toc

disp('Press any key to continue....');
pause;
disp('Display the image via "sort_coord_pixel" function');
temp_image(:) = 0;
for n = 1:1:length(output_coord(:,1))
    temp_image(output_coord(n,2),output_coord(n,1)) = 1;
    imshow(temp_image);
    title('"sort-coord-pixel" function - anti-clockwise');
    pause(0.01);
end

% ===================================================================
% ===================================================================

% -------------------------------------------------------------------
disp('Press any key to continue....');
pause;
disp('Get image "test_sort1.tif"');
temp_image = imread('test_sort1.tif');
[Ycoord,Xcoord] = find(temp_image~=0);
disp('sort_coord_pixels clockwise');
input_coord = [Xcoord,Ycoord];
disp('------------------------');
tic
output_coord = sort_coord_pixel(input_coord,'clockwise','progress track');
toc
disp('------------------------');
disp('Press any key to continue....');
pause;
disp('Display the image via "sort_coord_pixel" function');
temp_image(:) = 0;
for n = 1:1:length(output_coord(:,1))
    temp_image(output_coord(n,2),output_coord(n,1)) = 1;
    imshow(temp_image);
    title('"sort-coord-pixel" function - clockwise');
    pause(0.01);
end

% -------------------------------------------------------------------
disp('Press any key to continue....');
pause;
disp('Get image "test_sort1.tif"');
temp_image = imread('test_sort1.tif');
[Ycoord,Xcoord] = find(temp_image~=0);
disp('sort_coord_pixels anti-clockwise');
input_coord = [Xcoord,Ycoord];
disp('------------------------');
tic
output_coord = sort_coord_pixel(input_coord,'anti-clockwise','progress track');
toc
disp('------------------------');
disp('Press any key to continue....');
pause;
disp('Display the image via "sort_coord_pixel" function');
temp_image(:) = 0;
for n = 1:1:length(output_coord(:,1))
    temp_image(output_coord(n,2),output_coord(n,1)) = 1;
    imshow(temp_image);
    title('"sort-coord-pixel" function - anti-clockwise');
    pause(0.01);
end

% ===================================================================
% ===================================================================

% -------------------------------------------------------------------
disp('Press any key to continue....');
pause;
disp('Get image "test_sort2.tif"');
temp_image = imread('test_sort2.tif');
[Ycoord,Xcoord] = find(temp_image~=0);
disp('sort_coord_pixels clockwise, 4 connectivity');
input_coord = [Xcoord,Ycoord];
disp('------------------------');
tic
output_coord = sort_coord_pixel(input_coord,'clockwise',4);
toc
disp('------------------------');
disp('Press any key to continue....');
pause;
disp('Display the image via "sort_coord_pixel" function');
temp_image(:) = 0;
for n = 1:1:length(output_coord(:,1))
    temp_image(output_coord(n,2),output_coord(n,1)) = 1;
    imshow(temp_image);
    title('"sort-coord-pixel" function - clockwise');
    pause(0.01);
end

% -------------------------------------------------------------------
disp('Press any key to continue....');
pause;
disp('Get image "test_sort2.tif"');
temp_image = imread('test_sort2.tif');
[Ycoord,Xcoord] = find(temp_image~=0);
disp('sort_coord_pixels anti-clockwise, 4 connectivity');
input_coord = [Xcoord,Ycoord];
disp('------------------------');
tic
output_coord = sort_coord_pixel(input_coord,'anti-clockwise',4);
toc
disp('------------------------');
disp('Press any key to continue....');
pause;
disp('Display the image via "sort_coord_pixel" function');
temp_image(:) = 0;
for n = 1:1:length(output_coord(:,1))
    temp_image(output_coord(n,2),output_coord(n,1)) = 1;
    imshow(temp_image);
    title('"sort-coord-pixel" function - anti-clockwise');
    pause(0.01);
end

% ===================================================================
% ===================================================================

disp('Press any key to Close figure....');
pause;
close(f)


function [Q]=pointCloudPrinDir(V)

% function [Q]=pointCloudPrinDir(V)
% ------------------------------------------------------------------------
%
% Change log:
% 2019/04/28 Marked obsolete since function is the same as pointSetPrincipalDir
% ------------------------------------------------------------------------

[Q]=pointSetPrincipalDir(V);

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% 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 3 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, see <http://www.gnu.org/licenses/>.


function eeglabciplot(lower,upper,x,colour, alphaval)
% eeglabciplot(lower,upper)
% eeglabciplot(lower,upper,x)
% eeglabciplot(lower,upper,x,colour)
%
% Plots a shaded region on a graph between specified lower and upper confidence intervals (L and U).
% l and u must be vectors of the same length.
% Uses the 'fill' function, not 'area'. Therefore multiple shaded plots
% can be overlaid without a problem. Make them transparent for total visibility.
% x data can be specified, otherwise plots against index values.
% colour can be specified (eg 'k'). Defaults to blue.

% Author:   Raymond Reynolds 24/11/06
% Modified by Ramon Martinez Cancino

if length(lower)~=length(upper)
    error('lower and upper vectors must be same length')
end

if nargin<5
    alphaval = 1;
end
if nargin<4
    colour= 'r';
end

if nargin<3
    x=1:length(lower);
end

% convert to row vectors so fliplr can work
if find(size(x)==(max(size(x))))<2
x=x'; end
if find(size(lower)==(max(size(lower))))<2
lower=lower'; end
if find(size(upper)==(max(size(upper))))<2
upper=upper'; end

hdl_tmp = fill([x fliplr(x)],[upper fliplr(lower)],colour,'FaceAlpha', alphaval, 'EdgeColor', 'none');


function [ tempimg ] = visualCimage( img, cimages )
%VISUALCIMAGE Summary of this function goes here
%   Detailed explanation goes here

rl=[255  255   0  0    0    255  255];
gl=[255  0   255  255  0    0    255];
bl=[0    0   255  0    255  255  255];

[aa indd]=max(cimages,[],3);

% figure(102);
clear mask_color;
mask_r = rl(indd);
mask_g = gl(indd);
mask_b = bl(indd);
mask_color(:,:,1) = mask_r;
mask_color(:,:,2) = mask_g;
mask_color(:,:,3) = mask_b;

hsvmask=rgb2hsv(mask_color);
hsvmask(:,:,3)=aa*255;
%     hsvmask(:,:,2)=aa;
mask_color=hsv2rgb(hsvmask);

tempimg = double(img)*0.5 + mask_color*0.5;
%         tempimg =  mask_color;
% imshow(uint8(tempimg));

end


function out = isequal(f, g)
%ISEQUAL   Equality test for CHEBFUN3.
%   BOOL = ISEQUAL(F, G) returns logical 1 if F and G are same up to relative
%   machine precision. It returns logical 0 otherwise.
%
% The structure of this code is similar to `dematricize.m` from the HTUCKER
% toolbox of Tobler and Kressner.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

if ( isempty(f) )
    if ( isempty(g) )
        out = true;
    else
        out = false;
    end
    return
end

% Get low rank representation of f:
[fCore, fCols, fRows, fTubes] = tucker(f);

% Get low rank representation of g:
[gCore, gCols, gRows, gTubes] = tucker(g);

% Test every part:
out = ( isequal(fCore, gCore) & isequal(fCols, gCols) & ...
    isequal(fRows, gRows) & isequal(fTubes, gTubes) );

end


function MakeTableOfFunctions()
% MakeTableOfFunctions Outputs a csv summarizing INP_mops.txt
% ------------------------------------------------------------------------------
% Copyright (C) 2020, Ben D. Fulcher <ben.d.fulcher@gmail.com>,
% <http://www.benfulcher.com>
%
% If you use this code for your research, please cite the following two papers:
%
% (1) B.D. Fulcher and N.S. Jones, "hctsa: A Computational Framework for Automated
% Time-Series Phenotyping Using Massive Feature Extraction, Cell Systems 5: 527 (2017).
% DOI: 10.1016/j.cels.2017.10.001
%
% (2) B.D. Fulcher, M.A. Little, N.S. Jones, "Highly comparative time-series
% analysis: the empirical structure of time series and their methods",
% J. Roy. Soc. Interface 10(83) 20130048 (2013).
% DOI: 10.1098/rsif.2013.0048
%
% This work is licensed under the Creative Commons
% Attribution-NonCommercial-ShareAlike 4.0 International License. To view a copy of
% this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/ or send
% a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View,
% California, 94041, USA.
% ------------------------------------------------------------------------------

% Read in INP_mops.txt to get a list of functions
fid = fopen('INP_mops.txt');
Mops = textscan(fid,'%s %s','CommentStyle','#','CollectOutput',1);
fclose(fid);
Mops = Mops{1};
Mops = Mops(:,1);

% Split at the parenthesis:
MopsSplit = regexp(Mops,'(','split','ignorecase');
mFiles = cellfun(@(x)x{1},MopsSplit,'UniformOutput',false);
mFiles = unique(mFiles);
numMFiles = length(mFiles);

% Get help lines as descriptions:
helpLines = cell(numMFiles,1);
for i = 1:numMFiles
    helpMe = help(mFiles{i});
    newLines = regexp(helpMe,'\n');
    theTopLine = helpMe(1:newLines(1)-1);
    notSpaces = regexp(theTopLine,'\w*');
    helpLines{i} = theTopLine(notSpaces(2):end);
end

% Make a table
T = table(mFiles,helpLines);

% Output to csv:
writetable(T,'codeSummary.csv','Delimiter',',','QuoteStrings',true);

end


function ODG = PQnNetB (MOV)
% Neural net to get the final ODG

% P. Kabal $Revision: 1.1 $  $Date: 2003/12/07 13:27:44 $

persistent amin amax wx wxb wy wyb bmin bmax I J CLIPMOV
global PQopt

if (isempty (amin))
    I = length (MOV);
    if (I == 11)
        [amin, amax, wx, wxb, wy, wyb, bmin, bmax] = NNetPar ('Basic');
    else
        [amin, amax, wx, wxb, wy, wyb, bmin, bmax] = NNetPar ('Advanced');
    end
    [I, J] = size (wx);
end

sigmoid = inline ('1 / (1 + exp(-x))');

% Scale the MOV's
Nclip = 0;
MOVx = zeros (1, I);
for (i = 0:I-1)
    MOVx(i+1) = (MOV(i+1) - amin(i+1)) / (amax(i+1) - amin(i+1));
    if (~ isempty (PQopt) & PQopt.ClipMOV ~= 0)
        if (MOVx(i+1) < 0)
            MOVx(i+1) = 0;
            Nclip = Nclip + 1;
        elseif (MOVx(i+1) > 1)
            MOVx(i+1) = 1;
            Nclip = Nclip + 1;
        end
    end
end
if (Nclip > 0)
    fprintf ('>>> %d MOVs clipped\n', Nclip);
end

% Neural network
DI = wyb;
for (j = 0:J-1)
    arg = wxb(j+1);
    for (i = 0:I-1)
        arg = arg + wx(i+1,j+1) * MOVx(i+1);
    end
    DI = DI + wy(j+1) * sigmoid (arg);
end

ODG = bmin + (bmax - bmin) * sigmoid (DI);

function [amin, amax, wx, wxb, wy, wyb, bmin, bmax] = NNetPar (Version)

if (strcmp (Version, 'Basic'))
    amin = ...
        [393.916656,  361.965332,  -24.045116,    1.110661,  -0.206623, ...
           0.074318,    1.113683,    0.950345,    0.029985,   0.000101, ...
           0];
    amax = ...
        [921,         881.131226,   16.212030,  107.137772,   2.886017, ...
          13.933351,   63.257874, 1145.018555,   14.819740,   1,        ...
           1];
    wx = ...
        [ [ -0.502657,  0.436333,   1.219602 ];
          [  4.307481,  3.246017,   1.123743 ];
          [  4.984241, -2.211189,  -0.192096 ];
          [  0.051056, -1.762424,   4.331315 ];
          [  2.321580,  1.789971,  -0.754560 ];
          [ -5.303901, -3.452257, -10.814982 ];
          [  2.730991, -6.111805,   1.519223 ];
          [  0.624950, -1.331523,  -5.955151 ];
          [  3.102889,  0.871260,  -5.922878 ];
          [ -1.051468, -0.939882,  -0.142913 ];
          [ -1.804679, -0.503610,  -0.620456 ] ];
    wxb = ...
        [ -2.518254,  0.654841, -2.207228 ];
    wy = ...
        [ -3.817048,  4.107138,  4.629582 ];
    wyb = -0.307594;
    bmin = -3.98;
    bmax = 0.22;
else
    amin = ...
        [   13.298751,  0.041073,  -25.018791,  0.061560,   0.024523 ];
    amax = ...
        [ 2166.5,      13.24326,    13.46708,  10.226771,  14.224874 ];
    wx = ...
        [ [  21.211773, -39.913052, -1.382553, -14.545348,  -0.320899 ];
          [  -8.981803,  19.956049,  0.935389,  -1.686586,  -3.238586 ];
          [   1.633830,  -2.877505, -7.442935,   5.606502,  -1.783120 ];
          [   6.103821,  19.587435, -0.240284,   1.088213,  -0.511314 ];
          [  11.556344,   3.892028,  9.720441,  -3.287205, -11.031250 ] ];
    wxb = ...
        [   1.330890,   2.686103,    2.096598, -1.327851,   3.087055 ];
    wy = ...
        [ -4.696996,   -3.289959,    7.004782,  6.651897,   4.009144 ];
    wyb = -1.360308;
    bmin = -3.98;
    bmax = 0.22;
end


function bisection_rc_test ( )

%*****************************************************************************80
%
%% BISECTION_RC_TEST tests the BISECTION_RC library.
%
%  Location:
%
%    http://people.sc.fsu.edu/~jburkardt/m_src/bisection_rc/bisection_rc_test.m
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 January 2015
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'BISECTION_RC_TEST:\n' );
  fprintf ( 1, '  MATLAB version.\n' );
  fprintf ( 1, '  Test the BISECTION_RC library.\n' );

  bisection_rc_test01 ( );
  bisection_rc_test02 ( );
  bisection_rc_test03 ( );
  bisection_rc_test04 ( );
  bisection_rc_test05 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'BISECTION_RC_PRB:\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


% addpath('data');
% addpath(genpath('MSTV'));
% addpath(genpath('LPP'));
% addpath(genpath('OTVCA_V3'));
% addpath('RF classifier');

%% Load data
load Houston.mat;
HSI = Houston;
load TRLabel
load TSLabel
Tr = TRLabel;
Te = TSLabel;
clear TRLabel TSLabel Houston
%% Parameter setting
dim=max(unique(Te)); % Number of Features is set to the number of classes
Trees = 200; % for RF training
%% PCA+RF
[oa, pa, K, CM] = USFE_PCA(HSI, Tr, Te, dim, Trees);
aa = mean(pa);
%% MSTV+RF
[oa, pa, K, CM] = USFE_MSTV(HSI, Tr, Te, dim, Trees);
aa = mean(pa);
%% OTVCA Rasti et al.
[oa, pa, K, CM] = USFE_OTVCA(HSI, Tr, Te, dim, Trees);
aa = mean(pa);
%% LPP
[oa, pa, K, CM] = USFE_LPP(HSI, Tr, Te, dim, Trees);
aa = mean(pa);


function scanOut3M = interpScanToScan(baseScan,movScan,addToPlanCFlag,planC)
% function scanOut3M = interpScanToScan(baseScan,movScan,addToPlanCFlag,planC)
%
% This function interpolates movScan to baseScan grid by taking into
% account DICOM imageOrientation. baseScan and movScan must have sam eframe
% of reference for interpolation to be valid.
%
% baseScan = 1;
% movScan = 2;
% addToPlanCFlag = true;
% global planC % or load from file
% scanOut3M = interpScanToScan(baseScan,movScan,addToPlanCFlag,planC);
%
% APA, 3/7/2023

if ~exist('planC','var')
    global planC
end
indexS = planC{end};

% Check FOR
baseFOR = planC{indexS.scan}(baseScan).scanInfo(1).frameOfReferenceUID;
movFOR = planC{indexS.scan}(movScan).scanInfo(1).frameOfReferenceUID;

if ~isequal(baseFOR,movFOR)
    scanOut3M = [];
    return;
end

% Get physical (x,y,z) coordinates of baseScan in DICOM LPS
basePositionMatrix = planC{indexS.scan}(baseScan).Image2PhysicalTransM;
baseSizV = size(planC{indexS.scan}(baseScan).scanArray);
[rowM,colM] = meshgrid(1:baseSizV(1), 1:baseSizV(2));
rowColM = [rowM(:),colM(:)] - 1;
onesV = ones(size(rowColM,1),1);
numSlcVoxels = length(onesV);
xyzM = zeros(numSlcVoxels*baseSizV(3),4);
for slc = 1:baseSizV(3)
    rowColSlcM = [rowColM,onesV*(slc-1),onesV];
    xyzM(1+(slc-1)*numSlcVoxels:slc*numSlcVoxels,1:4) = (basePositionMatrix * rowColSlcM')';
end

% Get moving scan voxel indices (i,j,k) corresponding to (x,y,z) coordinates of the base scan
movSizV = size(planC{indexS.scan}(movScan).scanArray);
movPositionMatrix = planC{indexS.scan}(movScan).Image2PhysicalTransM;
ijkM = movPositionMatrix \ xyzM'; % col,row,slc
ijkM = round(ijkM);
nanV = sum(ijkM(1:3,:) < 0) > 0;
nanV = nanV | ijkM(2,:) > movSizV(1)-1 | ijkM(1,:) > movSizV(2)-1 | ijkM(3,:) > movSizV(3)-1;
indV = sub2ind(movSizV,ijkM(2,~nanV)+1,ijkM(1,~nanV)+1,ijkM(3,~nanV)+1);

% Get moving scan values at (i,j,k)
scanOut3M = zeros(baseSizV,'single');
movScan3M = single(planC{indexS.scan}(movScan).scanArray) - ...
    planC{indexS.scan}(movScan).scanInfo(1).CTOffset;
% slice order in cerr is opposite to dicom. (dicom 1st slice is inf, cerr 1st slice is sup)
% row, col order is same in cerr and dicom. i.e. (1st row, 1st col) is at the top left
% of the slice.
% Hence, flip moving scan along slice dim.
movScan3M = flip(movScan3M,3);
scanOut3M(~nanV) = movScan3M(indV);
scanOut3M = flip(scanOut3M,3);

% Add scan to planC
if addToPlanCFlag
    [xVals, yVals, zVals] = getScanXYZVals(planC{indexS.scan}(baseScan));
    deltaXYZv = getScanXYZSpacing(baseScan,planC);
    zV = zVals(:);
    regParamsS.horizontalGridInterval = deltaXYZv(1);
    regParamsS.verticalGridInterval = deltaXYZv(2);
    regParamsS.coord1OFFirstPoint = xVals(1);
    regParamsS.coord2OFFirstPoint   = yVals(end);

    regParamsS.zValues  = zV;
    regParamsS.sliceThickness = [planC{indexS.scan}(baseScan).scanInfo(:).sliceThickness];

    assocTextureUID = '';
    scanType = [planC{indexS.scan}(movScan).scanType,'_interp_',...
        planC{indexS.scan}(baseScan).scanType];

    planC = scan2CERR(scanOut3M,scanType,'Passed',regParamsS,assocTextureUID,planC);
end