classdef BackgroundSubtractorLSBP < handle
    %BACKGROUNDSUBTRACTORLSBP  Background Subtraction using Local SVD Binary Pattern
    %
    % More details about the algorithm can be found at [LGuo2016].
    %
    % It is based on LSBP feature descriptors and achieves state-of-the-art
    % performance on the CDnet 2012 dataset. LSBP descriptors are particularly
    % good in regions with illumination variation, noise and shadows. So, this
    % algorithm has better performance in this kind of regions.
    %
    % After extraction of LSBP descriptors, the algorithm processes frames
    % pixel-wise (i.e independently). Thus the implementation is parallelized
    % and fast enough for real-time processing.
    %
    % ## References
    % [LGuo2016]:
    % > L. Guo, D. Xu, and Z. Qiang. "Background Subtraction using Local SVD
    % > Binary Pattern". In 2016 IEEE Conference on Computer Vision and
    % > Pattern Recognition Workshops (CVPRW), pages 1159-1167, June 2016.
    % > [PDF](http://www.cv-foundation.org/openaccess/content_cvpr_2016_workshops/w24/papers/Guo_Background_Subtraction_Using_CVPR_2016_paper.pdf)
    %
    % See also: cv.BackgroundSubtractorLSBP.BackgroundSubtractorLSBP,
    %  cv.BackgroundSubtractorLSBP.apply,
    %  cv.BackgroundSubtractorLSBP.getBackgroundImage
    %

    properties (SetAccess = private)
        % Object ID
        id
    end

    %% BackgroundSubtractor
    methods
        function this = BackgroundSubtractorLSBP(varargin)
            %BACKGROUNDSUBTRACTORLSBP  Creates a LSBP Background Subtractor
            %
            %     bs = cv.BackgroundSubtractorLSBP()
            %     bs = cv.BackgroundSubtractorLSBP('OptionName', optionValue, ...)
            %
            % ## Options
            % * __MotionCompensation__ Whether to use camera motion
            %   compensation. One of:
            %   * __None__ (default)
            %   * __LK__
            % * __NSamples__ Number of samples to maintain at each point of
            %   the frame. default 20
            % * __LSBPRadius__ LSBP descriptor radius. default 16
            % * __TLower__ Lower bound for T-values. See [LGuo2016] for
            %   details. default 2.0
            % * __TUpper__ Upper bound for T-values. See [LGuo2016] for
            %   details. default 32.0
            % * __TInc__ Increase step for T-values. See [LGuo2016] for
            %   details. default 1.0
            % * __TDec__ Decrease step for T-values. See [LGuo2016] for
            %   details. default 0.05
            % * __RScale__ Scale coefficient for threshold values. default 10.0
            % * __RIncDec__ Increase/Decrease step for threshold values.
            %   default 0.005
            % * __NoiseRemovalThresholdFacBG__ Strength of the noise removal
            %   for background points. default 0.0004
            % * __NoiseRemovalThresholdFacFG__ Strength of the noise removal
            %   for foreground points. default 0.0008
            % * __LSBPThreshold__ Threshold for LSBP binary string. default 8
            % * __MinCount__ Minimal number of matches for sample to be
            %   considered as foreground. default 2
            %
            % See also: cv.BackgroundSubtractorLSBP
            %
            this.id = BackgroundSubtractorLSBP_(0, 'new', varargin{:});
        end

        function delete(this)
            %DELETE  Destructor
            %
            %     bs.delete()
            %
            % See also: cv.BackgroundSubtractorLSBP
            %
            if isempty(this.id), return; end
            BackgroundSubtractorLSBP_(this.id, 'delete');
        end

        function fgmask = apply(this, im, varargin)
            %APPLY  Updates the background model and computes the foreground mask
            %
            %     fgmask = bs.apply(im)
            %     fgmask = bs.apply(im, 'OptionName', optionValue, ...)
            %
            % ## Input
            % * __im__ Next video frame.
            %
            % ## Output
            % * __fgmask__ The output foreground mask as an 8-bit binary image
            %   (0 for background, 255 for foregound).
            %
            % ## Options
            % * __LearningRate__ The value between 0 and 1 that indicates how
            %   fast the background model is learnt. Negative parameter value
            %   makes the algorithm to use some automatically chosen learning
            %   rate. 0 means that the background model is not updated at all,
            %   1 means that the background model is completely reinitialized
            %   from the last frame. default -1
            %
            % See also: cv.BackgroundSubtractorLSBP.getBackgroundImage
            %
            fgmask = BackgroundSubtractorLSBP_(this.id, 'apply', im, varargin{:});
        end

        function bgImg = getBackgroundImage(this)
            %GETBACKGROUNDIMAGE  Computes a background image
            %
            %     bgImg = bs.getBackgroundImage()
            %
            % ## Output
            % * __bgImg__ The output background image.
            %
            % See also: cv.BackgroundSubtractorLSBP.apply
            %
            bgImg = BackgroundSubtractorLSBP_(this.id, 'getBackgroundImage');
        end
    end

    %% Algorithm
    methods (Hidden)
        function clear(this)
            %CLEAR  Clears the algorithm state
            %
            %     obj.clear()
            %
            % See also: cv.BackgroundSubtractorLSBP.empty
            %
            BackgroundSubtractorLSBP_(this.id, 'clear');
        end

        function b = empty(this)
            %EMPTY  Returns true if the algorithm is empty
            %
            %     b = obj.empty()
            %
            % ## Output
            % * __b__ Returns true if the algorithm is empty (e.g. in the very
            %   beginning or after unsuccessful read).
            %
            % See also: cv.BackgroundSubtractorLSBP.clear
            %
            b = BackgroundSubtractorLSBP_(this.id, 'empty');
        end

        function name = getDefaultName(this)
            %GETDEFAULTNAME  Returns the algorithm string identifier
            %
            %     name = obj.getDefaultName()
            %
            % ## Output
            % * __name__ This string is used as top level XML/YML node tag
            %   when the object is saved to a file or string.
            %
            % See also: cv.BackgroundSubtractorLSBP.save,
            %  cv.BackgroundSubtractorLSBP.load
            %
            name = BackgroundSubtractorLSBP_(this.id, 'getDefaultName');
        end

        function save(this, filename)
            %SAVE  Saves the algorithm to a file
            %
            %     obj.save(filename)
            %
            % ## Input
            % * __filename__ Name of the file to save to.
            %
            % This method stores the algorithm parameters in a file storage.
            %
            % See also: cv.BackgroundSubtractorLSBP.load
            %
            BackgroundSubtractorLSBP_(this.id, 'save', filename);
        end

        function load(this, fname_or_str, varargin)
            %LOAD  Loads algorithm from a file or a string
            %
            %     obj.load(fname)
            %     obj.load(str, 'FromString',true)
            %     obj.load(..., 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __fname__ Name of the file to read.
            % * __str__ String containing the serialized model you want to
            %   load.
            %
            % ## Options
            % * __ObjName__ The optional name of the node to read (if empty,
            %   the first top-level node will be used). default empty
            % * __FromString__ Logical flag to indicate whether the input is a
            %   filename or a string containing the serialized model.
            %   default false
            %
            % This method reads algorithm parameters from a file storage.
            % The previous model state is discarded.
            %
            % See also: cv.BackgroundSubtractorLSBP.save
            %
            BackgroundSubtractorLSBP_(this.id, 'load', fname_or_str, varargin{:});
        end
    end

    %% BackgroundSubtractorLSBPDesc
    methods (Static)
        function desc = computeLSBPDesc(frame, LSBPSamplePoints)
            %COMPUTELSBPDESC  This is for calculation of the LSBP descriptors
            %
            %     desc = cv.BackgroundSubtractorLSBP.computeLSBPDesc(frame, LSBPSamplePoints)
            %
            % ## Input
            % * __frame__ input frame
            % * __LSBPSamplePoints__ 32 sample points
            %
            % ## Output
            % * __desc__ LSBP descriptors
            %
            desc = BackgroundSubtractorLSBP_(0, 'computeLSBPDesc', frame, LSBPSamplePoints);
        end
    end

end


startup

% specify your paths to the datasets
name = {'VV' 'LIME' 'NPE' 'NPE-ex1' 'NPE-ex2' 'NPE-ex3' 'MEF' 'DICM'};
dataset = strcat('data', filesep, name, filesep, '*.*');

% specify methods and metrics
method = {@multiscaleRetinex @dong @npe @lime @mf @srie @BIMEF};
metric = {@loe100x100};
% metric = {@loe100x100 @vif}; % NOTE matlabPyrTools is required to run VIF metric (vif.m).

for n = 1:numel(dataset); data = dataset{n};
    data,
    Test = TestImage(data);
    Test.Method = method;
    Test.Metric = metric;

    % run test and display results
    Test,

    % save test to a .csv file
    save(Test); % %save(Test, ['TestReport__' name{n} '.csv']);
end


function [data,Qgp,Qvb,ax] = novac2010_mohsst5(data, Qgp, Qvb)

if nargin < 1 || isempty(data)
  data = mohsst5_loaddata;
end

if nargin < 2 || isempty(Qgp)
  % GPPCA dates, e.g., 20091001 (crashed), 20090824, 20090820 (crashed),
  % 20090819 (crashed)
  Qgp = load(['mohsst5_weighted_testsize=20_D=80_Wcov=se_Wden=30_Xcov=se-' ...
              'per-cs_Xden=5_iter=200_date=20090824'], 'W', 'varW', 'X', ...
             'varX', 'tau', 'pseudoX', 'Xp', 'CovXp', 'logthetaX', ...
             'covfuncX');
% $$$   Qgp = load(['mohsst5_weighted_testsize=20_D=80_Wcov=se_Wden=30_Xcov=se-' ...
% $$$               'per-cs_Xden=5_iter=50_date=20090604'], 'W', 'varW', 'X', ...
% $$$              'varX', 'tau', 'loglikelihood');
end

if nargin < 3
  % VBPCA
  Qvb = load(['mohsst5_weighted_VBPCA_testsize=20_D=80_iter=50_date=' ...
              '20090601']);
  % Do rotation for some components
  Qvb.A(:,4) = -Qvb.A(:,4);
  Qvb.S(4,:) = -Qvb.S(4,:);

end

weights = sqrt(cosd(data.coordinates(2,:)));
lands = colsum(~isnan(data.observations)) == 0;
if rows(Qgp.W) == 1727 % t
  D = cols(Qgp.W);
  disp('The results are not ready? Fill the lands and use inverse weights..')
  W = zeros([rows(data.observations),D]);
  varW = W;
  W(~lands,:) = Qgp.W;
  varW(~lands,:) = Qgp.varW;
  Qgp.W = bsxfun(@rdivide, W, weights(:));
  Qgp.varW = bsxfun(@rdivide, varW, weights(:).^2);
end

% $$$ totally_missing_columns = sum( sum(~isnan(data.observations),1) == 0)
% $$$ return

[M,N] = size(data.observations);

% Choose what to show
plot_comps = false;
mixing_weights = true;

% $$$
% $$$ % Plot spatial and temporal components
% $$$ if plot_comps
% $$$
% $$$   % GPFA
% $$$   [mapfigh, tsfigh] = mohsst5_plotexperiment(data, Qgp, true, 1:4);
% $$$
% $$$   % Saturate the second component
% $$$   warning('Saturating the second spatial component of GPFA!')
% $$$   ax = findobj(mapfigh, 'type', 'axes')
% $$$   set(ax(6), 'clim', [-0.7 0.7]);
% $$$   set(ax(4), 'clim', [-0.9 0.9]);
% $$$ %  return
% $$$
% $$$ % $$$   print(mapfigh, '-depsc2', ['/home/jluttine/papers/2009NIPS/' ...
% $$$ % $$$                     'fig_experiment_loadings_gppca.eps']);
% $$$ % $$$   print(tsfigh, '-depsc2', ['/home/jluttine/papers/2009NIPS/' ...
% $$$ % $$$                     'fig_experiment_timeseries_gppca.eps']);
% $$$
% $$$   % VBPCA
% $$$   [mapfigh, tsfigh] = mohsst5_plotexperiment(data, Qvb, false, 1:4);
% $$$
% $$$   % Saturate the VBPCA components
% $$$   warning('Saturating VBPCA components');
% $$$   ax = findobj(mapfigh, 'type', 'axes')
% $$$   set(ax(8), 'clim', [-1 1]);
% $$$   set(ax(6), 'clim', [-0.8 0.8]);
% $$$   set(ax(4), 'clim', [-0.7 0.7]);
% $$$   set(ax(2), 'clim', [-0.7 0.7]);
% $$$
% $$$ % $$$   print(mapfigh, '-depsc2', ['/home/jluttine/papers/2009NIPS/' ...
% $$$ % $$$                     'fig_experiment_loadings_vbpca.eps']);
% $$$ % $$$   print(tsfigh, '-depsc2', ['/home/jluttine/papers/2009NIPS/' ...
% $$$ % $$$                     'fig_experiment_timeseries_vbpca.eps']);
% $$$ end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Mixing weights from the GP components to PCA components
if mixing_weights

  indsX = 1:N;

  %%%% FOR VBPCA %%%%

  if true

    % DON'T ROTATE VBPCA RESULTS BECAUSE THE COVARIANCE MATRIX Av IS
    % CORRUPTED!!!!
    %
    % An adhoc solution:
    Av = covcell_to_covarray(Qvb.Av);
    Av(:) = 0;

    plot_pca_components(Qvb.A, Av, Qvb.S, covcell_to_covarray(Qvb.Sv), ...
                        data,'VBPCA', indsX, false);

  end

  %%%% FOR GPPCA %%%%

  %% Preprocess

  spatial_pca = false;

  if ~spatial_pca
    % First, remove bias and scale the GP components to unit variance
    X0 = bsxfun(@minus, Qgp.X, mean(Qgp.X,2));
    % Scale to unit variance
    xx = var(X0,1,2) + mean(Qgp.varX,2); % variance whitening
    sqrtxx = sqrt(xx);
    varX = bsxfun(@rdivide, Qgp.varX, xx);
    X = bsxfun(@rdivide, X0, sqrtxx);
    varW = bsxfun(@times, Qgp.varW, xx');
    W = bsxfun(@times, Qgp.W, sqrtxx');
  else
    disp('Plotting spatial PCA, is this correct??')
    % First, remove bias and scale the GP components to unit variance
    W0 = bsxfun(@minus, Qgp.W, mean(Qgp.W,1));
    % Scale to unit variance
    xx = mean(Qgp.X.^2,2) + mean(Qgp.varX,2); % 2nd moment whitening
    % xx = var(Qgp.X,1,2) + mean(Qgp.varX,2); % variance whitening
    sqrtxx = sqrt(xx);
    varX = bsxfun(@rdivide, Qgp.varX, xx);
    X = bsxfun(@rdivide, Qgp.X, sqrtxx);
    varW = bsxfun(@times, Qgp.varW, xx');
    W = bsxfun(@times, W0, sqrtxx');
  end

  % Variances to covariance matrices
  [M,D] = size(W);
  [D,N] = size(X);
  CovX = zeros([D D N]);
  for n=1:N
    CovX(:,:,n) = diag(varX(:,n));
  end
  CovW = zeros([D D M]);
  for m=1:M
    CovW(:,:,m) = diag(varW(m,:));
  end

  plot_pca_components(W,CovW,X, CovX,data,'GPPCA', indsX, true);

end

function [W,CovW,X,CovX,R,scaledR] = plot_pca_components(W,CovW,X,CovX, ...
                                                  data,method, indsX, rotate)

[M,D] = size(W);
[D,N] = size(X);

if nargin < 7 || isempty(indsX)
  indsX = 1:N;
end
if nargin < 8 || isempty(rotate)
  rotate = true;
end

% Ignore the not requested indices
X(:,setdiff(1:N,indsX)) = 0;
CovX(:,:,setdiff(1:N,indsX)) = 0;

% Ignore land areas
lands = colsum(~isnan(data.observations)) == 0;
W(lands,:) = 0;
CovW(:,:,lands) = 0;

weights2 = cosd(data.coordinates(2,:));
if rotate
  % Rotate to pca
  [W,CovW,X,CovX,R] = rotate_to_pca(W,CovW,X,CovX,weights2);
else
  R = eye(D);
end

% Evaluate explained variance for each component
WW = W'*diag(weights2)*W;
for m=1:M
  WW = WW + weights2(m) * CovW(:,:,m);
end

% Debug stuff:
%XX = X*X' + sum(CovX,3)
%error = mean(mean( abs(W*X - W_old*X_old) ))

%WW10 = WW(1:20,1:20)
S = sqrt(diag(diag(WW/size(W,1))));
scaledR = S*R;

if strcmpi(method, 'gppca')
  % Change the sign of some components
  R = eye(D);
  R(1,1) = -1;
  R(2,2) = -1;
  W = W * R;
  X = R * X;
end
if strcmpi(method, 'vbpca')
  % Change the sign of some components
  R = eye(D);
  R(3,3) = -1;
  W = W * R;
  X = R * X;
end

if true
  % Plot temporal PCA components
  Xpca = X;
  varXpca = zeros(size(X));
  for n=1:N
    varXpca(:,n) = diag(CovX(:,:,n));
  end
  eX = 2*sqrt(varXpca);
  hax = tsgpplot(data.time, Xpca(1:4,:)', eX(1:4,:)');

  % Publication style
  for j = 1:length(hax)
    xlim(hax(j), [min(data.time) max(data.time)]);
    set( hax(j), 'YTick', [] )
    set( hax(j), 'YTickLabel', [] )
    datetick(hax(j), 'x', 10, 'keeplimits');
    if j ~= length(hax)
      set(hax(j), 'xticklabel', []);
    end
  end
% $$$   set(gcf, 'Units', 'centimeters');
% $$$   pos = get(gcf, 'Position');
% $$$   figw = 35;
% $$$   figh = 8;
% $$$   set(gcf, 'Position', [pos(1) pos(2) figw figh]);
% $$$   set(gcf, 'PaperPositionMode', 'auto', 'PaperSize', [figw figh]);
  set_subplot_positions(hax, 4,1, [0.01 0.01 0.01 0.3], [0.01 0.01]);
  set_ticks_fontsize(hax, 5);
  set_figure_size(gcf, 13, 7);
  filename = sprintf(['/home/jluttine/thesis/figures/' ...
                      'novac2010_experiment_timeseries_%s.eps'], lower(method));
  print(gcf, '-depsc2', filename);
end

if true
  % Plot spatial PCA components
  figure
  mapproj('global-ellipse');
  [LON,LAT] = meshgrid(data.longitude, data.latitude);
  comps = 1:4;
  hax = [];
  h_cb = [];
  for d=comps
    subplot(1,4,d)
    set(gca, 'xtick', [], 'ytick', []);
    mappcolor(LON, LAT, reshape(W(:,d), size(LON)));
    h_cb(d) = colorbar('SouthOutside');
    hax(d) = gca;
    mapcoast;

    if strcmpi(method, 'vbpca')
      switch d
       case 1
        disp('Saturating vbpca 1-component')
        set(gca, 'clim', [-0.8 0.8]);
       case 2
        disp('Saturating vbpca 2-component')
        set(gca, 'clim', [-0.8 0.8]);
       case 4
        disp('Saturating vbpca 4-component')
        set(gca, 'clim', [-0.8 0.8]);
      end
    end
  end

  % Publication style:
  set_subplot_positions(hax, 1,4, [0.01 0.01 0.01 0.3], [0.01 0.01]);
  set_colorbar_position(h_cb, hax, 0.04, 0.04);
  set(h_cb, 'FontSize', 5);
  set_figure_size(gcf, 13, 2.3);
  filename = sprintf(['/home/jluttine/thesis/figures/' ...
                      'novac2010_experiment_loadings_%s.eps'], lower(method));
  print(gcf, '-depsc2', filename);

end


filename='CantileverSquare';
ptype = 'MACRO';
initial_case = 'full';
%cost = {'compliance'};
cost = {'stressNorm'};
weights = 1;
constraint = {'volumeConstraint'};
filterType = 'P1';

optimizer = 'DualNestedInPrimal';
optimizerUnconstrained = 'PROJECTED GRADIENT';
designVariable = 'MicroParams';
homegenizedVariablesComputer = 'ByVademecum';
vademecumFileName = 'Rectangle';%'SmoothRectangle';
%vademecumFileName = 'SmoothRectangle';

nsteps = 1;
maxiter = 500;

Vfrac_initial = 0.3;
Vfrac_final = 0.3;

optimality_initial = 1e-5;
optimality_final = 1e-5;
constr_initial = 1e-3;
constr_final = 1e-3;

printing = false;
monitoring_interval = 1;

ub = 0.989;
lb = 0.011;
rate = 0.5;


function [l] = read_label(sname, lname)
% l = read_label(<sname>, lname)
%
% reads the label file 'lname' from the subject 'sname'
% in the subject's label directory into the vector l
% l will be nvertices-by-5, where each column means:
% (1) vertex number, (2-4) xyz at each vertex, (5) stat
%
% IMPORTANT: the vertex number is 0-based.
%

%
% read_label.m
%
% Original Author: Bruce Fischl
% CVS Revision Info:
%    $Author: nicks $
%    $Date: 2011/03/02 00:04:12 $
%    $Revision: 1.7 $
%
% Copyright © 2011 The General Hospital Corporation (Boston, MA) "MGH"
%
% Terms and conditions for use, reproduction, distribution and contribution
% are found in the 'FreeSurfer Software License Agreement' contained
% in the file 'LICENSE' found in the FreeSurfer distribution, and here:
%
% https://surfer.nmr.mgh.harvard.edu/fswiki/FreeSurferSoftwareLicense
%
% Reporting: freesurfer@nmr.mgh.harvard.edu
%

l = [];

if(nargin ~= 2)
  fprintf('l = read_label(<sname>, lname)\n');
  return;
end

if(~isempty(sname))
  sdir = getenv('SUBJECTS_DIR') ;
  fname = sprintf('%s/%s/label/%s.label', sdir, sname, lname) ;
else
	ind = findstr(lname, '.label') ;
	if (length(ind) > 0)
        fname = lname ;
    else
		fname = sprintf('%s.label', lname);
	end
end

% open it as an ascii file
fid = fopen(fname, 'r') ;
if(fid == -1)
  fprintf('ERROR: could not open %s\n',fname);
  return;
end

fgets(fid) ;
if(fid == -1)
  fprintf('ERROR: could not open %s\n',fname);
  return;
end

line = fgets(fid) ;
nv = sscanf(line, '%d') ;
l = fscanf(fid, '%d %f %f %f %f\n') ;
l = reshape(l, 5, nv) ;
l = l' ;

fclose(fid) ;


function mpc = t_case_tlmp
%T_CASE_TLMP  Single bus, 2-gen case for TLMP examples from Cong Chen
%   Please see CASEFORMAT for details on the case file format.

%   MOST
%   Copyright (c) 2022, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MOST.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://github.com/MATPOWER/most for more info.

%% MATPOWER Case Format : Version 2
mpc.version = '2';

%%-----  Power Flow Data  -----%%
%% system MVA base
mpc.baseMVA = 100;

%% bus data
%	bus_i	type	Pd	Qd	Gs	Bs	area	Vm	Va	baseKV	zone	Vmax	Vmin
mpc.bus = [
	1	3	0	0	0	0	1	1	0	135	1	1.05	0.95;
	2	1	0	0	0	0	1	1	0	135	1	1.05	0.95;
];

%% generator data
%	bus	Pg	Qg	Qmax	Qmin	Vg	mBase	status	Pmax	Pmin	Pc1	Pc2	Qc1min	Qc1max	Qc2min	Qc2max	ramp_agc	ramp_10	ramp_30	ramp_q	apf
mpc.gen = [
	1	450	0	50	-50	1	100	1	500	0	0	0	0	0	0	0	0	1000	1000	0	0;
	1	50	0	50	-50	1	100	1	500	0	0	0	0	0	0	0	0	1000	1000	0	0;
	2	-420	0	0	0	1	100	1	0	-450	0	0	0	0	0	0	0	1000	1000	0	0;
];

%% branch data
%	fbus	tbus	r	x	b	rateA	rateB	rateC	ratio	angle	status	angmin	angmax
mpc.branch = [
	1	2	0.005	0.01	0	0	0	3	0	0	1	-360	360;
];

%%-----  OPF Data  -----%%
%% generator cost data
%	1	startup	shutdown	n	x1	y1	...	xn	yn
%	2	startup	shutdown	n	c(n-1)	...	c0
mpc.gencost = [
	2	0	0	2	25	0;
	2	0	0	2	30	0;
	2	0	0	2	1000	0;
];


function varargout = trace(varargin)
% TRACE integral of a CHEBFUN2 along its diagonal
%
% TRACE(f) is the integral of function f(x,x).
%
% See also DIAG.

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

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

end


function [scales, scalesK] = hsvargplvmRetainedScales(model, thresh, displPlots, displ)

if nargin < 4 || isempty(displ)
    displ = false;
end

if nargin < 3 || isempty(displPlots)
    displPlots = true;
end

if nargin < 2 || isempty(thresh)
    thresh = 0.01;
end

for h=1:model.H
    scalesK{h} = zeros(model.layer{h}.M, model.layer{h}.q);
    scalesAll{h} = zeros(model.layer{h}.M, model.layer{h}.q);
    scalesAllTmp{h} = svargplvmScales('get', model.layer{h});

    for m=1:model.layer{h}.M
        scales{h}{m} = vargplvmRetainedScales(model.layer{h}.comp{m},thresh);
        scalesK{h}(m,scales{h}{m}) = 1;
        scalesAll{h}(m,:) = scalesAllTmp{h}{m};
        scalesAll{h}(m,:) = scalesAll{h}(m,:) / max(scalesAll{h}(m,:)); %% Scale so that 1 is max
    end
end

if displPlots
    for h=1:model.H
        if model.layer{h}.M > 1
            figure
            imagesc(scalesAll{h}); title(['All scales for layer ' num2str(h)]);     set(gca,'XGrid','on')
            figure
            imagesc(scalesK{h}); title(['Binarized scales for layer ' num2str(h)]);     set(gca,'XGrid','on')
        end
    end
end

if displ
    for h=1:model.H
        fprintf('# Layer %d\n', h)
        fprintf(' q  | Scales\n')
        fprintf('------------------\n')
        for q=1:model.layer{h}.M
            fprintf(' %d | %s \n',q,num2str(scales{h}{q}));
        end
        fprintf('\n');
    end
end


function cmap = grayColorCmap(numGrays,numColors)
%
% cmap = grayColorCmap(numGrays,numColors)
%
% Makes colormap array with:
%   gray scale - 1:numGrays
%   jet colors - numGrays+1:numGrays+numColors
%
% This one differs from grayCmap.m as this one has both gray band and color
% band in gray color.

if ~exist('numGrays','var')
    numGrays = 128;
end
if ~exist('numColors','var')
    numColors = 128;
end

cmap = zeros(numGrays+numColors,3);
cmap(1:numGrays+numColors,:) = [gray(numGrays);gray(numColors)];


function definput=arg_firwin(definput)

truncgaussflags = {'truncgauss'};

definput.flags.wintype=[{...
    'hanning','hann','sine','cosine', 'sqrthann','hamming', 'square',...
    'rect', 'tria','bartlett', 'triangular','sqrttria','blackman',...
    'blackman2', 'nuttall','nuttall10','nuttall01','nuttall20',...
    'nuttall11','nuttall03', 'nuttall12','nuttall21', 'nuttall30',...
    'ogg', 'itersine', 'nuttall02'}, truncgaussflags ];


function cx = csscal ( n, sa, cx, incx )

%*****************************************************************************80
%
%% CSSCAL scales a complex vector by a real constant.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 April 2006
%
%  Author:
%
%    MATLAB version by John Burkardt
%
%  Reference:
%
%    Jack Dongarra, Jim Bunch, Cleve Moler, Pete Stewart,
%    LINPACK User's Guide,
%    SIAM, 1979,
%    ISBN13: 978-0-898711-72-1,
%    LC: QA214.L56.
%
%    Charles Lawson, Richard Hanson, David Kincaid, Fred Krogh,
%    Basic Linear Algebra Subprograms for Fortran Usage,
%    Algorithm 539,
%    ACM Transactions on Mathematical Software,
%    Volume 5, Number 3, September 1979, pages 308-323.
%
%  Parameters:
%
%    Input, integer N, the number of entries in the vector.
%
%    Input, real SA, the multiplier.
%
%    Input, complex CX(*), the vector to be scaled.
%
%    Input, integer INCX, the increment between successive entries of
%    the vector CX.
%
%    Output, complex CX(*), the scaled vector.
%
  cx(1:incx:1+(n-1)*incx) = sa * cx(1:incx:1+(n-1)*incx);

  return
end


% mvm_demo

% OVERVIEW: This script provides a demo on how to execute the MVM function,
% part of the MVToolbox in the Physionet-Cardiovascular-Signal-Toolbox.
% This demo script does the following,
% 1. Loads a sample ECG with annotations from the ./MVtoolbox/Demos/testdata subfolder
% 2. Remove power line interference at 60 Hz and baseline wander signal
% from the ecg
% 3. Perform arrhythmia detection on each of the segment_size min analysis windows,
% avoid performing MVM analysis on windows with positive arrythmia
% detection
% 4. Compute MVM on segment_size min windows not affected by arrhythmia
% 5. Store the output in the following variables,
%
%       variable                description (Units)
%       energyinband_array      QRS variability energy measured for each analysis window in the beatquency
%                               domain (beats^(-2))
%       sqi_array               The signal quality measured for each analysis
%                               window (unitless with value in the closed interval [0,1]. higher values mean cleaner signals)
%       heart_rate_estimate     The estimate of the median heart rate for each
%                               analysis window is given in this array (beats per minute)
%
% The expected values for each of the output variables is as follows,
%       energyinband_array = [8.6362e-08,NaN,1.1978e-07]
%       sqi_array = [0.9988,NaN,1]
%       heart_rate_estimate = [80,NaN,79.893]
%
% REPO:
%       https://github.com/cliffordlab/PhysioNet-Cardiovascular-Signal-Toolbox
%   ORIGINAL SOURCE AND AUTHORS:
%       Written by Ismail Sadiq
%	COPYRIGHT (C) 2019
%   LICENSE:
%       This software is offered freely and without warranty under
%       the GNU (v3 or later) public license. See license file for
%       more information. The license may be found in
%       the Documents folder of the Physionet-Cardiovascular-Signal-Toolbox.

% Load test ecg data
addpath(genpath('../../../../../PhysioNet-Cardiovascular-Signal-Toolbox-master/')); % add all dependencies from cardiovascular signal toolbox
sig = load('./testdata/mvm/sample_ecg_datam');
siginfo = readheader('./testdata/mvm/sample_ecg_datam.hea');
Fs = siginfo.freq;
ecg = (sig.val - siginfo.adczero)./siginfo.gain; % Adjust signal according to gain and dc offset
clear siginfo sig;

% Read QRSon, Q, R, S, QRSoff fiducial point annotations. Multiple
ann.QRSon = read_ann('./testdata/mvm/sample_ecgm','qrson'); ann.Q = read_ann('./testdata/mvm/sample_ecgm','q'); ann.R = read_ann('./testdata/mvm/sample_ecgm','r'); ann.S = read_ann('./testdata/mvm/sample_ecgm', 's'); ann.QRSoff = read_ann('./testdata/mvm/sample_ecgm', 'qrsoff');
%figure(1); plot(ecg); hold on; % Check annotation if needed
%stem(ann.QRSon, ecg(ann.QRSon)); stem(ann.Q, ecg(ann.Q)); stem(ann.R, ecg(ann.R)); stem(ann.S, ecg(ann.S)); stem(ann.QRSoff, ecg(ann.QRSoff)); hold off

% Read filter coefficients for power line interference (pli) filter
b = csvread('../Tools/MVM/pli_filter_coef_fs1000.csv');

% Add path to helper functions
addpath('../Tools/MVM/')

% Remove baseline wander
baseline = medianfilter_is(ecg, Fs);
ecg_baselinefree = ecg - baseline;

% Remove pli
% Filter each signal for pli
ecg_filtered = filter(b,1,ecg_baselinefree); clear ecg_baselinefree baseline
% Remove delay
delay = mean(grpdelay(b));
ecg_filtered(1:delay) = [];

% Detect arrhythmia

% Compute feature
minute_duration = 1*60*Fs;   % Duration of 1 minute in samples
segment_size = 5;   % Size of MVM analysis window in minutes
ii = 1; % Index to keep track of each non overlapping segment_size minute window

energyinband_array = NaN(1,ceil(length(ecg_filtered)/(segment_size*minute_duration))); % Array for storing the MVM energy evalauted for each segment_size minute analysis window, initialze to length of max possible non overlapping segment_size minute windows
sqi_array = energyinband_array; % Array for storing the signal quality for each analysis window, same dimensions as energyinband_array
heart_rate_est = energyinband_array; % Array for storing the heart rate estimate for each analysis window, same dimensions as energyinband_array
while (ii <= length(ecg_filtered))

    % Use atrial fibirillation arrhythmia detection in 60 beat non overlapping windows for each segment_size min analysis window
    if (ii+segment_size*minute_duration-1 > length(ecg_filtered))
        % Length of last analysis window is less than segment_size minutes, perform analysis till end of record
        endi = length(ecg_filtered);
    else
        endi = ii+segment_size*minute_duration-1;
    end

    % Get current 60 beat window for arrhythmia detection
    cur_win_r = ann.R(ann.R > ii); cur_win_r = cur_win_r(cur_win_r < endi);
    Index_test = NaN(1,ceil(length(cur_win_r)/60)); % Variable for storing arrhythmia detection for each 60 beat window
    for jj = 1:60:length(cur_win_r)
        % Get the current 60 beat window for arrhythmia detection
        if (jj+59 <= length(cur_win_r))
            cur_r = cur_win_r(jj:jj+59);
        else
            cur_r = cur_win_r(jj:end);
        end

        % If fewer than 12 beats or greater than 60 beats in the current
        % window do not perform arrhythmia detection
        if (length(diff(cur_r)) >= 12 && length(diff(cur_r)) <= 60)
            features = AF_features(diff(cur_r),Fs);
            Index_test(ceil(jj/60)) = SVM_AFdetection_withoutTrainingModel(features,1);
        else
            disp('Please input a RR interval time series with number of beats between 12 and 60')
        end

    end

    if (nansum(Index_test) == 0)
        % If no arrhythmia detection in current segment_size min window, compute MVM

        % Get qrson, q, r, s, qrsoff annotations for current window
        ann_win.R = cur_win_r-ii+1;
        ann_win.QRSon = ann.QRSon(ann.QRSon > ii); ann_win.QRSon = ann_win.QRSon(ann_win.QRSon < endi)-ii+1;
        ann_win.Q = ann.Q(ann.Q > ii); ann_win.Q = ann_win.Q(ann_win.Q < endi)-ii+1;
        ann_win.S = ann.S(ann.S > ii); ann_win.S = ann_win.S(ann_win.S < endi)-ii+1;
        ann_win.QRSoff = ann.QRSoff(ann.QRSoff > ii); ann_win.QRSoff = ann_win.QRSoff(ann_win.QRSoff < endi)-ii+1;

        % Get ecg in current window
        ecg_filtered_win = ecg_filtered(ii:endi);
        % Morph Var QRS
        disp(['Evaluating QRS MVM for analysis window ' num2str(ceil(ii/(segment_size*minute_duration))) ' starting at time (s) ' num2str(ii/Fs)])
        debug = 0;
        normalize = 1;
        [energyinband_array(ceil(ii/(segment_size*minute_duration))),sqi_array(ceil(ii/(segment_size*minute_duration))),heart_rate_est(ceil(ii/(segment_size*minute_duration)))] = ComputeMVM(ecg_filtered_win,ann_win,Fs,segment_size,normalize);
        % Analysis of current window successful, shift to next segment_size minute window
        ii = ii + segment_size*minute_duration;
    else
        % If arrhythmia detected in any consecutive 60 beats, shift analysis window by 1 minute.
        disp('Detected arrhythmia. shifting analysis window by 1 min.');
        ii = ii + minute_duration;
    end

end


function [p_, sdp_, c_, sdc_, dk_, sdk_, aa_, bb_]=mypval2(var1, mati)

    % clpvla.m                            A.Allmann
    % function to calculate the parameters of the modified Omori Law
    %
    %
    %
    % this function is a modification of a program by Paul Raesenberg
    % that is based on Programs by Carl Kisslinger and Yoshi Ogata
    %
    % function finds the maximum liklihood estimates of p,c and k, the
    % parameters of the modifies Omori equation
    % it also finds the standard deviations of these parameters
    %
    % Input: Earthquake Catalog of an Cluster Sequence
    %
    % Output: p c k values of the modified Omori Law with respective
    %         standard deviations
    %         A and B values of the Gutenberg Relation based on k
    %
    % Create an input window for magnitude thresholds and
    % plot cumulative number versus time to allow input of start and end
    % time

    global backcat ttcat
    global clu1 pyy tmp1 tmp2 tmp3 tmp4 difp
    global xt cumu cumu2
    global p c dk tt pc loop nn pp nit t err1x err2x ieflag isflag
    global cstep pstep tmpcat ts tend eps1 eps2
    global sdc sdk sdp  aa bb pcheck loopcheck
    global autop tmeqtime tmvar
    %if var1 == 3
    tmvar=[];
    %input of parameters(Magnitude,Time)
    ZG.newt2=ttcat;              %function operates with single cluster
    autop=0;
    if var1==4
        autop=1;
    end
    %calculate start -end time of overall catalog
    t0b = min(ZG.newt2.Date);
    teb = max(ZG.newt2.Date);
    tdiff=days(teb-t0b);       %time difference in days

    par3=tdiff/100;

    par5=par3;
    if par5>.5
        par5=par5/5;
    end

    % calculate cumulative number versus time and bin it
    %
    n = ZG.newt2.Count;
    [cumu, xt] = hist(ZG.newt2.Date,(t0b:days(par3):teb));
    [cumu, xt] = hist(days(ZG.newt2.Date-ZG.newt2.Date(1)),(0:par5:tdiff)); %WHY BOTH?
    difp= [0 diff(cumu)];
    cumu2 = cumsum(cumu);

    % find start time of time series
    %
    nn=find(cumu==max(cumu));
    nnn=nn(1,1)-2;
    tmvar=1;           %temperal variable
    if par3>=1
        tmp3=t0b+nnn*days(par3);
    else
        tmp3=nnn*par5;
    end
    tmp3 = mati;
    tmp2=min(ttcat.Magnitude);
    tmp1=max(ttcat.Magnitude);

    tmp3=max(0,tmp3);

    tmp4=teb;

    %%end

    %cumputation part after parameter input
    %elseif var1==8  | var1==6 | var1==7
    %set the error test values
    eps1=.0005;
    eps2=.0005;

    %set the parameter starting values
    PO=1.1;
    CO=0.1;

    %set the initial step size
    pstep=.05;
    cstep=.05;
    pp=PO;
    pc=CO;
    nit=0;
    ieflag=0;
    isflag=0;
    pcheck=false;
    err1x=0;
    err2x=0;
    ts=0.0000001;
    if autop ~= 1             %input was manual

        %Build timecatalog

        mains=find(ttcat.Magnitude == max(ttcat.Magnitude),1);
        mains=ttcat.subset(mains);         %biggest shock in sequence (first one only!)
        assert(mains.Count == 1);
        if par3<0.001
            daycriteria1= ttcat.Date>=days(tmp3)+ttcat.Date(1);
            daycriteria2= ttcat.Date<=days(tmp4)+ttcat.Date(1);
            tmpcat = ttcat.subset(daycriteria1&daycriteria2);
            tmp6=days(tmp3)+ttcat.Date(1);
        else
            tmpcat=ttcat.subset(tmp3<=ttcat.Date & ttcat.Date<=tmp4);
            tmp6=tmp3;
        end
        tmpcat=tmpcat.subset(tmp2<=tmpcat.Magnitude & tmpcat.Magnitude<=tmp1);
        if var1 ==6 || var1==7
            tmpcat=tmpcat.subset(tmpcat.Date>mains.Date);
            tmpcat=[mains; tmpcat];
            ts=(tmp6-mains.Date); %# days
            ts=max(0.0000001,ts)
        end
        tmeqtime=clustime(tmpcat);
        tmeqtime=tmeqtime-tmeqtime(1);     %time in days relative to first eq
        tmeqtime=tmeqtime(2:length(tmeqtime));

        %automatic estimate works with whole sequence
    else
        tmeqtime=clustime(ttcat);
        tmeqtime=tmeqtime-tmeqtime(1);
        tmeqtime=tmeqtime(2:length(tmeqtime));

    end

    tp1 = input('tp1=   ');
    tp2 = input('tp2=    ');
    ts = tp1;
    l = tmeqtime >= tp1 & tmeqtime <= tp2;
    tmeqtime = tmeqtime(l);

    tend=tmeqtime(length(tmeqtime)); %end time

    %Loop begins here
    nn=length(tmeqtime);
    loop=0;
    loopcheck=0;
    tt=tmeqtime(nn)+1;
    t=tmeqtime;
    if pc < 0 ; pc = 0.0; end
    if pc <= ts; pc = ts + 0.05;end

    MIN_CSTEP = 0.000001;
    MIN_PSTEP = 0.00001;

    ploop_c_and_p_calcs(MIN_CSTEP, MIN_PSTEP, true,'kpc'); %call of function who calculates parameters

    if loopcheck<500
        %round values on two digits
        p=round(p, -2);
        sdp=round(sdp, -2);
        c=round(c, -3);
        sdc=round(sdc, -3);
        dk=round(dk, -2);
        sdk= round(sdk, -2);
        aa=round(aa, -2);
        bb=round(bb, -2);

        disp(['p = ' num2str(p)  ' +/- ' num2str(sdp)]);
        disp(['c = ' num2str(c)  ' +/- ' num2str(sdc)]);
        disp(['k = ' num2str(dk)  ' +/- ' num2str(sdk)]);
        disp(['b = ' num2str(bb)  ' +/- ' num2str(sdp)]);
        disp(['a = ' num2str(aa)  ' +/- ' num2str(sdp)]);
    else
        disp('No result');
        %p = nan;
        %c = nan;
        %k = nan;
        %bb = nan;
        %aa = nan;

        % p = nan; sdp = nan;
    end
    if autop~=1
        if par3>=1
            tdiff = round(tmpcat(length(tmpcat(:,1)),3)-tmpcat(1,3));
        else
            tdiff = (tmpcat(length(tmpcat(:,1)),3)-tmpcat(1,3))*365;
        end
        % set arrays to zero
        %
        if par3>=1
            cumu = 0:1:(tdiff/days(par3))+1;
            cumu2 = 0:1:(tdiff/days(par3))-1;
        else
            par5=par3/5;
            cumu = 0:par5:tdiff+2*par3;
            cumu2 =  0:par5:tdiff-1;
        end
        cumu = zeros(size(cumu));
        cumu2 = zeros(size(cumu2));
        %
    end
    tmvar=[];
    %end;

    p_=p;
    sdp_=sdp;
    c_=c;
    sdc_=sdc;
    dk_=dk;
    sdk_=sdk;
    aa_=aa;
    bb_=bb;
end


%-------------------------------------------------------------------------------------------------------------------%
%
% IB2d is an Immersed Boundary Code (IB) for solving fully coupled non-linear
% 	fluid-structure interaction models. This version of the code is based off of
%	Peskin's Immersed Boundary Method Paper in Acta Numerica, 2002.
%
% Author: Nicholas A. Battista
% Email:  nick.battista@unc.edu
% Date Created: May 27th, 2015
% Institution: UNC-CH
%
% This code is capable of creating Lagrangian Structures using:
% 	1. Springs
% 	2. Beams (*torsional springs)
% 	3. Target Points
%	4. Muscle-Model (combined Force-Length-Velocity model, "Hill+(Length-Tension)")
%
% One is able to update those Lagrangian Structure parameters, e.g., spring constants, resting lengths, etc
%
% There are a number of built in Examples, mostly used for teaching purposes.
%
% If you would like us to add a specific muscle model, please let Nick (nick.battista@unc.edu) know.
%
%--------------------------------------------------------------------------------------------------------------------%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FUNCTION: updates the target point positions
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function targets = update_Target_Point_Positions(dt,current_time,targets)

IDs = targets(:,1);                 % Stores Lag-Pt IDs in col vector
%xPts= targets(:,2);                % Original x-Values of x-Target Pts.
yPts= targets(:,3);                 % Original y-Values of y-Target Pts.
%kStiffs = targets(:,4);             % Stores Target Stiffnesses

N_target = length(targets(:,1));    %Gives total number of target pts!

% NEEDED FOR UPDATE FILE FROM CORAL GEOMETRY! %
N_half = 90;                        % # of pts. on ONE tentacle

    %frames per second in data
     F = 30.0;
     %pixels per dm in data
     S = 1733.333333333333333333;
     %time in frames (mod one pulse)
     t =  F*mod(current_time,2.30);
     tp = F*2.25;
     tend = F*2.30;
     %initial offset from center of the domain in dm
     xoffset = 0.019;
     yoffset = 0.25;
     xoffset2grid1 = 0.2;
     xoffset2grid2 = 0.4;

     qc11 = -8.018203211249667e-13;
     qc12 = 1.706310971452060e-10;
     qc13 = -1.371526883228119e-8;
     qc14 = 5.116506115621489e-7;
     qc15 = -8.613944795521634e-6;
     qc16 = 4.951095471423292e-5;
     qc17 = -1.237254488643602e-4;
     qc21 = -1.093988700839764e-10;
     qc22 = 2.370737151797367e-8;
     qc23 = -1.946684756263760e-6;
     qc24 = 7.447999061932255e-5;
     qc25 = -1.285757196003425e-3;
     qc26 = 7.184871148722453e-3;
     qc27 = -2.357284935085283e-2;
     qc31 = -3.111491615328405e-9;
     qc32 = 6.922752279229525e-7;
     qc33 = -5.951659336196739e-5;
     qc34 = 2.461541908755476e-3;
     qc35 = -4.830999119980220e-2;
     qc36 = 3.293063238297988e-1;
     qc37 = -1.893567487439901;
     qc41 = 2.028150369106308e-8;
     qc42 = -4.188949936239104e-6;
     qc43 = 3.237380275082298e-4;
     qc44 = -1.158763275070524e-2;
     qc45 = 1.908244836752949e-1;
     qc46 = -1.142372536532416;
     qc47 = 3.584246435337805;

    if (t<=tp)

        qpoly1=qc17+qc16*t+qc15*t*t+qc14*t*t*t+qc13*t*t*t*t+qc12*t*t*t*t*t+qc11*t*t*t*t*t*t;
        qpoly2=qc27+qc26*t+qc25*t*t+qc24*t*t*t+qc23*t*t*t*t+qc22*t*t*t*t*t+qc21*t*t*t*t*t*t;
        qpoly3=qc37+qc36*t+qc35*t*t+qc34*t*t*t+qc33*t*t*t*t+qc32*t*t*t*t*t+qc31*t*t*t*t*t*t;
        qpoly4=qc47+qc46*t+qc45*t*t+qc44*t*t*t+qc43*t*t*t*t+qc42*t*t*t*t*t+qc41*t*t*t*t*t*t;

    else
        qpolytf1=qc17+qc16*tp+qc15*tp*tp+qc14*tp*tp*tp+qc13*tp*tp*tp*tp+qc12*tp*tp*tp*tp*tp+qc11*tp*tp*tp*tp*tp*tp;
        qpolytf2=qc27+qc26*tp+qc25*tp*tp+qc24*tp*tp*tp+qc23*tp*tp*tp*tp+qc22*tp*tp*tp*tp*tp+qc21*tp*tp*tp*tp*tp*tp;
        qpolytf3=qc37+qc36*tp+qc35*tp*tp+qc34*tp*tp*tp+qc33*tp*tp*tp*tp+qc32*tp*tp*tp*tp*tp+qc31*tp*tp*tp*tp*tp*tp;
        qpolytf4=qc47+qc46*tp+qc45*tp*tp+qc44*tp*tp*tp+qc43*tp*tp*tp*tp+qc42*tp*tp*tp*tp*tp+qc41*tp*tp*tp*tp*tp*tp;

        qpoly1 = qpolytf1*((tend-tp)-(t-tp))/(tend-tp)+qc17*(t-tp)/(tend-tp);
        qpoly2 = qpolytf2*((tend-tp)-(t-tp))/(tend-tp)+qc27*(t-tp)/(tend-tp);
        qpoly3 = qpolytf3*((tend-tp)-(t-tp))/(tend-tp)+qc37*(t-tp)/(tend-tp);
        qpoly4 = qpolytf4*((tend-tp)-(t-tp))/(tend-tp)+qc47*(t-tp)/(tend-tp);
    end

for i=1:N_target                    % Loops over all target points!

    shifted_Xt1 = yPts(i)-yoffset;

    X_target = xoffset+qpoly4/S-qpoly3*shifted_Xt1+qpoly2*S*shifted_Xt1*shifted_Xt1-qpoly1*S*S*shifted_Xt1*shifted_Xt1*shifted_Xt1;

    if i<= N_target/2
        if i<=N_half
            X_target = -X_target+ xoffset2grid1;
        else
            X_target = X_target + xoffset2grid1;
        end
    else
        if i<=N_target/2+N_half
            X_target = -X_target+ xoffset2grid2;
        else
            X_target = X_target + xoffset2grid2;
        end
    end
    targets(IDs(i),2) = X_target;      % Store new xVals
    %targets(IDs(i),3) = yPts(IDs(i)); % Store new yVals

end


function envihdrwrite(filename,dims,datatype,resolu,UL,interleave,zone)
%  write envi format file of unit8 and int16
%  for example: enviwrite('testzz',data,'int16',[30,30],jiUL,'bsq',ZC,'this is for test only');
%  i,j => x, y => rows and cols
%  Input  1)  'filename' is the name of the file
%  Input  2)  'dims' is the dimenstion of the image (rows,cols,bands)
%  Input  3)  'dataype' is the datatype to write 'unit8' or 'int16'
%  Input  4)  'resolu' is the resolution of the pixel
%  Input  5)  'UL' is the UpperLeftPoint X Y of the UL pixel (not center of UL pixel)
%  Input  6)  'interleave' is the bsq bip bil format
%  Input  7)  'zone' is the UTM zone

% if strcmp(datatype,'uint8')
% %     envi_data=uint8(envi_data);
%     dt=1;
% elseif strcmp(datatype,'int16')
% %     envi_data=int16(envi_data);
%     dt=2;
% elseif strcmp(datatype,'uint16')
% %     envi_data=uint16(envi_data);
%     dt=12;
% else
%     fprintf('Invalid write data type!\n');
%     return;
% end

if strcmp(datatype,'uint8')
%    envi_data=uint8(envi_data);
    dt=1;
elseif strcmp(datatype,'int16')
%    envi_data=int16(envi_data);
    dt=2;
elseif strcmp(datatype,'int32')
%    envi_data=int32(envi_data);
    dt=3;
elseif strcmp(datatype,'uint16')
%    envi_data=uint16(envi_data);
    dt=12;
elseif strcmp(datatype,'single')
%    envi_data=single(envi_data);
    dt=4;
else
    fprintf('Invalid write data type!\n');
    return;
end

% n_dims=size(envi_data);

nrows=dims(1);
ncols=dims(2);
bands=1;

if length(dims)==3
    bands=dims(3);
end

% multibandwrite(envi_data,filename,interleave);

filename_hdr=[filename,'.hdr'];

fid_out=fopen(filename_hdr,'wt');

fprintf(fid_out,'ENVI\n');
fprintf(fid_out,'description = {Landsat Scientific Data}\n');
fprintf(fid_out,'samples = %d\n',ncols); % samples is for j
fprintf(fid_out,'lines   = %d\n',nrows); % lines is for i
fprintf(fid_out,'bands   = %d\n',bands);
fprintf(fid_out,'header offset = 0\n');
fprintf(fid_out,'file type = ENVI Standard\n');
fprintf(fid_out,'data type = %d\n',dt);
fprintf(fid_out,'interleave = %s\n',interleave);
fprintf(fid_out,'sensor type = Landsat\n');
fprintf(fid_out,'byte order = 0\n');

if isempty(zone)
    %label as Landsat ARD
    fprintf(fid_out, 'map info = {Albers Conical Equal Area, 1, 1, %d, %d, %d, %d, WGS-84}\n',UL(1),UL(2),resolu(1),resolu(2));
    fprintf(fid_out, 'projection info = {9, 6378140, 6356755.288157528, 23, -96, 0, 0, 29.5, 45.5,WGS-84, Albers Conical Equal Area}\n');
    fprintf(fid_out, 'coordinate system string = {PROJCS["WGS_1984_Albers",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378140.0,298.257]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Albers"],PARAMETER["false_easting",0.0],PARAMETER["false_northing",0.0],PARAMETER["central_meridian",-96.0],PARAMETER["standard_parallel_1",29.5],PARAMETER["standard_parallel_2",45.5],PARAMETER["latitude_of_origin",23.0],UNIT["Meter",1.0]]}');
else
    if (zone > 0)
        fprintf(fid_out, 'map info = {UTM, 1.000, 1.000, %d, %d, %d, %d, %d, North, WGS-84, units=Meters}',UL(1),UL(2),resolu(1),resolu(2),zone);
    else
        fprintf(fid_out, 'map info = {UTM, 1.000, 1.000, %d, %d, %d, %d, %d, South, WGS-84, units=Meters}',UL(1),UL(2),resolu(1),resolu(2),-zone);
    end
end

fclose(fid_out);
end


%%*******************************************************************
%% schurmat_sblk: compute Schur complement matrix corresponding to
%%                SDP blocks.
%%
%% symm = 0, HKM
%%      = 1, NT
%%*****************************************************************
%% SDPT3: version 4.0
%% Copyright (c) 1997 by
%% Kim-Chuan Toh, Michael J. Todd, Reha H. Tutuncu
%% Last Modified: 16 Sep 2004
%%*****************************************************************

   function schur = schurmat_sblk(blk,At,par,schur,p,X,Y);

   global  nnzschur nzlistschur

   iter = par.iter;
   smallblkdim = par.smallblkdim;

   if isempty(smallblkdim); smallblkdim = 50; end
   if (nargin == 7); symm = 0; else; symm = 1; Y = X; end;
   m = length(schur);
   pblk = blk(p,:);
   if (iter == 1)
      nnzschur(size(blk,1),1) = m*m;
      nzlistschur = cell(size(blk,1),1);
   end
%%
   if (max(pblk{2}) > smallblkdim) | (length(pblk{2}) <= 10)
      %%
      %% compute schur for matrices that are very sparse.
      %%
      m1 = size(At{p,1},2);
      if issparse(schur); schur = full(schur); end;
      J = min(m1, max(find(par.nzlistA{p,1} < inf))-1);
      if (J > 0)
         if issparse(X{p}) & ~issparse(Y{p}); X{p} = full(X{p}); end
         if ~issparse(X{p}) & issparse(Y{p}); Y{p} = full(Y{p}); end
         if (iter <= 3)
            [nnzschur(p),nzlisttmp] = mexschur(pblk,At{p,1},par.nzlistA{p,1},...
            par.nzlistA{p,2},par.permA(p,:),Y{p},X{p},J,symm,schur);
            if (nnzschur(p) == mexnnz(nzlisttmp))
               nzlistschur{p} = nzlisttmp;
            else
               nzlistschur{p} = [];
            end
         else
            if isempty(nzlistschur{p})
               mexschur(pblk,At{p,1},par.nzlistA{p,1},...
               par.nzlistA{p,2},par.permA(p,:),Y{p},X{p},J,symm,schur);
            else
               mexschur(pblk,At{p,1},par.nzlistA{p,1},...
               par.nzlistA{p,2},par.permA(p,:),Y{p},X{p},J,symm,schur,nzlistschur{p});
            end
         end
      end
      %%
      %% compute schur for matrices that are not so sparse or dense.
      %%
      if (m1 < m) %% for low rank constraints
         ss = [0, cumsum(pblk{3})];
         len = sum(pblk{3});
         dd = At{p,3};
         DD = spconvert([dd(:,2:4); len,len,0]);
         XVD = X{p}*At{p,2}*DD;
         YVD = Y{p}*At{p,2}*DD;
      end
      L = max(find(par.nzlistAsum{p,1} < inf)) -1;
      if (J < L)
         len = par.nzlistAsum{p,1}(J+1); list = par.nzlistAsum{p,2}(1:len,:);
      end
      if (m1 > 0)
         for k = J+1:m
            if (k<=m1)
               isspAk = par.isspA(p,k);
               Ak = mexsmat(blk,At,isspAk,p,k);
               if (k <= L)
                  idx1 = par.nzlistAsum{p,1}(k)+1; idx2 = par.nzlistAsum{p,1}(k+1);
                  list = [list; par.nzlistAsum{p,2}(idx1:idx2,:)];
                  list = sortrows(list,[2 1]);
                  tmp = Prod3(pblk,X{p},Ak,Y{p},symm,list);
               else
                  tmp = Prod3(pblk,X{p},Ak,Y{p},symm);
               end
            else %%--- for low rank constraints
               idx = [ss(k-m1)+1 :ss(k-m1+1)];
               tmp = XVD(:,idx)* (Y{p}*At{p,2}(:,idx))';
            end
            if (~symm)
               tmp = 0.5*(mexsvec(pblk,tmp) + mexsvec(pblk,tmp'));
            else
               tmp = mexsvec(pblk,tmp);
            end
            permk = par.permA(p,k);
            idx  = par.permA(p,1:min(k,m1));
            tmp2 = schur(idx,permk) + mexinprod(blk,At,tmp,min(k,m1),p);
            schur(idx,permk) = tmp2;
            schur(permk,idx) = tmp2';
         end
      end
      if (m1 < m) %% for low rank constraints
         m2 = m - m1;
         XVtmp = XVD'*At{p,2};
         YVtmp = At{p,2}'*YVD;
         for k = 1:m2
            idx0 = [ss(k)+1 : ss(k+1)];
            tmp = XVtmp(:,idx0) .* YVtmp(:,idx0);
            tmp = tmp*ones(length(idx0),1);
            tmp3 = schur(m1+[1:m2],m1+k) + mexqops(pblk{3},tmp,ones(length(tmp),1),1);
            schur(m1+[1:m2],m1+k) = tmp3;
         end
      end
   else
      %%--- for SDP block where each sub-block is small dimensional
      if issparse(X{p}) & ~issparse(Y{p}); Y{p} = sparse(Y{p}); end
      if ~issparse(X{p}) & issparse(Y{p}); X{p} = sparse(X{p}); end
      tmp = mexskron(pblk,X{p},Y{p});
      schurtmp = At{p,1}'*tmp*At{p,1};
      %% schurtmp = 0.5*(schurtmp + schurtmp');
      if (norm(par.permA(p,:)-[1:m]) > 0)
         Perm = spconvert([(1:m)', par.permA(p,:)', ones(m,1)]);
         schur = schur + Perm'*schurtmp*Perm;
      else
         schur = schur + schurtmp;
      end
   end
%%*******************************************************************


function xs = searchGauss(x,gpstruct,LB,UB,optimState,options)
%SEARCHGAUSS Multivariate normal random search.

if nargin == 0
    xs = 'gauss';
    return;
end

MeshSize = optimState.meshsize;
SearchFactor = optimState.searchfactor;

nvars = length(x);

% Diagonal covariance matrix for random search
sigma = 0.5*MeshSize*SearchFactor*eye(nvars);

% Random draw from multivariate normal
xs = bsxfun(@plus, x, randn(options.Nsearch,nvars)*sigma);

end


function [estBias, estVar] = testSpSegmentationEstimator(imsegs, spdata, maps)

% UNFINISHED
[data, lab] = formatData(spdata, {imsegs(:).labels});

vconf = test_boosted_dt_mc(vclassifier, data);
vconf = 1 ./ (1+exp(-vconf));
vconf = vconf ./ repmat(sum(vconf, 2), 1, size(vconf, 2));

hconf = test_boosted_dt_mc(hclassifier, data);
hconf = 1 ./ (1+exp(-hconf));
hconf = hconf ./ repmat(sum(hconf, 2), 1, size(hconf, 2));

spEst = [vconf(:, 1) repmat(vconf(:, 2), 1, 5).*hconf2 vconf(:, 3)];
spTrue = lab;

nmaps = 0;
for f = 1:numel(maps)
    nmaps = nmaps + numel(maps{f});
end

pEst = zeros(nmaps, 1);
pTrue = zeros(nmaps, 1);
%
% True = zeros(size(valEst));
% for i = 1:numel(lab)
%     for k =
%
% spvlabels = {imsegs(:).vert_labels};
% sphlabels = {imsegs(:).horz_labels};
%
% % test vertical
% [vdata, vlab] = formatData(spfeatures, spvlabels);
% vconf = test_boosted_dt_mc(vclassifier, vdata);
% vconf = 1 ./ (1+exp(-vconf));
% vconf = vconf ./ repmat(sum(vconf, 2), 1, size(vconf, 2));
% [tmp, vmax] = max(vconf, [], 2);
% verror = mean(vmax~=vlab)
%
% vconferr = 0;
% for k = 1:numel(vlab)
%     vconferr = vconferr + 1 - vconf(k, vlab(k));
% end
% vconferr = vconferr / numel(vlab)
%
% % test subclass
% [hdata, hlab] = formatData(spfeatures, sphlabels);
% hconf = test_boosted_dt_mc(hclassifier, hdata);
% hconf = 1 ./ (1+exp(-hconf));
% hconf = hconf ./ repmat(sum(hconf, 2), 1, size(hconf, 2));
% [tmp, hmax] = max(hconf, [], 2);
% herror = mean(hmax~=hlab)
%
% hconferr = 0;
% for k = 1:numel(hlab)
%     hconferr = hconferr + 1 - hconf(k, hlab(k));
% end
% hconferr = hconferr / numel(hlab)
%
% % get same_label error
% %[serror, sconferr] = sameLabelError(spfeatures, spvlabels, sphlabels, ...
% %    {imsegs(:).adjmat}, vclassifier, hclassifier)
%
% errors.verr = verror;
% errors.vcerr = vconferr;
% errors.herr = herror;
% errors.hcerr = hconferr;
% %errors.serr = serror;
% %errors.scerr = sconferr;
%
% [hdata2, hlab2] = formatData(spfeatures, spvlabels);
% hconf2 = test_boosted_dt_mc(hclassifier, hdata2);
% hconf2 = 1 ./ (1+exp(-hconf2));
% hconf2 = hconf2 ./ repmat(sum(hconf2, 2), 1, size(hconf2, 2));
%
% lab = (vlab==1)*1 + (vlab==2)*(hlab2+1) + (vlab==3)*7;
% pEst = [vconf(:, 1) repmat(vconf(:, 2), 1, 5).*hconf2 vconf(:, 3)];
% pTrue = repmat((1:7), numel(lab), 1).*repmat(lab, 1, 7);
%
% size(pEst)
% size(pTrue)
%
% [pMean, pVal, estBias] = evaluateProbabilityEstimate(pEst(:), pTrue(:), 0.05)
% pErrors.pMean = pMean;
% pErrors.pVal = pVal;
% pErrors.estBias = estBias;
%
%
%

%
%
%
% pVal = [step/2:step:(1-step/2)];
%
% nsteps = numel(pVal);
%
% estBias = 0;
%
% for v = 1:numel(pVal)
%     v1 = pVal(v)-step/2;
%     v2 = min(v1+step, 1);
%
%     ind = find((pEst >= v1) & (pEst <= v2));
%
%     pMean(v) = mean(pTrue(ind));
%     estBias = estBias + numel(ind)/numel(pEst)*(pMean(v)-pVal(v));
% end


clear;clc;
% caffe.set_mode_cpu();
caffe.set_mode_gpu();
caffe.set_device(0);
caffe.reset_all();

addpath('./evaluation_func/');
addpath('./evaluation_func/matlabPyrTools-master/');

% model = 'IDN_x2_deploy.prototxt';
% model = 'IDN_x4_deploy.prototxt';
model = 'IDN_x3_deploy.prototxt';

% weights = 'caffemodel/IDN_x2.caffemodel';
% weights = 'caffemodel/IDN_x4.caffemodel';
weights = 'caffemodel/IDN_x3.caffemodel';
%weights = 'caffemodel/IDN_x4_mscoco.caffemodel';
net=caffe.Net(model,weights,'test');
test_dataset='Set5'; % Set5 | Set14 | B100 | Urban100

testfolder=['test_data/' test_dataset '/'];
up_scale=3; % 2 | 3 | 4

savepath = 'results/';
folderResultCur = fullfile(savepath,[test_dataset,'_x',num2str(up_scale)]);
if ~exist(folderResultCur,'file')
    mkdir(folderResultCur);
end

if strcmp(test_dataset,'Set5') || strcmp(test_dataset,'Set14')
    filepaths=dir(fullfile(testfolder,'*.bmp'));
else
    filepaths=dir(fullfile(testfolder,'*.jpg'));
end

psnr_bic=zeros(length(filepaths),1);
psnr_idn=zeros(length(filepaths),1);

ssim_bic=zeros(length(filepaths),1);
ssim_idn=zeros(length(filepaths),1);

ifc_bic=zeros(length(filepaths),1);
ifc_idn=zeros(length(filepaths),1);

time_idn=zeros(length(filepaths),1);

for i=1:length(filepaths)
    %% read groud truth image
    [add,imname,type]=fileparts(filepaths(i).name);
    im=imread([testfolder imname type]);
    dimension=size(im,3);
    %% work on illuminance only
    if size(im,3)>1
        im_ycbcr=rgb2ycbcr(im);
        im=im_ycbcr(:,:,1);
        im_cb=im_ycbcr(:,:,2);
        im_cr=im_ycbcr(:,:,3);
        im_cb=modcrop(im_cb,up_scale);
        im_cr=modcrop(im_cr,up_scale);
        im_cb_=shave(imresize(imresize(im_cb,1/up_scale,'bicubic'),up_scale,'bicubic'),[up_scale,up_scale]);
        im_cr_=shave(imresize(imresize(im_cr,1/up_scale,'bicubic'),up_scale,'bicubic'),[up_scale,up_scale]);
    end
    im_gnd=modcrop(im,up_scale);
    im_gnd=single(im_gnd)/255;
    im_l=imresize(im_gnd,1/up_scale,'bicubic');

    %% bicubic interpolation
    im_b=imresize(im_l,up_scale,'bicubic');

    %% IDN feed-forward
    tic
    im_input=permute(im_l,[2,1,3]);
    net.blobs('data').reshape([size(im_input),1,1]);
    net.reshape();
    net.blobs('data').set_data(im_input);
    net.forward_prefilled();
    im_result=net.blobs('upsample').get_data();

    im_h=im_result'+mycrop(im_b,up_scale);
    time_idn(i)=toc;

    %% remove border
    im_h=myshave(uint8(im_h*255),up_scale);
    im_gnd=shave(uint8(im_gnd*255),[up_scale,up_scale]);
    im_b=shave(uint8(im_b*255),[up_scale,up_scale]);

    %% compute PSNR
    psnr_bic(i)=compute_psnr(im_gnd,im_b);
    psnr_idn(i)=compute_psnr(im_gnd,im_h);

    %% compute SSIM
    ssim_bic(i)=ssim_index(im_gnd,im_b);
    ssim_idn(i)=ssim_index(im_gnd,im_h);

    %% compute IFC

    ifc_idn(i) = ifcvec(double(im_gnd),double(im_h));
    ifc_bic(i)=ifcvec(double(im_gnd),double(im_b));

    %% save results
    if dimension>1
        imwrite(ycbcr2rgb(cat(3,im_h,im_cb_,im_cr_)),fullfile(folderResultCur,[imname,'_x',num2str(up_scale),'.png']));
    else
        imwrite(im_h,fullfile(folderResultCur,[imname,'_x',num2str(up_scale),'.png']));
    end
    save(fullfile(folderResultCur,['PSNR_',test_dataset,'_x',num2str(up_scale),'.mat']),'psnr_idn');
    save(fullfile(folderResultCur,['SSIM_',test_dataset,'_x',num2str(up_scale),'.mat']),'ssim_idn');
    save(fullfile(folderResultCur,['IFC_', test_dataset,'_x',num2str(up_scale),'.mat']),'ifc_idn');
end

fprintf('Mean PSNR for Bicubic: %f dB\n', mean(psnr_bic));
fprintf('Mean PSNR for IDN: %f dB\n', mean(psnr_idn));

fprintf('Mean SSIM for Bicubic: %f \n', mean(ssim_bic));
fprintf('Mean SSIM for IDN: %f \n', mean(ssim_idn));

fprintf('Mean IFC for Bicubic: %f \n', mean(ifc_bic));
fprintf('Mean IFC for IDN: %f \n', mean(ifc_idn));

fprintf('Mean Time for IDN: %f \n', mean(time_idn));


function mrVistaData = dtiXformGetMrVistaDataForFibers(handles, view, scanNum, fgNum)
%
% mrVistaData = dtiXformGetMrVistaDataForFibers(handles, [view], [scanNum], [fgNum])
%
% Uses the xformVAnatToAcpc (see dtiXformVanatCompute) to convert the specified
% fiber group to mrVista vAnatomy coords and pulls data from the selected
% gray view. Note that only fiber end-points are used, and they are
% projected to the nearest gray-matter coord.
%
% HISTORY:
% 2005.07.28 RFD (bob@white.stanford.edu) wrote it.

if(~exist('view','var') | isempty(view))
    view = getSelectedGray;
end
if(~exist('scanNum','var') | isempty(scanNum))
    scanNum = getCurScan(view);
end
if(~exist('fgNum','var') | isempty(fgNum))
    fgNum = handles.curFiberGroup;
end

% This is in vAnatomy voxels. We should probably scale by mmPerVox.
distThresh = 3;

fg = handles.fiberGroups(fgNum);

% Select only layer 1 for the grayCoords.
grayCoords = view.coords(:,view.nodes(6,:)==1);

distSqThresh = distThresh.^2;
fibNum = 0;
allCoords = [];
requireBothEnds = 1;

% We are only grabbing data for fiber endpoints, so we need num fibers * 2.
% We will apply a 4x4 xform, so we need homogeneous coords (nx4).
coords = zeros(length(fg.fibers)*2, 3);
for(ii=1:length(fg.fibers))
    % Get coords for fiber endpoints (first and last point)
    coords((ii-1)*2+1,:) = fg.fibers{ii}(:,1)';
    coords((ii-1)*2+2,:) = fg.fibers{ii}(:,end)';
end
coords = mrAnatXformCoords(inv(handles.xformVAnatToAcpc), coords);

% Now project endpoint coords to nearest gray matter coord
[indices, bestSqDist] = nearpoints(coords', grayCoords);
tooFarInds = bestSqDist>distSqThresh;
if(requireBothEnds)
    % Sometimes we want to delete fibers that have only one endpoint close
    % enough to the gray matter (eg. if we want to test connectivity).
    notBoth = tooFarInds(1:2:end)|tooFarInds(2:2:end);
    tooFarInds = repmat(notBoth,2,1);
    tooFarInds = tooFarInds(:)';
end
indices(tooFarInds) = [];

%mrVistaData.coords = grayCoords(:,indices);

mrVistaData.co = getCurDataROI(view,'co',scanNum,grayCoords(:,indices));
noData = isnan(mrVistaData.co);
mrVistaData.ph = getCurDataROI(view,'ph',scanNum,grayCoords(:,indices));
mrVistaData.amp = getCurDataROI(view,'amp',scanNum,grayCoords(:,indices));
mrVistaData.co(noData) = [];
mrVistaData.ph(noData) = [];
mrVistaData.amp(noData) = [];
if(~isempty(view.map) && ~isempty(view.map{scanNum}))
    mrVistaData.map = view.map{curScan}(indices);
    mrVistaData.map(noData) = [];
else
    mrVistaData.map = [];
end
mrVistaData.grayInds = indices(~noData);

fibNum = length(indices);

disp([num2str(fibNum) ' fibers had endpoints within ' num2str(sqrt(distSqThresh)) ' units of gray coords.']);
return;


clear; clc; close all; warning off;
addpath(genpath('./.'));
addpath(genpath('/home/./caffe/')) ;
caffe.set_mode_gpu();
caffe.set_device(0);

scale      = 4;
ext        =  {'*.JPG','*.png','*.bmp', '*.tif'};
CameraType = {'Canon', 'Nikon'};
folder     = './.';
filepaths  = dir(fullfile(folder, '*.caffemodel'));
weights = fullfile(folder,filepaths.name);
model = '*.prototxt';
net = caffe.Net(model, weights,'test');

count = 1;
for q = 1:2
    folder2   =  ['Test/', CameraType{q}, '/', num2str(scale)];
    filepaths2 =  [];
    for p = 1 : length(ext)
        filepaths2 = cat(1,filepaths2, dir(fullfile(folder2, ext{p})));
    end
    for i = 1 : 2: length(filepaths2)
        disp(i)
        HR = imread(fullfile(folder2,filepaths2(i).name));
        HR = modcrop(HR, 4);
        HR_Ycbcr = im2double(rgb2ycbcr(HR));
        HR_Y = im2single(HR_Ycbcr(:, :, 1));

        LR = imread(fullfile(folder2,filepaths2(i+1).name));
        LR = modcrop(LR, 4);
        LR_Ycbcr = im2double(rgb2ycbcr(LR));
        LR_Y = im2single(LR_Ycbcr(:, :, 1));

        % The testing image is too large and will cause out-of-memory issue.
        size_img = size(LR_Y);
        if ((size_img(1) > 1200) && (size_img(2) > 1200))
            size_patch = [1200 1200];
            size_skip = [800 800];
            [patch] = im2patch(LR_Y, size_patch, size_skip);
            [patchY] = im2patch(HR_Y, size_patch, size_skip);
        else
            patch = LR_Y;
            patchY = HR_Y;
        end

        for k = 1:size(patch,3)
            net.blobs('data').reshape([size(patch(:,:,k),1) size(patch(:,:,k),2), 1, 1]);
            net.reshape();
            res = net.forward({patch(:,:,k)});
            result = res{1};

            [PSNRCur, SSIMCur] = Cal_PSNRSSIM(im2uint8(patchY(:,:,k)),im2uint8(result),0,0);
            PSNRs(count) = PSNRCur;
            SSIMs(count) = SSIMCur;
            count = count + 1;
        end
    end
end
mean(PSNRs)
mean(SSIMs)
caffe.reset_all()


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

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

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

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


function out = isreal(f)
%ISREAL   Test if a CHEBFUN2V object F is real-valued.
%   ISREAL(F) returns logical true if F does not have any nonzero imaginary
%   part and false otherwise.
%
%   (This is slightly different from the Matlab convention, where isreal(x)
%   is false if x is a complex number whose imaginary part is 0.)
%
% See also CHEBFUN/ISREAL, CHEBFUN2/ISREAL, and CHEBFUN3/ISREAL.

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

if ( isempty(f) )
    out = true;
    return
end

for ii = 1:f.nComponents
    out(ii) = isreal(f.components{ii});
end
out = all(out);

end


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

% Pick a random point from a bounded range.
% Parameters:
%     n; dimensionality of the search-space.
%     x; center position of the sampling-range.
%     range; desired sampling-range.
%     lowerBound; search-space lower-boundary.
%     upperBound; search-space upper-boundary.
% Returns:
%     fitness; the measure to be minimized.
function y = samplebounded(n, x, range, lowerBound, upperBound)

    % Adjust sampling range so it does not exceed bounds.
    l = max(x - range, lowerBound);
    u = min(x + range, upperBound);

    % Pick a sample from within the bounded range.
    y = initagent(n, l, u);
end

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


function [A,twt]=loadrd3(fname,varargin)
% loads an rd3 file... (requires the .rad file to be present)
% syntax: [A,twt]=loadrd3('prof4',[starttrace],[tracecount],[options])
%
% options: 'stack'... return the mean of the profile
%
% Aslak Grinsted 2002
%

% load details from .RAD file

fname=strrep(lower(fname),'.rd3','');

numargcount=size(varargin,2);
tracecount=inf;
starttrace=1;
stack=0;

l=1;
numargcount=size(varargin,2); %how many numeric arguments are there before the settings?
while (l<=size(varargin,2))
   a=varargin{l};
   if ischar(a)
      v=[];
      if (l<numargcount), numargcount=l-1; end
      %if ((l+1)<=size(varargin,2)), v=varargin{l+1}; end
      switch lower(a)
      case {'stack','s'}
          stack=1;
      end
   end
   l=l+1;
end
switch numargcount
case 2
    starttrace=varargin{1};
    tracecount=varargin{2};
end

infos=rd3info(fname,'scans','samples','timewindow');
sz=infos{2};
timewindow=infos{3};

twt=((1:sz)'-1)*timewindow*1e-9/sz;

%loads the rd3 file
fid=fopen([fname '.rd3'],'r');
if (starttrace>1)
   fseek(fid,(starttrace-1)*sz*2,0);
end

if (stack==0)
    A=fread(fid,[sz tracecount],'short');
else
    blocksize=1+fix(1000000/sz); %number of traces to read at a time...

    A=zeros(sz,1);
    tracesread=0;
    while ((~feof(fid))&(tracesread<tracecount))
        B=fread(fid,[sz blocksize],'short');
        A=A+sum(B,2);
        tracesread=tracesread+size(B,2);
    end
    A=A/tracesread;
end
fclose(fid);
%A=reshape(A,sz,size(A,1)/sz);


function elemType = updatetype(elemType,brother)
%% UPDATETYPE update the type of triangles.
%
% Copyright (C) Long Chen. See COPYRIGHT.txt for details.

if (size(brother,1)==0), return; end
oldNT = length(elemType);
newNT = max(brother(:,2)); % brother(t,1) < brother(t,2)
if oldNT < newNT % coarse grid to fine grid
    elemType(newNT) = 0;
    firstBrother = zeros(oldNT,1,'uint32');
    idx = (brother(:,1) <= oldNT);
    t = brother(idx,1);
    tt = brother(idx,2);
    firstBrother(t(end:-1:1)) = tt(end:-1:1);
    % update first bisected elements from 1:oldNT first
    elemType(firstBrother(t)) = ~elemType(t);
    elemType(t) = ~elemType(t);
    % updated second bisected elements
    idx = (brother(:,2) > (oldNT + length(find(firstBrother))));
    elemType(brother(idx,2)) = ~elemType(brother(idx,1));
    elemType(brother(idx,1)) = elemType(brother(idx,2));
else % fine grid to coarse grid
    elemType(brother(:,1)) = ~elemType(brother(:,1));
    elemType(brother(:,2)) = [];
end


function [rtk,stat]=pppos(rtk,obs,nav)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%% precise point positioning %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%input:  rtk - rtk control struct
%        obs - observations
%        nav - navigation message
%output: rtk - rtk control struct
%        stat - state (0:error 1:ok)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

global glc
nobs=size(obs,1); MAXITER=8; iter=1; stat=0;
exc=zeros(nobs,1); dr=zeros(3,1);

% initialize rtk.sat.fix
for i=1:glc.MAXSAT
    for j=1:rtk.opt.nf
        rtk.sat(i).fix(j)=0;
    end
end

% debug tracing
% fprintf('\n \n \n');
% fprintf('time= %d',obs(1).time.time);fprintf('\n');
% fprintf('before time update');
% printx_ppp(rtk.x,rtk);
% printP(rtk.P,rtk);

% time update
rtk=udstate_ppp(rtk,obs,nav);

% debug tracing
% fprintf('after time update');
% printx_ppp(rtk.x,rtk);
% printP(rtk.P,rtk);

% cumpute satellite position,clock bias,velocity,clock drift
sv=satposs(obs,nav,rtk.opt.sateph);

% exclude measurements of eclipsing satellite (block IIA)
if rtk.opt.posopt(4)==1
    sv=testeclipse(obs,nav,sv);
end

% compute earth tides correction
if rtk.opt.tidecorr==1
    dr=tidedisp(gpst2utc(obs(1).time),rtk.sol.pos,7,nav.erp,nav.otlp);
end

while iter<=MAXITER

    % calculate residuals,measurement matrix,measurement noise matrix
    [v,H,R,~,exc,nv,rtk]=ppp_res(0,rtk.x,rtk,obs,nav,sv,dr,exc);
    if nv==0,break;end

    % debug tracing
%     printv(v);
%     printH(H);
%     printR(R);

    % measurement update
    [X,P,stat_tmp]=Kfilter_h(v,H,R,rtk.x,rtk.P);
    if stat_tmp==0
        [week,sow]=time2gpst(obs(1).time);
        fprintf('Warning:GPS week = %d sow = %.3f,filter error!\n',week,sow);
        stat=0;break;
    end

    % debug tracing
%     fprintf('after measurement update');
%     printx_ppp(X,rtk);
%     printP(P,rtk);

    % calculate posteriori residuals,validate the solution
    [~,~,~,~,exc,stat,rtk]=ppp_res(iter,X,rtk,obs,nav,sv,dr,exc);
    iter=iter+1;

    if stat==1
        rtk.x=X; rtk.P=P;
        break;
    end

end

if iter>MAXITER
    [week,sow]=time2gpst(obs(1).time);
    fprintf('Warning:GPS week=%d sow=%.3f, ppp iteration overflows',week,sow);
end

if stat==1
    % PPP ambiguity resolution (Not supported for the time being)

    % update solution
    rtk=update_stat(rtk,obs,glc.SOLQ_PPP);

    % hold fixed ambiguity (Not supported for the time being)

end

return


function fem2d_pack_test03 ( )

%*****************************************************************************80
%
%% TEST03 tests the BASIS_11_**_TEST routines.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    12 March 2009
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST03\n' );
  fprintf ( 1, '  BASIS_11_T3_TEST tests BASIS_11_T3.\n' );
  fprintf ( 1, '  BASIS_11_T4_TEST tests BASIS_11_T4.\n' );
  fprintf ( 1, '  BASIS_11_T6_TEST tests BASIS_11_T6.\n' );

  basis_11_t3_test ( );

  basis_11_t4_test ( );

  basis_11_t6_test ( );

  return
end


%%% data randomization

function [data_out] = randomizer(data_in)
D=length(data_in);
State=[1 0 0 1 0 1 0 1 0 0 0 0 0 0 0];

for k=1:D
    fdB=bitxor(State(14),State(15));
    State=[fdB State(1:end-1)];
    data_out(k,1)=bitxor(data_in(k,1),fdB);
 end


%%%%%%define your parameters here
%{
%%mnist mlp
opts.dataset_name='mnist';
network_name='cnn'; %network name
use_gpu=1; %use gpu or not
PrepareDataFunc=@PrepareData_MNIST_MLP;
NetInit=@net_init_mlp_mnist;
use_selective_sgd=1;
ssgd_search_freq=10;
learning_method=@sgd; %training method: @sgd,@adagrad,@rmsprop,@adam
sgd_lr=1e-2;
opts.n_epoch=20;
opts.LoadResults=0;
%}

%{
n_epoch=20; %training epochs
dataset_name='mnist'; %dataset name
network_name='cnn'; %network name
use_gpu=1; %use gpu or not

%function handle to prepare your data
PrepareDataFunc=@PrepareData_MNIST_CNN;
%function handle to initialize the network
NetInit=@net_init_cnn_mnist;

%automatically select learning rates
use_selective_sgd=1;
%select a new learning rate every n epochs
ssgd_search_freq=10;
learning_method=@sgd; %training method: @sgd,@adagrad,@rmsprop,@adam

%sgd parameter
%(unnecessary if selective-sgd is used)
%sgd_lr=5e-2;
%}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%% end

%opts=[];
%addpath('./CoreModules');
opts.n_epoch=n_epoch; %training epochs
opts.dataset_name=dataset_name; %dataset name
opts.network_name=network_name; %network name
opts.use_gpu=use_gpu; %use gpu or not

if ~isfield(opts,'datatype')
    opts.datatype ='single';
end

if ~isfield(opts,'LoadNet')
    opts.LoadNet=0;
end

opts.dataDir=['./',opts.dataset_name,'/'];
opts=PrepareDataFunc(opts);

%opts.parameters=[];

opts.parameters.current_ep=1;

%%%parameters in the training

opts.parameters.learning_method=learning_method;
opts.parameters.selective_sgd=use_selective_sgd;%call selective-sgd

%selective-sgd parameters
if opts.parameters.selective_sgd==1
    if ~isfield(opts.parameters,'search_iterations')
        opts.parameters.search_iterations=30;%iterations used to determine the learning rate
    end
    opts.parameters.ssgd_search_freq=ssgd_search_freq;%%search every n epoch
    if ~isfield(opts.parameters,'lrs')

        opts.parameters.lrs =[1,.5];%initialize selection range
        if ~strcmp(func2str(opts.parameters.learning_method),'sgd')&&~strcmp(func2str(opts.parameters.learning_method),'sgd2')
            opts.parameters.lrs =opts.parameters.lrs.*1e-1;
        end
        opts.parameters.lrs=[opts.parameters.lrs,opts.parameters.lrs*1e-1,opts.parameters.lrs*1e-2,opts.parameters.lrs*1e-3];%initialize selection range
    end
    opts.parameters.selection_count=0;%initialize
    opts.parameters.selected_lr=[];%initialize
end

if opts.parameters.selective_sgd==0
    opts.parameters.lr =sgd_lr;
end

%%sgd parameters
if ~isfield(opts.parameters,'mom')
    opts.parameters.mom =0.9;
end

%adam parameters
if strcmp(func2str(opts.parameters.learning_method),'adam')
    if ~isfield(opts.parameters,'mom2')
        opts.parameters.mom2 =0.999;
    end
end

if ~isfield(opts.parameters,'batch_size')
    opts.parameters.batch_size=500;
end
if ~isfield(opts.parameters,'weightDecay')
    opts.parameters.weightDecay=1e-4;
end

opts=generate_output_filename(opts);

if ~isfield(opts,'plot')
    opts.plot =1;
end

if ~isfield(opts,'LoadResults')
    opts.LoadResults=0;
end

if ~opts.LoadResults
    TrainingScript();
end


 function z = fatrix2_embed(mask, dim, x)
%function z = fatrix2_embed(mask, dim, x)
%|
%| version of embed that handles an empty mask
%|
%| in
%|	x	[N L]
%|	dim	[]		size(mask) if mask is nonempty
%|	mask	[(dim)]		possibly empty
%|
%| out
%|	z	[(dim) L]
%|
%| Copyright 2010-12-21, Jeff Fessler, University of Michigan

if nargin < 3, ir_usage, end

if ~isempty(mask)
	z = embed(x, mask);
else
	z = reshape(x, [dim size(x,2)]);
end


function gpmf = gpmf_constant(varargin)
%GPMF_CONSTANT  Create a constant mean function
%
%  Description
%    GPMF = GPMF_CONSTANT('PARAM1',VALUE1,'PARAM2,VALUE2,...)
%    creates constant mean function structure in which the named
%    parameters have the specified values. Any unspecified
%    parameters are set to default values.
%
%    GPMF = GPMF_CONSTANT(GPMF,'PARAM1',VALUE1,'PARAM2,VALUE2,...)
%    modify a mean function structure with the named parameters
%    altered with the specified values.
%
%    Parameters for constant mean function
%      constant          - constant value for the constant
%                          base function (default 1)
%      prior_mean        - prior mean (scalar or vector) for base
%                          functions' weight prior (default 0)
%      prior_cov         - prior covariances (scalar or vector)
%                          for base functions' prior corresponding
%                          each selected input dimension. In
%                          multiple dimension case prior_cov is a
%                          struct containing scalars or vectors.
%                          The covariances must all be either
%                          scalars (diagonal cov.matrix) or
%                          vectors (for non-diagonal cov.matrix)
%                          (default 100)
%
%  See also
%    GP_SET, GPMF_LINEAR, GPMF_SQUARED
%

% Copyright (c) 2010 Tuomas Nikoskinen
% Copyright (c) 2011 Jarno Vanhatalo

% This software is distributed under the GNU General Public
% License (version 3 or later); please refer to the file
% License.txt, included with the software, for details.

  ip=inputParser;
  ip.FunctionName = 'GPMF_CONSTANT';
  ip.addOptional('gpmf', [], @isstruct);
  ip.addParamValue('constant',1, @(x) isvector(x) && all(x>0));
  ip.addParamValue('prior_mean',0, @(x) isvector(x));
  ip.addParamValue('prior_cov',100, @(x) isvector(x));
  ip.addParamValue('mean_prior', [], @isstruct);
  ip.addParamValue('cov_prior', [], @isstruct);
  ip.parse(varargin{:});
  gpmf=ip.Results.gpmf;

  if isempty(gpmf)
    % Initialize a mean function
    init=true;
    gpmf.type = 'gpmf_constant';
  else
    % Modify a mean function
    if ~isfield(gpmf,'type') && isequal(gpmf.type,'gpmf_constant')
      error('First argument does not seem to be a constant mean function')
    end
    init=false;
  end

  % Initialize parameters
  if init || ~ismember('type',ip.UsingDefaults)
    gpmf.constant = ip.Results.constant;
  end
  if init || ~ismember('prior_mean',ip.UsingDefaults)
    gpmf.b=ip.Results.prior_mean(:)';
  end
  if init || ~ismember('prior_mean',ip.UsingDefaults)
    gpmf.B=ip.Results.prior_cov(:)';
  end
  if init || ~ismember('mean_prior',ip.UsingDefaults)
    gpmf.p.b=ip.Results.mean_prior;
  end
  if init || ~ismember('cov_prior',ip.UsingDefaults)
    gpmf.p.B=ip.Results.cov_prior;
  end
  if init
    % Set the function handles to the nested functions
    gpmf.fh.geth = @gpmf_geth;
    gpmf.fh.pak = @gpmf_pak;
    gpmf.fh.unpak = @gpmf_unpak;
    gpmf.fh.lp = @gpmf_lp;
    gpmf.fh.lpg = @gpmf_lpg;
    gpmf.fh.recappend = @gpmf_recappend;
  end

end

function h = gpmf_geth(gpmf, x)
%GPMF_GETH  Calculate the base function values for a given input.
%
%  Description
%    H = GPMF_GETH(GPMF,X) takes in a mean function structure
%    GPMF and inputs X. The function returns a row vector of
%    length(X) containing the constant value which is by default
%    1.

  constant=gpmf.constant;
  h = repmat(constant,1,length(x(:,1)));

end

function [w, s] = gpmf_pak(gpmf, w)
%GPMF_PAK  Combine GP mean function parameters into one vector
%
%  Description
%    W = GPCF_LINEAR_PAK(GPCF) takes a covariance function
%    structure GPCF and combines the covariance function
%    parameters and their hyperparameters into a single row
%    vector W.
%
%       w = [ log(gpcf.coeffSigma2)
%             (hyperparameters of gpcf.coeffSigma2)]'
%
%  See also
%    GPCF_LINEAR_UNPAK

  w = []; s = {};
  if ~isempty(gpmf.p.b)
    w = gpmf.b;
    if numel(gpmf.b)>1
      s = [s; sprintf('gpmf_constant.b x %d',numel(gpmf.b))];
    else
      s = [s; 'gpmf_constant.b'];
    end
    % Hyperparameters of coeffSigma2
    [wh sh] = gpmf.p.b.fh.pak(gpmf.p.b);
    w = [w wh];
    s = [s; sh];
  end

  if ~isempty(gpmf.p.B)
    w = [w log(gpmf.B)];
    if numel(gpmf.B)>1
      s = [s; sprintf('log(gpmf_constant.B x %d)',numel(gpmf.B))];
    else
      s = [s; 'log(gpmf_constant.B)'];
    end
    % Hyperparameters of coeffSigma2
    [wh sh] = gpmf.p.B.fh.pak(gpmf.p.B);
    w = [w wh];
    s = [s; sh];
  end

end

function [gpmf, w] = gpmf_unpak(gpmf, w)
%GPCF_LINEAR_UNPAK  Sets the mean function parameters
%                   into the structure
%
%  Description
%    [GPCF, W] = GPMF_UNPAK(GPCF, W) takes a covariance
%    function structure GPCF and a hyper-parameter vector W, and
%    returns a covariance function structure identical to the
%    input, except that the covariance hyper-parameters have been
%    set to the values in W. Deletes the values set to GPCF from
%    W and returns the modified W.
%
%    Assignment is inverse of
%       w = [ log(gpcf.coeffSigma2)
%             (hyperparameters of gpcf.coeffSigma2)]'
%
%  See also
%   GPCF_LINEAR_PAK

  gpp=gpmf.p;

  if ~isempty(gpp.b)
    i2=length(gpmf.b);
    i1=1;
    gpmf.b = w(i1:i2);
    w = w(i2+1:end);

    % Hyperparameters of coeffSigma2
    [p, w] = gpmf.p.b.fh.unpak(gpmf.p.b, w);
    gpmf.p.b = p;
  end

  if ~isempty(gpp.B)
    i2=length(gpmf.B);
    i1=1;
    gpmf.B = exp(w(i1:i2));
    w = w(i2+1:end);

    % Hyperparameters of coeffSigma2
    [p, w] = gpmf.p.B.fh.unpak(gpmf.p.B, w);
    gpmf.p.B = p;
  end

end

function lp = gpmf_lp(gpmf)
%GPCF_SEXP_LP  Evaluate the log prior of covariance function parameters
%
%  Description
%
%  See also

% Evaluate the prior contribution to the error. The parameters that
% are sampled are transformed, e.g., W = log(w) where w is all
% the "real" samples. On the other hand errors are evaluated in
% the W-space so we need take into account also the Jacobian of
% transformation, e.g., W -> w = exp(W). See Gelman et.al., 2004,
% Bayesian data Analysis, second edition, p24.
  lp = 0;
  gpp=gpmf.p;

  if ~isempty(gpmf.p.b)
    lp = lp + gpp.b.fh.lp(gpmf.b, ...
                   gpp.b);
  end

  if ~isempty(gpp.B)
    lp = lp + gpp.B.fh.lp(gpmf.B, ...
                   gpp.B) +sum(log(gpmf.B));
  end
end

function [lpg_b, lpg_B] = gpmf_lpg(gpmf)
%GPCF_SEXP_LPG  Evaluate gradient of the log prior with respect
%               to the parameters.
%
%  Description
%    LPG = GPCF_SEXP_LPG(GPCF) takes a covariance function
%    structure GPCF and returns LPG = d log (p(th))/dth, where th
%    is the vector of parameters.
%
%  See also
%    GPCF_SEXP_PAK, GPCF_SEXP_UNPAK, GPCF_SEXP_LP, GP_G

  lpg_b=[]; lpg_B=[];
  gpp=gpmf.p;

  if ~isempty(gpmf.p.b)
    lll = length(gpmf.b);
    lpgs = gpp.b.fh.lpg(gpmf.b, gpp.b);
    lpg_b = [lpgs(1:lll) lpgs(lll+1:end)];  %.*gpmf.b+1
  end

  if ~isempty(gpmf.p.B)
    lll = length(gpmf.B);
    lpgs = gpp.B.fh.lpg(gpmf.B, gpp.B);
    lpg_B = [lpgs(1:lll).*gpmf.B+1 lpgs(lll+1:end)];
  end
end

function recmf = gpmf_recappend(recmf, ri, gpmf)
%RECAPPEND  Record append
%
%  Description
%
%  See also
%    GP_MC and GP_MC -> RECAPPEND

% Initialize record
  if nargin == 2
    recmf.type = 'gpmf_constant';

    % Initialize parameters
    recmf.b= [];
    recmf.B = [];

    % Set the function handles
    recmf.fh.geth = @gpmf_geth;
    recmf.fh.pak = @gpmf_pak;
    recmf.fh.unpak = @gpmf_unpak;
    recmf.fh.lp = @gpmf_lp;
    recmf.fh.lpg = @gpmf_lpg;
    recmf.fh.recappend = @gpmf_recappend;

    recmf.p=[];
    recmf.p.b=[];
    recmf.p.B=[];
    if isfield(ri.p,'b') && ~isempty(ri.p.b)
      recmf.p.b = ri.p.b;
    end
    if ~isempty(ri.p.B)
      recmf.p.B = ri.p.B;
    end
    return
  end

  gpp = gpmf.p;

  % record magnSigma2
  if ~isempty(gpmf.b)
    recmf.b(ri,:)=gpmf.b;
    if ~isempty(recmf.p.b)
      recmf.p.b = gpp.b.fh.recappend(recmf.p.b, ri, gpmf.p.b);
    end
  elseif ri==1
    recmf.b=[];
  end

  if ~isempty(gpmf.B)
    recmf.B(ri,:)=gpmf.B;
    if ~isempty(recmf.p.B)
      recmf.p.B = gpp.B.fh.recappend(recmf.p.B, ri, gpmf.p.B);
    end
  elseif ri==1
    recmf.B=[];
  end

end


function Q = cumsummat(N)
%CUMSUMMAT   Trigonometric Fourier integration matrix.
%   Q = CUMSUMMAT(N) is the matrix that maps function values at N equi-spaced
%   points to values of the integral of the interpolating trigonometric
%   polynomial at those points.

% [TODO]: Add support.
error('CHEBFUN:TRIGCOLLOC:cumsummat:notSupported', ...
    ['Indefinite integration is currently not supported for ' ...
    'TRIGCOLLOC discretization.\nPlease consider using ' ....
    'CHEBCOLLOC2 or ULTRAS discretization.']);

end


function MatingPool = MatingStrategy(IMatrix)

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

% This function is written by Jiawei Yuan

Ps                   = 0.7;     % probability of partner selection
[Num,~]              = size(IMatrix);
[~,Neighboors]       = min(IMatrix,[],2);

AllInd               = 1:Num;
SpouseID             = Neighboors;
ChnageInd            = find(rand(1,Num)>Ps);
SpouseID(ChnageInd)  = AllInd(ceil(rand(1,length(ChnageInd))*Num));

AllInd               = reshape(AllInd,1,Num);
SpouseID             = reshape(SpouseID,1,Num);
MatingPool           = [AllInd,SpouseID];
end


function [ report ] = testReport( obj )
%testReport Analyze the sequence and return a text report
%   Currently no parameters are required. In future versions it may be
%   possible to (de)select some tests
%
% maxim.zaitsev@uniklinik-freiburg.de

% find the RF pulses and list flip angles
flipAnglesDeg=[];
for k=obj.rfLibrary.keys
    libData=obj.rfLibrary.data(k).array;
    if length(obj.rfLibrary.type)>=k
        rf=obj.rfFromLibData(libData,obj.rfLibrary.type(k));
    else
        rf=obj.rfFromLibData(libData);
    end
    flipAnglesDeg=[flipAnglesDeg abs(sum(rf.signal(1:end-1).*(rf.t(2:end)-rf.t(1:end-1))))*360]; %we use rfex.t(1) in place of opt.system.rfRasterTime
end
flipAnglesDeg=unique(flipAnglesDeg);

% calculate TE and TR

[duration, numBlocks, eventCount]=obj.duration();

%[ktraj_adc, ktraj, t_excitation, t_refocusing, t_adc] = obj.calculateKspace();
%[ktraj_adc, t_adc, ktraj, t_ktraj, t_excitation, t_refocusing] = obj.calculateKspacePP();
[ktraj_adc, t_adc, ~, ~, t_excitation, ~] = obj.calculateKspacePP();

% trajectory calculation will fail for spin-echoes if seq is loaded from a
% file for the current file format revision (1.2.0) because we do not store
% the use of the RF pulses. Read function has an option 'detectRFuse' which
% may help...

%
kabs_adc=sum(ktraj_adc.^2,1).^0.5;
[kabs_echo, index_echo]=min(kabs_adc);
t_echo=t_adc(index_echo); % just a first estimate, see if we can improve it
if kabs_echo>eps
    i2check=[];
    % check if adc kspace trajectory has elements left and right to index_echo
    if index_echo > 1
        i2check=[i2check (index_echo-1)];
    end
    if index_echo < length(kabs_adc)
        i2check=[i2check (index_echo+1)];
    end
    for a=1:numel(i2check)
        v_i_to_0=-ktraj_adc(:,index_echo);
        v_i_to_t=ktraj_adc(:,i2check(a))-ktraj_adc(:,index_echo);
        % project v_i_to_0 to v_o_to_t
        p_vit=v_i_to_0'*v_i_to_t/(vecnorm(v_i_to_t)^2);
        if p_vit>0
            % we have forund a bracket for the echo and the proportionality
            % coefficient is p_vit
            t_echo=t_adc(index_echo)*(1-p_vit) + t_adc(i2check(a))*p_vit;
            break;
        end
    end
end

if ~isempty(t_excitation)
    t_ex_tmp=t_excitation(t_excitation<t_echo);
    TE=t_echo-t_ex_tmp(end);
    % TODO detect multiple TEs
else
    TE=NaN;
end

if (length(t_excitation)<2)
    TR=duration; % best estimate for now
else
    t_ex_tmp1=t_excitation(t_excitation>t_echo);
    if isempty(t_ex_tmp1)
        TR=t_ex_tmp(end)-t_ex_tmp(end-1);
    else
        TR=t_ex_tmp1(1)-t_ex_tmp(end);
    end
    % TODO check frequency offset to detect multiple slices
end

% check sequence dimensionality and spatial resolution
k_extent=max(abs(ktraj_adc),[],2);
k_scale=max(k_extent);
if (k_scale~=0)
    k_bins=4e6; % this defines our ability to separate k-space samples.
                % lower values give us imunity to rounding errors in k-space calculations
                % current code below (2nd pass) however merges neighboring cells (+-1)
    k_threshold=k_scale/k_bins;

    % detect unused dimensions and delete them
    if any(k_extent<k_threshold)
        ktraj_adc(k_extent<k_threshold,:)=[]; % delete rows
        k_extent(k_extent<k_threshold)=[];
    end

    % bin the k-space trajectory to detect repetitions / slices
    k_len=size(ktraj_adc,2);
    k_repeat=zeros(1,k_len);
    k_storage=zeros(1,k_len);
    k_storage_next=1;
    % containers.Map only supports string as a key... (in older matlabs)
    %kmap = containers.Map('KeyType', 'char', 'ValueType', 'int32');
    kmap = java.util.HashMap;
    for i=1:k_len
        key_string = sprintf('%d ', int32(k_bins+round(ktraj_adc(:,i)/k_threshold)));
        % containers.Map does not have a proper find function so we use direct
        % access and catch the possible error
        k_storage_ind = kmap.get(key_string);
        if isempty(k_storage_ind)
            k_storage_ind=k_storage_next;
            kmap.put(key_string,k_storage_ind);
            k_storage_next=k_storage_next+1;
        end
        k_storage(k_storage_ind)=k_storage(k_storage_ind)+1;
        k_repeat(i) = k_storage(k_storage_ind);
    end
    % at this point k_storage(1:(k_storage_next-1)) is our visit frequency map
    Repeats_max=max(k_storage(1:(k_storage_next-1)));
    Repeats_min=min(k_storage(1:(k_storage_next-1)));
    Repeats_median=median(k_storage(1:(k_storage_next-1)));
    Repeats_unique=unique(k_storage(1:(k_storage_next-1)));
    Counts_unique=zeros(size(Repeats_unique));
    for i=1:numel(Repeats_unique)
        Counts_unique(i)=sum(Repeats_unique(i)==k_storage(1:(k_storage_next-1)));
    end

    ktraj_rep1=ktraj_adc(:,k_repeat==1);
    % TODO: think of something clever, e.g. detecting maximum delta-k
    % if length(k_extent)==2
    %     dt = delaunayTriangulation(ktraj_rep1');
    %     k = convexHull(dt);
    %     figure; plot(dt.Points(:,1),dt.Points(:,2), '.', 'markersize',10); hold on;
    %     plot(dt.Points(k,1),dt.Points(k,2), 'r'); hold off;
    %     %[V,R] = voronoiDiagram(dt);
    %     figure; voronoi(dt);
    % end
    % try to detect k-space lines or columns.
    k_counters=zeros(size(ktraj_rep1));
    dims=size(ktraj_rep1,1);
    %ordering=cell(1,dims);
    kmap = java.util.HashMap;
    for j=1:dims
        %kmap = containers.Map('KeyType', 'int32', 'ValueType', 'int32');
        k_storage=zeros(1,k_len);
        k_storage_next=1;
        kmap.clear();
        for i=1:size(ktraj_rep1,2)
            key=int32(round(ktraj_rep1(j,i)/k_threshold));
            k_storage_ind = kmap.get(key);
            if isempty(k_storage_ind) % attempt to account for rounding errors
                k_storage_ind = kmap.get(key+1);
            end
            if isempty(k_storage_ind) % attempt to account for rounding errors
                k_storage_ind = kmap.get(key-1);
            end
            if isempty(k_storage_ind)
                k_storage_ind=k_storage_next;
                kmap.put(key,k_storage_ind);
                k_storage_next=k_storage_next+1;
                k_storage(k_storage_ind)=ktraj_rep1(j,i);
                %fprintf('%d:%d(%g) ',k_storage_ind,key,ktraj_rep1(j,i));
            end
            %assert(k_storage_ind==k_storage(k_storage_ind));
            k_counters(j,i) = k_storage_ind;
        end
        %ordering{j}=cell2mat(kmap.values);
        %fprintf('\n');
    end
    unique_kpositions=max(k_counters,[],2);
    isCartesian=(prod(unique_kpositions)==size(ktraj_rep1,2));
else
    unique_kpositions=1;
end
% check gradient amplitudes and slew rates

% gradient waveform
gw_data=obj.waveforms_and_times(); % FIXME: avoid this second call for generating gradient shapes (1st one was inside of the k-space calculation routine)
gws=cell(size(gw_data));
ga=zeros(length(gw_data),1);
gs=zeros(length(gw_data),1);
% to calculate max absolute gradients and slew rates we have to play
% tricks... we namely have to interpolate the data to the common time axis
dim1ind = @(x, n) x(n,:);
common_time=unique(dim1ind([gw_data{:}],1));
gw_ct=zeros(length(gw_data),length(common_time));
gs_ct=zeros(length(gw_data),length(common_time)-1);
for gc=1:length(gw_data)
    if size(gw_data{gc},2)>0
        gws{gc}=(gw_data{gc}(2,2:end)-gw_data{gc}(2,1:end-1))./(gw_data{gc}(1,2:end)-gw_data{gc}(1,1:end-1)); % slew
        % interpolate to the common time
        gw_ct(gc,:)=interp1(gw_data{gc}(1,:),gw_data{gc}(2,:),common_time,'linear',0);
        gs_ct(gc,:)=(gw_ct(gc,2:end)-gw_ct(gc,1:end-1))./(common_time(2:end)-common_time(1:end-1));
        % max grad/slew per channel
        ga(gc)=max(abs(gw_data{gc}(2,:)));
        gs(gc)=max(abs(gws{gc}));
        % TODO: calculate grad RMS values (this is an interesting task in the piece-wise-linear domain)
    end
end

%figure; plot(common_time, gw_ct');
%figure; plot(common_time, sum(gw_ct.^2,1).^0.5);
%figure; plot(0.5*(common_time(1:end-1)+common_time(2:end)), sum(gs_ct.^2,1).^0.5);

% max absolute value grad/slew -- check for a worst case upon rotation
ga_abs=max(sum(gw_ct.^2,1).^0.5);
gs_abs=max(sum(gs_ct.^2,1).^0.5);

% check timing of blocks and delays (raster alignment)
[timing_ok, timing_error_report] = obj.checkTiming();

report = { sprintf('Number of blocks: %d\n',numBlocks),...
           [ sprintf('Number of events:\n'),...
             sprintf('   RF:   %6d\n',eventCount(2)),...
             sprintf('   Gx:   %6d\n',eventCount(3)),...
             sprintf('   Gy:   %6d\n',eventCount(4)),...
             sprintf('   Gz:   %6d\n',eventCount(5)),...
             sprintf('   ADC:  %6d\n',eventCount(6))],...
           [ sprintf('Sequence duration: %.6fs\n',duration),...
             sprintf('TE: %.6fs\n',TE),...
             sprintf('TR: %.6fs\n',TR) ],...
             sprintf('Flip angle: %.02f°\n', flipAnglesDeg),...
             sprintf('Unique k-space positions (a.k.a. columns, rows, etc): %d\n', unique_kpositions)};
if any(unique_kpositions>1)
    report = { report{:},...
           [ sprintf('Dimensions: %d\n', length(k_extent)),...
             sprintf('   Spatial resolution: %.02f mm\n', 0.5./k_extent*1e3) ],...
             sprintf('Repetitions/slices/contrasts: %.d  range: [%.d %.d]\n', Repeats_median, Repeats_min, Repeats_max) };
    report = { report{:},...
        sprintf('   %d k-space position(s) repeated %d times\n', [Counts_unique;Repeats_unique])};

    if isCartesian
       report = { report{:}, sprintf('Cartesian encoding trajectory detected\n') };
    else
       report = { report{:}, sprintf('Non-Cartesian/irregular encoding trajectory detected (e.g. EPI, spiral, radial, etc)\n') };
    end
end
if (timing_ok)
    report = { report{:}, sprintf('Block timing check passed successfully\n') };
else
    report = { report{:}, [ sprintf('Block timing check failed! Error listing follows:\n'),...
                            sprintf([timing_error_report{:}]) ] };
end
report = { report{:},...
    sprintf('Max. Gradient: %.0f Hz/m == %.02f mT/m\n', [ga mr.convert(ga,'Hz/m','mT/m')]'),...
    sprintf('Max. Slew Rate: %g Hz/m/s == %.02f T/m/s\n', [gs mr.convert(gs,'Hz/m/s','T/m/s')]') };
report = { report{:},...
    sprintf('Max. Absolute Gradient: %.0f Hz/m == %.02f mT/m\n', [ga_abs mr.convert(ga_abs,'Hz/m','mT/m')]'),...
    sprintf('Max. Absolute Slew Rate: %g Hz/m/s == %.02f T/m/s\n', [gs_abs mr.convert(gs_abs,'Hz/m/s','T/m/s')]') };

end