function [evtonsets,X,bestp,meff,origvec] = ga2(gensize,numgen,conditions,mspec,varargin)
%[evtonsets,X,bestp,meff,origvec] = ga2(gensize,numgen,conditions,mspec,[nooverlap])
%
% everything in conditions should be in number of frames (TRs), not seconds
% model_setup_ui.m automatically creates the correct format
%
% optional last argument is a 1 or 0.  1 Constrains the events so that
% events of different trials do not overlap.
%
% recommended: test conditions setup before running with
% [X,pv] = construct_model(mspec,conditions,[]);
% also [X,pv] = paramvec2onsets(mspec,conditions,[]);
%
% OR
%
% [X,pv] = construct_model(mspec,conditions,[],[1 14]);
% ...to constrain overlaps among trials to a min of 14 TRs apart,
% (variable trial onsets will only be properly constrained by the 2nd element).
% OR add in mspec.toverlap = [1 10], e.g.
%
% Tor Wager
% April 19, 2002
% Modified April 2, 2003: changed xover, convergence, constrained
%   so that min time between trial onsets is maintained
%   also added non-identity intrinsic autocorrelation
%   and capability for d-optimality
%
% Modified May 14, 2003: changed autocorrelation function to colored noise
%
% convergence criteria:
%   all efficiency scores are the same, OR no improvement in 100 generations
%
% defaults:
%   exponential autocorrelation function based on empirical estimates
%   saturation (clipping) of the predicted response at 2.5 times the original height
%       in order to approximate nonlinear effects
%   A-optimal design efficiency computation
%
%   Also possible:
%   Combo A-D optimal design, equally weighted
%       for A-optimal design, mspec.dopt = 0;
%       for D-optimality, specify mspec.dopt = 1;
%   But I'm still testing the D-optimality stuff.
%
% to see a test of A vs D optimality, try:
% Vi = eye(mspec.numframes);
% for i = 1:1000,
%    [X,paramvec] = construct_model(mspec,conditions,[]);
%    a(i) = calcefficiency(ones(1,size(X,2) - 1),[],pinv(X),Vi,0);
%    d(i) = 1 ./ (inv(det(X'*X)) .^ (1./size(X,2)));
% end
% d = d - mean(d);
% figure; plot(a,d,'x'); xlabel('A-efficiency'),ylabel('D-efficiency')
% a1 = calcefficiency(ones(1,size(X,2) - 1),[],pinv(X),Vi,0);
% d1 = 1 ./ (inv(det(X'*X)) .^ (1./size(X,2)));
% hold on;plot(a1,d1,'rs','MarkerFaceColor','r')

t0 = clock;

% --------------------------------------------------------------------
%
% * Setup and defaults
%
% --------------------------------------------------------------------

if length(varargin) > 0, nooverlap = varargin{1};,else, nooverlap = 0;,end

for j = 1:gensize, newvec{j} = [];,end

% intrinsic autocorrelation
% --------------------------------------------------------------------
%Vi = eye(mspec.numframes);      % use this for scanner white noise

% new autocorr, from VNL experiment (n = 10)
% this is invariant to the TR as well.
f = inline('5.6034 * exp(-.93 * x)','x');
t1 = f(1:mspec.TR:10); t1 = t1 ./ t1(1);

Vi = getv('make',t1,ceil(mspec.numframes));

% nonlinearity and fitness function
% --------------------------------------------------------------------

% nonlinear clipping threshold
satthresh = 2.5;

% display results vs. random?
showres = 1;

% converge if no change in this many generations
genconverge = 10;

% optimality - default is A
if ~isfield(mspec,'dopt'), mspec.dopt = 0;, end
if mspec.dopt == 2
    disp('Computing both A- and D-optimality'),
elseif mspec.dopt == 1
    disp('Computing D-optimality'),
else
    disp('Computing A-optimality'),
end

if nooverlap & length(nooverlap) == 1
    % we need a list of all trial onset conditions to make sure we don't create
    % illegal lists in xover
    % older, more cumbersome way based on each condition
    trialonsetinfo = get_tonsetinfo(conditions);
elseif nooverlap & length(nooverlap) > 1
    % newer way: minimum time constraint between all trial onsets
    trialonsetinfo = nooverlap(2);
else
    % no constraints
    trialonsetinfo = -Inf;
end

% model seeding - m-sequences, 10 %
% works for designs with one subpart per trial - don't know about
% others.  will have to insert more paramvec entries
% --------------------------------------------------------------------
nmseq = round(gensize ./ 10);
%[mseqs,newvec(1:nmseq)] = genMseq(mspec.numframes,[],[],nmseq,length(conditions));

[tmp,mseqs] = genMseq(mspec.numframes,[],[],nmseq,length(conditions));  % 10 sequences

for i = 1:length(mseqs)
    % get paramvec, which constrains length to correct values
    [tmp,pvm] = construct_model(mspec,conditions,mseqs{i});
    newvec{i} = pvm;
end

% set up contrasts across conditions
% --------------------------------------------------------------------
    numframes = [];,    % ne4eded for ga3power at the end, and for contrasts
    for i = 1:length(conditions),
        for j=1:length(conditions(i).subcond), numframes(end+1) = conditions(i).subcond(j).hrfest;,
        end
    end

if isfield(mspec,'contrasts')
    % executes the code to apply contrast, apply_dx_contrast.m, in
    % construct_model
    disp(['Found contrast to collapse columns: ']), mspec.contrasts
end

f1 = figure; set(gcf,'Color','w'); hold on; title('Max efficiency'),xlabel('Generation')

% matrix of multiplier values for each param in first cell to add noise
tmp = cat(1,newvec{:}); for i = 1:length(tmp), tmp{i} = diff(tmp{i}); end , tmp = cat(2, tmp{:});
noisestd = .2 .* range(tmp);
disp(['Noise std if no change is: ' num2str(noisestd)])

% --------------------------------------------------------------------
%
% * Start generations
%
% --------------------------------------------------------------------

for i = 1:numgen

    t1 = clock;

    for j = 1:gensize

        % --------------------------------------------------------------------
        % * make models
        % --------------------------------------------------------------------
        % if empty (1st generation), then it constructs a model.
        [X,paramvec{j}] = construct_model(mspec,conditions,newvec{j},nooverlap);
        X = modelSaturation(X,satthresh);

        % tmp for Emily
        %X(:,15*4+1:15*5) = X(:,15*4+1:15*5) + X(:,15*6+1:15*7); X(:,15*6+1:15*7) = [];

        XX{j} = X;

        if i == i & j == 1
            cweights = ones(1,size(X,2) - 1);
        end

        if mspec.dopt == 0
            eff(j) = calcEfficiency(cweights,[],pinv(X),Vi,0);
        elseif mspec.dopt == 1
            eff(j) = det(X'*X) .^ (1./size(X,2)); % 1 ./ (inv(det(X'*X)) .^ (1./size(X,2)));  % D-optimality
        elseif mspec.dopt == 2  % for A- D-optimality
            eff2(j) = calcEfficiency(cweights,[],pinv(X),Vi,0);
            eff(j) = det(X'*X) .^ (1./size(X,2));  % D-optimality
        end

    end

    if mspec.dopt == 2  % for A- D-optimality
        zeff = (eff - mean(eff)) ./ std(eff);
        zeff2 = (eff2 - mean(eff2)) ./ std(eff2);
        zeff = zeff + zeff2;
        meffi = max(zeff);
        meffind = find(zeff == meffi); meffind = meffind(1);
        meff(i) = eff(meffind);
        meff2(i) = eff2(meffind);
        t2 = clock;
        fprintf(1,'Gen %3.0f: D-eff is %3.4f, A-eff is %3.4f, model %3.0f, time = %3.2f, elapsed = %3.0f\n',i,meff(i),meff2(i),meffind,etime(t2,t1),etime(t2,t0));
        figure(f1); subplot 121; plot(1:i,meff,'r','LineWidth',2); title('D-efficiency')
        subplot 122; plot(1:i,meff2,'b','LineWidth',2); title('A-efficiency')
        drawnow

    else
        [meffi, meffind] = max(eff);
        meffind = meffind(1);
        meff(i) = meffi;
        t2 = clock;
        fprintf(1,'Gen %3.0f: best eff is %3.4f, model %3.0f, time = %3.2f, elapsed = %3.0f\n',i,meffi,meffind,etime(t2,t1),etime(t2,t0));
        figure(f1); plot(1:i,meff,'LineWidth',2); drawnow
    end

    % --------------------------------------------------------------------
    % add noise if no improvement at all
    % rounding and illegal values should be handled by construct_model
    % but need to be integers >= 0 for HRF power below
    % in next iteration
    % --------------------------------------------------------------------
    if meffind == 1

        for j = 1:length(paramvec)
            if j == meffind
                % leave the best one alone!
            else
                for k = 1:length(paramvec{j})
                    paramvec{j}{k} = paramvec{j}{k} + round( noisestd .* randn(size(paramvec{j}{k})) );

                    paramvec{j}{k}(paramvec{j}{k} < 0) = 0;
                end
            end
        end

    end

    % --------------------------------------------------------------------
    % * save best and crossover
    % --------------------------------------------------------------------
    bestp = paramvec{meffind};

    % test power of bestp
    clear delta
    for reg = 1:length(bestp)
        delta{reg} = zeros(mspec.numframes,1);
        delta{reg}(bestp{reg}+1) = 1;
        delta{reg} = delta{reg}(1:mspec.numframes);
    end
    P = hrf_power(mspec.TR,conditions(1).subcond.hrfest,delta,eye(length(bestp)));
    bestipow(i) = max(P.ipow);
    figure(f1); hold on; plot(bestipow,'r','LineWidth',2),drawnow
    %figure;subplot(1,2,1);imagesc(P.X2); subplot(1,2,2);imagesc(XX{meffind}); colormap gray

    % --------------------------------------------------------------------
    % * Check for convergence
    % --------------------------------------------------------------------
    if i > genconverge
        last_gens = meff(i-genconverge+1:i);
        unique_in_last_gens = length(unique(last_gens));
        % if the above is one, there has been no change in last n
        % generations
    else
        unique_in_last_gens = Inf;
    end

    if (all(eff == median(eff))) || unique_in_last_gens == 1
        isconverged = 1;
        disp(['System converged at generation ' num2str(i)])

        break
    end

    % save 1st generation in origvec output
    if i == 1, origvec = newvec; end

    [newvec] = xover(paramvec,eff,trialonsetinfo);
        %newvec{ceil(rand * length(newvec))} = bestp;   % this causes lots of the same list to be inserted randomly
     newvec{1} = bestp;

end

% --------------------------------------------------------------------
% * End of GA
% --------------------------------------------------------------------

X = construct_model(mspec,conditions,bestp,nooverlap);

% --------------------------------------------------------------------
% * Figure of final model matrix
% --------------------------------------------------------------------
try
    figure('Color','w'); imagesc(X); colormap(gray)
    bestcondno = cond(X);
    tmp = corrcoef(X); tmp=tmp(:); tmp(isnan(tmp) | tmp == 1) = []; maxcorr = max(tmp);
    tmp = sprintf('Best model: Cond. # = %3.2f, max pairwise corr = %3.2f',bestcondno,maxcorr);
    title(tmp),
catch
    disp('Problem with figures')
end

% this plots lines for onsets of first event type
%hold on; plot(repmat([.5 1],length(evtonsets{1}),1)',[1+(evtonsets{1} ./ mspec.TR) 1+(evtonsets{1} ./ mspec.TR)]','r','LineWidth',2)

% --------------------------------------------------------------------
% * Text list of onset times
% --------------------------------------------------------------------
try
    disp(' '); disp('GA2.m output')
    [evtonsets,paramvec] = paramvec2onsets(mspec,conditions,bestp,nooverlap);
catch
    disp('Error building evtonsets!  Incorrect model specification in model_setup_ui.m')
    evtonsets = [];
end

fname = ['ga2_output' datestr(now,31)]; fname(fname==' ')='_';fname(end-5)='h';fname(end-2)='m';fname=fname(1:end-2);
try
    eval(['save ' fname ' mspec conditions X bestp nooverlap evtonsets paramvec'])
catch
    warning('Not all vars created?  Saving everything.')
    eval(['save ' fname])
end

if showres

    % --------------------------------------------------------------------
    % * Figure of final model matrix
    % --------------------------------------------------------------------
    try
        [out,P] = ga3power(bestp,mspec,conditions,eye(length(numframes)));
    catch
        disp('Could not execute power plot.')
    end

    % --------------------------------------------------------------------
    % * Figure of A vs D optimality
    % --------------------------------------------------------------------
try
    figure('Color','w');hist(diff(evtonsets{1})); xlabel('Time between trial onsets'),ylabel('Frequency'); set(gca,'FontSize',18)

    if ~exist('Vi') == 1
        disp('No Vi detected: Using white noise')
        Vi = eye(mspec.numframes);      % use this for scanner white noise
    end

    disp('Comparing GA results (red square) to 1000 random designs (blue x)')
     for i = 1:1000,
        [X,paramvec] = construct_model(mspec,conditions,[],nooverlap);
        a(i) = calcefficiency(ones(1,size(X,2) - 1),[],pinv(X),Vi,0);
        d(i) = det(X'*X) .^ (1./size(X,2));     % 1 ./ (inv(det(X'*X)) .^ (1./size(X,2)));
     end
    figure('Color','w'); plot(a,d,'x'); set(gca,'FontSize',18); xlabel('A-efficiency'),ylabel('D-efficiency')
    [X,paramvec] = construct_model(mspec,conditions,bestp,nooverlap);
    a1 = calcefficiency(ones(1,size(X,2) - 1),[],pinv(X),Vi,0);
    d1 = 1 ./ (inv(det(X'*X)) .^ (1./size(X,2)));
    hold on;plot(a1,d1,'rs','MarkerFaceColor','r')
    title('GA result vs. random designs')
catch
    disp('Problem with A-vs-D optimality figure')
end

end

return

% --------------------------------------------------------------------
% * get best half, crossover to fill in lists
% --------------------------------------------------------------------
function newvec = xover(paramvec,eff,t)

% save best one - now done outside xover
%b = find(eff == max(eff)); b = b(1); b = paramvec{b};

% add a little random noise to efficiency - 1% of var of efficiency
eff = eff + randn(1,length(eff)) .* .01 * var(eff);

w = find(eff > median(eff));

% we can only do crossover if not all the designs are the same
if isempty(w)
    warning('Extremely homogenous sample!')
    % add a little random noise to efficiency - 1% of var of efficiency
    eff = eff + randn(1,length(eff)) .* .01 * mean(eff);
    w = find(eff > median(eff));
end

% check all paramvec values - works if all trial onsets are fixed
%for i=1:length(eff),ttmp=cat(1,paramvec{1}{:});ttmp=ttmp(:);,tmax(i)=max(ttmp);tmin(i)=min(ttmp);,end,[tmin; tmax]

% save best half
newvec = paramvec(w);
last = size(newvec,2);  % save size for adding random variation to existing

% fill in 2nd half with crossovers of first half
while length(newvec) < length(paramvec)

    w = ceil(rand(1,2) * length(newvec));
    babyv = [];

    for i = 1:length(newvec{w(1)})

        babyv{i} = rcomb(newvec{w(1)}{i},newvec{w(2)}{i});

        if length(t) > 1    % if we have full trialonsetinfo
        % older, more cumbersome way based on each condition
        % construct a set of legal vectors - cannot be less time between events than min onset time

        it = 1;
        while any(diff(babyv{i}) < t(1,i))

            tmp = [Inf diff(babyv{i})]; tmp = t(1,i) - tmp; tmp(tmp < 0) = 0;
            babyv{i} = babyv{i} + ceil(tmp);

            it = it + 1;
            if it > 20,
                %warning(['Too many iterations to get a legal vector for ' num2str(i)]),
                babyv{i} = rcomb(newvec{w(1)}{i},newvec{w(2)}{i});
            end

            if it > 100
                warning(['Too many iterations to get a legal vector for cond ' num2str(i)]),
                w = ceil(rand(1,2) * length(newvec));
                babyv{i} = rcomb(newvec{w(1)}{i},newvec{w(2)}{i});
                keyboard
            end
        end

        else
            % newer way constrains min time only
            % t is constrained in construct_model, so leave out here
        end

    end

    newvec{end+1} = babyv;

end

% add random variation to existing best half
for i = 1:length(paramvec{1})   % i indexes events

    for j = 1:last  % j indexes organisms

        p = sign(randn(1,length(newvec{j}{i})));

        if length(t) > 1    % if old way

        if t(3,i) == 1

            p(1) = 0;
            d = diff(newvec{j}{i});   % get diffs to make sure we don't move something illegally
            d = [Inf d] - t(1,i);
            p(find(d <= 1 & p < 0)) = 0; % set shift value to 0 for these points
            newvec{j}{i} = newvec{j}{i} + p;

            while any(diff(newvec{j}{i}) < t(1,i))

                tmp = [Inf diff(newvec{j}{i})]; tmp = t(1,i) - tmp; tmp(tmp < 0) = 0;
                newvec{j}{i} = newvec{j}{i} + ceil(tmp);

            end

        elseif t(3,i) < 1

            tmp2 = newvec{j}{i} + p;
            %disp('orig')
            %tmp2
            % ensure no values go outside proscribed range
            tmp2(tmp2 < t(1,i)) = t(1,i);
            tmp2(tmp2 > t(2,i)) = t(2,i);
            %disp('final')
            %tmp2

            newvec{j}{i} = tmp2;
        else
            warning('This should not happen.  t(3,:) should be 1 or -Inf')
        end

        else   % not old way, no constraints here (constraints in construct_model)
            newvec{j}{i} = newvec{j}{i} + p;
            newvec{j}{i}(newvec{j}{i} < 0) = 0;
        end

    end

    % warning: may not really ensure that we have stimuli too close
end

%newvec{1} = b;      % re-insert best one

return

% --------------------------------------------------------------------
% * crossover
% --------------------------------------------------------------------
function c = rcomb(a,b)
% combines 2 vectors of numbers at a random crossover point

w = ceil(rand * (length(a) - 1));
c(1:w) = a(1:w);
c = [c b(w+1:end)];

return

function [t,sc] = get_tonsetinfo(conditions)
% get list of onset times to match paramvec
% this contains info needed to see if one trial is impinging on the previous one, based on the length
% so it saves a vector, t, of the minimum times in TRs that each paramvec can have
% this value is compared, for each onset vector in paramvec, to the difference among onset times (trial length)
% to make sure no trial length is less than the minimum.
%
% t has first row = min, 2nd = max, 3rd = trial onsets (1) or subpart (0)

ind = 1;
for i = 1:length(conditions)
    if size(conditions(i).onsets,2) == 2   % variable range of trial onsets
        tmp = sum(conditions(i).onsets);
        t(1,ind) = tmp(1);
        t(2,ind) = tmp(2);
        t(3,ind) = 1;
        ind = ind + 1;
    end

    for j = 1:length(conditions(i).subcond)
        if length(conditions(i).subcond(j).onsets) > 1 & any(diff(conditions(i).subcond(j).onsets))
            t(1:2,ind) = [min(conditions(i).subcond(j).onsets); max(conditions(i).subcond(j).onsets)];
            t(3,ind) = 0;
            % need this for subcond, i think   %conditions(i).subcond(j).onsets(1);
            ind = ind + 1;
        end
    end
end

t(t == 0) = -Inf;

return


function [X] = spm_zeros(X)
% fills a cell or structure array with zeros
% FORMAT [X] = spm_zeros(X)
% X  - numeric, cell or stucture array[s]
%__________________________________________________________________________
% Copyright (C) 2005-2013 Wellcome Trust Centre for Neuroimaging

% Karl Friston
% $Id: spm_zeros.m 6233 2014-10-12 09:43:50Z karl $

% create zeros structure
%--------------------------------------------------------------------------
X = spm_unvec(zeros(spm_length(X),1),X);


function [ r,flag ] = reward_grid_world_goal(s,x,x_goal,x_bad,r_goal,r_bad,r_step)
%reward
%
%   input ---------------------------------------------------------
%
%       o x      : (1 x 1), current grid index of the agent.
%
%       o x_goal : (1 x 1), goal grid index.
%
%   output ---------------------------------------------------------
%
%       o r      : (1 x 1), reward value
%

if s == x_goal

    r    = r_goal;
    flag = true;

elseif ismember(s,x_bad)

    r    = r_bad;
    flag = true;

else

    r    = r_step;
    flag = false;

end

end


function varargout = drawMesh(vertex, face, varargin)
% Plot polygonal 2D or 3D mesh.
%
% Usage:    drawMesh(vertex, face)
%           drawMesh(vertex, face, 'wire')
%           hMesh = drawMesh(vertex, face, color, 'surf', alpha)
%
% INPUT:
% vertex        - nv-by-2 matrix of [x y] or
%                 nv-by-3 matrix of [x y z] vertex coordinates
% face          - nf-by-? faces matrix
% (optional)
% 'wire' or
% 'surf'        - plot wire mesh or surface (default) mesh;
% color         - string, defining the face color (only in 'surf' mode);
%                 default: 'g' (green color);
% alpha         - a scalar between 0 and 1, defining transparency:
%                 0 - transparent, 1 - opaque (default).
%
% OUTPUT:
% (optional)
% hMesh         - handle to the patch object.
%
% Examples:
% 3D:
%  load('queen.mat'); figure(1); clf; drawMesh(vertex, face);
%  load('queen.mat'); figure(1); clf; drawMesh(vertex, face, 'wire');
%  load('queen.mat'); figure(1); clf; drawMesh(vertex, face, 'r', .5);
% 2D:
%  load('home.mat');  figure(1); clf; drawMesh(vertex, face, 'wire');
%
% See also: drawVector, drawPlane, drawSpan, drawLine.

% Copyright (c) 2009, Dr. Vladimir Bondarenko <http://sites.google.com/site/bondsite>

% Check input:
error(nargchk(2,4,nargin));
[mv,nv] = size(vertex);
[mf,nf] = size(face);
if (nv~=3)&&(nv~=2) , error('Wrong dimensions of the vertex matrix.'); end;

% Defaults:
alfa     = 1;
meshType = 'surf';
fcolor = 'g';

% Parse input:
if nargin > 2
    for ii=1:nargin-2
        if ischar(varargin{ii})
           if strcmpi(varargin{ii}, 'surf')||strcmpi(varargin{ii}, 'wire')
               meshType = varargin{ii};
           else
                 fcolor = varargin{ii};
           end;
        elseif isnumeric(varargin{ii})
            alfa = varargin{ii};
        end
    end
end
if (alfa > 1)||(alfa < 0), error('The alpha parameter must be in [0, 1].');end;

% Plot the mesh
switch meshType
    case 'surf'
        hMesh = patch('vertices', vertex,'faces', face,...
                      'facecolor', fcolor, 'FaceAlpha', alfa);
        camlight('headlight');
    case 'wire'
        hMesh = patch('vertices', vertex,'faces', face,...
                      'facecolor', 'none');
end
%axis equal tight off
if nargout==1, varargout{1} = hMesh; end


function [tt]=tt_kron7(tt1,tt2,s)
%Kronecker product of two TT-tensors in the reverse order
%   [TT]=TT_KRON7(TT1,TT2,S)
% May 26, 2011
% Vladimir Kazeev
% vladimir.kazeev@gmail.com
% INM RAS
% Moscow, Russia

d1 = size(tt1,1);
d2 = size(tt2,1);

tt1{1}=permute(tt1{1},[(1:s),s+2,s+1]);
%tt2{1}=permute(tt2{1},[(1:s),s+2,s+1]);

tt = cell(d1+d2,1);
for i=1:d2
	tt{i}=tt2{i};
end
for i=1:d1
	tt{d2+i}=tt1{i};
end

%tt{1}=permute(tt{1},[(1:s),s+2,s+1]);

return
end


function polys = meshFacePolygons(varargin)
%MESHFACEPOLYGONS Returns the set of polygons that constitutes a mesh.
%
%   POLYGONS = meshFacePolygons(V, F)
%   POLYGONS = meshFacePolygons(MESH)
%
%   Example
%     [v f] = createCubeOctahedron;
%     polygons = meshFacePolygons(v, f);
%     areas = polygonArea3d(polygons);
%     sum(areas)
%     ans =
%         18.9282
%
%   See also
%     meshes3d, meshFace, polygonArea3d

% ------
% Author: David Legland
% e-mail: david.legland@grignon.inra.fr
% Created: 2013-08-20,    using Matlab 7.9.0.529 (R2009b)
% Copyright 2013 INRA - Cepia Software Platform.

% extract vertices and faces
[v, f] = parseMeshData(varargin{:});

% number of faces
if iscell(f)
    nFaces = length(f);
else
    nFaces = size(f, 1);
end

% allocate cell array for result
polys = cell(nFaces, 1);

% compute polygon corresponding to each face
if iscell(f)
    for i = 1:nFaces
        polys{i} = v(f{i}, :);
    end
else
    for i = 1:nFaces
        polys{i} = v(f(i,:), :);
    end
end


function data = montage_image_Worsley(image_name, varargin)
% ::
%
%    data = montage_image_Worsley(3D or 4D image name)
%
% Make a compact montage of some images
% Designed by Keith Worsley for pca_image.m
% Adapted by Tor Wager, Feb 2008
%
% Limits and Colormap are designed for component loadings between [-1 1]
%
% :Examples:
% ::
%
%    create_figure('Montage');
%    montage_image_Worsley('test_run1_pca.img');
%
%    data = montage_image_Worsley(imgname, 'pcacov')  % changes scaling and colormap
%    data = montage_image_Worsley(imgname, 'pcacov', [1 3 5])  % show only
%                                                           volumes 1, 3, 5 in image(s)

% ..
%    COPYRIGHT:   Copyright 2002 K.J. Worsley,
%              Department of Mathematics and Statistics,
%              McConnell Brain Imaging Center,
%              Montreal Neurological Institute,
%              McGill University, Montreal, Quebec, Canada.
%              worsley@math.mcgill.ca
%
%              Permission to use, copy, modify, and distribute this
%              software and its documentation for any purpose and without
%              fee is hereby granted, provided that this copyright
%              notice appears in all copies. The author and McGill University
%              make no representations about the suitability of this
%              software for any purpose.  It is provided "as is" without
%              express or implied warranty.
% ..
%
% ..
%    Tor Wager
% ..

scaletype = 'pcacor';  % Scale image and colors for PCA component viewing
whichvols = [];

for i = 1:length(varargin)
        if ischar(varargin{i})
            switch varargin{i}
                % reserved keywords
                case 'noscale', scaletype = 'none';

                case 'pcacov', scaletype = 'pcacov';

                case 'whichvols', whichvols = varargin{i + 1};

                otherwise, warning(['Unknown input string option:' varargin{i}]);
            end
        end
end

% Get data
% -------------------------------------------------------------------------
image_name = expand_4d_filenames(image_name); % for SPM2 compatibility
V = spm_vol(image_name);

if isempty(whichvols)
    wh_vols = 1:length(V);

else
    % select only certain vols
    V = V(wh_vols);
end

p = length(V);
go_ok = 1;
if p > 10
    go_ok = input('More than 10 images! Are you sure you want to continue?');
end
if ~go_ok, return, end

data = spm_read_vols(V);

% Setup stuff
% -------------------------------------------------------------------------

numslices = V(1).dim(3);
% p = num comps
numys=V(1).dim(2);
numxs=V(1).dim(1);
   xr=1:numxs;
   yr=1:numys;
   %N=prod(V(1).dim(1:3));

nrow=round(sqrt(numslices/3.25/p));
nrow=max(nrow,1);

ncol=ceil(numslices/nrow);

numxr=length(xr);
numyr=length(yr);
bigmat=zeros(p*nrow*numyr,ncol*numxr);

% Create big mat
% -------------------------------------------------------------------------
r=0;
for k=1:p
   c=0;
   for i=1:numslices
      bigmat((1:numyr)+r*numyr,(1:numxr)+c*numxr)=flipud(data(xr,yr,i,k)');
      c=c+1;
      if c>=ncol && i<numslices
         r=r+1;
         c=0;
      end
   end
   r=r+1;
end
xtick=((1:ncol*numxr)-1)/(ncol*numxr-1)*ncol-0.5;
ytick=((1:p*nrow*numyr)-1)/(p*nrow*numyr-1)*p+0.5;

switch scaletype
    case 'pcacor'
        zlim=[-1 1]; % [min(bigmat(:)) max(bigmat(:))];
    case 'pcacov'
        sdbm = nanstd(data(:));
        if(sdbm == 0)
            warning('Std dev of 0!');
            zlim = [-3 3];
        else
            zlim = [-3*sdbm 3*sdbm];
        end

    otherwise
        zlim = [min(bigmat(:)) max(bigmat(:))];
end

%
% Make image
% -------------------------------------------------------------------------
imagesc(xtick,ytick,bigmat,zlim);
xlabel('Slice (0 based)'); ylabel('Component');
switch scaletype
    case {'pcacor', 'pcacov'}
        title('Spatial components');
    otherwise
end
%colormap(spectral); colorbar;

set(gca,'YDir','Reverse')

% tor colormap stuff
% -------------------------------------------------------------------------
switch scaletype
    case {'pcacor'}
    cmap = colormap_tor([0 0 0], [1 1 0], [0 0 1], [0 1 1], [.5 .5 .5], [1 .4 .4], [1 0 0]);
    case {'pcacov'}
       cmap = colormap_tor([0 0 .5], [1 1 0], [0 0 1], [0 1 1], [0 0 0], [1 .4 .4], [1 0 0]);

    otherwise
     cmap = colormap_tor([0 0 0], [1 1 0], [0 0 1], [0 1 1], [.5 .5 .5], [1 .4 .4], [1 0 0]);
end
colormap(cmap)
colorbar('vert')

axis tight

end


%% Copyright (C) 2014-2022 Colin B. Macdonald
%%
%% This file is part of OctSymPy.
%%
%% OctSymPy is free software; you can redistribute it and/or modify
%% it under the terms of the GNU General Public License as published
%% by the Free Software Foundation; either version 3 of the License,
%% or (at your option) any later version.
%%
%% This software is distributed in the hope that it will be useful,
%% but WITHOUT ANY WARRANTY; without even the implied warranty
%% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
%% the GNU General Public License for more details.
%%
%% You should have received a copy of the GNU General Public
%% License along with this software; see the file COPYING.
%% If not, see <http://www.gnu.org/licenses/>.

%% -*- texinfo -*-
%% @documentencoding UTF-8
%% @defmethod @@sym erfc (@var{x})
%% Symbolic erfc function.
%%
%% Example:
%% @example
%% @group
%% syms x
%% y = erfc (x)
%%   @result{} y = (sym) erfc(x)
%% @end group
%% @end example
%%
%% Note: this file is autogenerated: if you want to edit it, you might
%% want to make changes to 'generate_functions.py' instead.
%%
%% @end defmethod

function y = erfc(x)
  if (nargin ~= 1)
    print_usage ();
  end
  y = elementwise_op ('erfc', x);
end

%!error erfc (sym(1), 2)
%!assert (isequaln (erfc (sym(nan)), sym(nan)))

%!shared x, d
%! d = 1;
%! x = sym('1');

%!test
%! f1 = erfc(x);
%! f2 = erfc(d);
%! assert( abs(double(f1) - f2) < 1e-15 )

%!test
%! D = [d d; d d];
%! A = [x x; x x];
%! f1 = erfc(A);
%! f2 = erfc(D);
%! assert( all(all( abs(double(f1) - f2) < 1e-15 )))

%!test
%! % round trip
%! y = sym('y');
%! A = erfc (d);
%! f = erfc (y);
%! h = function_handle (f);
%! B = h (d);
%! assert (A, B, -eps)


% THIS SOFTWARE AND ANY ACCOMPANYING DOCUMENTATION IS RELEASED "AS IS."  THE U.S. GOVERNMENT MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, CONCERNING THIS SOFTWARE AND ANY ACCOMPANYING DOCUMENTATION, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT WILL THE U.S. GOVERNMENT BE LIABLE FOR ANY DAMAGES, INCLUDING ANY LOST PROFITS, LOST SAVINGS OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE, OR INABILITY TO USE, THIS SOFTWARE OR ANY ACCOMPANYING DOCUMENTATION, EVEN IF INFORMED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.
%
% file: get_rate_diff_ci3.m
% computes confidence interval
%  - assumes x's are the number of successes in n Bernoulli trials
%  - finds confidence interval around the estimate for r1-r2
%  - with confidence level 1 - alpha
%  - finds a symmetrical two-sided interval, unless one side
%    would cross zero or one, in which case the interval is
%    offset.

% 030113 tdr created

function ci = get_rate_diff_ci3(x1,A1,x2,A2,alpha,method,verbose)
% balanced width

r1_hat = x1/A1; r2_hat = x2/A2; delta_r_hat = r1_hat - r2_hat;

tolerance = 1e-6;
max_count = 50;
count = 0;

%set limits on search for width
width_too_small = 0; width_too_big = 1e12;

%check that width_too_big is indeed too big
a = delta_r_hat - width_too_big; b = delta_r_hat + width_too_big;
lower_tail_contribution = 1- rate_diff(x1,A1,x2,A2,a);  upper_tail_contribution = rate_diff(x1,A1,x2,A2,b);
alpha_width_too_big = lower_tail_contribution + upper_tail_contribution;
if alpha_width_too_big > alpha, error('Failure to set upper bound on CI width'); end;

% set initial guess and corresponding alpha
width_guess = (width_too_big + width_too_small)/2;
a = delta_r_hat - width_guess; b = delta_r_hat + width_guess;
lower_tail_contribution = 1- rate_diff(x1,A1,x2,A2,a);  upper_tail_contribution = rate_diff(x1,A1,x2,A2,b);
alpha_guess = lower_tail_contribution + upper_tail_contribution;

% binary search
while (abs(alpha_guess - alpha) > tolerance & (count < max_count))
    if (alpha_guess < alpha)
        width_too_big = width_guess;
        width_guess = (width_too_small + width_guess)/2;
    else
        width_too_small = width_guess;
        width_guess = (width_too_big + width_guess)/2;
    end;
    count = count+1;
    a = delta_r_hat - width_guess;     b = delta_r_hat + width_guess;
    lower_tail_contribution = 1- rate_diff(x1,A1,x2,A2,a);  upper_tail_contribution = rate_diff(x1,A1,x2,A2,b);
    alpha_guess = lower_tail_contribution + upper_tail_contribution;
end;

ci = [delta_r_hat a b];


% Copyright 2011 Zdenek Kalal
%
% This file is part of TLD.
%
% TLD is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% TLD is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with TLD.  If not, see <http://www.gnu.org/licenses/>.

function ntuple = ntuples(varargin)
% Computes all possible ntupples.

x = varargin;

ntuple = x{1};
for i = 2:length(x)
    num_col  = size(ntuple,2);
    num_item = length(x{i});
    ntuple   = repcel(ntuple, 1, num_item);
    newline  = repmat(x{i},1,num_col);
    ntuple   = [ntuple;newline];
end


function forwardTransportQuantReverseFigures(model)
% Figure of the qualitatively forward transport reactions that are quantitatively reversible.
% Creates a vertical errorbar figure of the qualitatively forward transport reactions
% that are quantitatively reversible, whether from group contribution or
% Keq, that then need to be assigned to be forward, to limit the growth rate
% i.e. abc transporters or reactions involving protons.
%
% USAGE:
%
%    forwardTransportQuantReverseFigures(model)
%
% INPUT:
%    model:    structure with fields:
%
%                * .transportRxnBool
%                * .dGt0Min
%                * .dGt0Max
%                * .directions.forwardReversible
%
% .. Author: - Ronan M.T. Fleming

[nMet,nRxn]=size(model.S);

directions=model.directions;

%transport reactions
forwardTransportQuantReverseBool=false(nRxn,1);
for n=1:nRxn
    %if reaction directionality changed from forward to Reversible and als
    %a transport reaction
    if directions.forwardReversible(n) && model.transportRxnBool(n)
        %abc transporters or reactions involving protons
        if ~isempty(strfind(model.rxns{n},'abc')) ||  nnz(strcmp('h[c]',model.mets(model.S(:,n)~=0)))~=0 || nnz(strcmp('h[e]',model.mets(model.S(:,n)~=0)))~=0
            forwardTransportQuantReverseBool(n,1)=1;
        end
    end
end

if 0
    X1=1:nRxn;
    %dGrt0
    Y0=(model.DrGt0Min+model.DrGt0Max)/2;
    L0=Y0-model.DrGt0Min;
    U0=model.DrGt0Max-Y0;
    %dGrt
    Y=(model.DrdGtMin+model.DrGtMax)/2;
    L=Y-model.DrGtMin;
    U=model.DrGtMax-Y;
    %find the amount of reactions with normal cumulative distribution over
    %range of dGt0
    P = normcdf(0,Y0,L0);
else
    Y0=model.DrGt0Mean;
    L0=model.DrGt0Mean-model.DrGt0Min;
    U0=model.DrGt0Max-model.DrGt0Mean;

    Y=model.DrGtMean;
    L=model.DrGtMean-model.DrGtMin;
    U=model.DrGtMax-model.DrGtMean;
    P=directions.forwardProbability;
end
%sort by probability that a reaction is forward (puts any NaN first)
[tmp,xip]=sort(P,'descend');

%     only take the indices of the problematic reactions, but be sure to
%     take them in order of descending P
xip2=zeros(nnz(forwardTransportQuantReverseBool),1);
p=1;
for n=1:nRxn
    if forwardTransportQuantReverseBool(xip(n))
        xip2(p)=xip(n);
        p=p+1;
    end
end
xip=xip2;
X1=1:length(xip);

%replace the NaN due to zero st dev
forwardReversible_dGf_dG0Fwd=false(nRxn,1);
forwardReversible_dGf_dG0Rev=false(nRxn,1);
for n=1:nRxn
    %only the transport reactions
    if forwardTransportQuantReverseBool(n)
        if model.DrGt0Min(n)==model.DrGt0Max(n)
            if model.DrGt0Min(n)<0
                forwardReversible_dGf_dG0Fwd(n)=1;
            else
                forwardReversible_dGf_dG0Rev(n)=1;
            end
        end
    end
end
nNaNpLHS=nnz(forwardReversible_dGf_dG0Fwd);
nNaNpRHS=nnz( forwardReversible_dGf_dG0Rev);
if (nNaNpLHS+nNaNpRHS)~=nnz(isnan((P(forwardTransportQuantReverseBool))))
    warning('ExtraCategory');
end
%nans are first in the ordering of indexes
NaNPInd=xip(1:nNaNpLHS+nNaNpRHS);
%sorts indices of the zero std dev met by their mean dG0t
[tmp,xipNaNPInd]=sort(Y0(NaNPInd));
%new ordering
xip=[NaNPInd(xipNaNPInd(1:nNaNpLHS)); xip(nNaNpLHS+nNaNpRHS+1:end); NaNPInd(xipNaNPInd(nNaNpLHS+1:nNaNpLHS+nNaNpRHS))];

% close all
figure1 = figure;
% Create axes
axes1 = axes('Parent',figure1,'Color',[0.702 0.7804 1]);
hold on;

%upper and lower X
minX=min(model.DrGtMin(forwardTransportQuantReverseBool));
maxX=max(model.DrGtMax(forwardTransportQuantReverseBool));
%baselines
Y1(1:length(xip))=minX;
P(P==1)=NaN;
P(P==0.5)=NaN;
Y1(~isnan(P(xip)) & P(xip)~=1 & P(xip)~=0.5)=maxX;
bar_handle6=barh(X1,Y1,1,'BaseValue',minX,'FaceColor',[0.86 0.86 0.86],'EdgeColor','none');

%dGrt errorbar
%   PLOTERR(X,Y,{LX,UX},{LY,UY}) plots the graph of vector X vs. vector Y
%   with error bars specified by LX and UX in horizontal direction and
%   with error bars specified by LY and UY in vertical direction.
%   H = PLOTERR(...) returns a vector of line handles in this order:
%      H(1) = handle to datapoints
%      H(2) = handle to errorbar y OR errorbar x if error y not specified
%      H(3) = handle to errorbar x if error y specified
% LineSpec=[''LineStyle','none','LineWidth',2,'DisplayName','forwardReversible','Color','r'']
LineSpec='r.';
hE = ploterr(Y(xip),X1,{model.DrGtMin(xip) model.DrGtMax(xip)},[],LineSpec,'hhxy',0);
set(hE(2),'LineWidth',5);
% hE=errorbar(X1,Y(xip),L(xip),U(xip),'LineStyle','none','LineWidth',2,'DisplayName','forwardReversible','Color','r');
%dGrt0 errorbar on top and inside dGrt
LineSpec='b.';
hE = ploterr(Y0(xip),X1,{model.DrGt0Min(xip) model.DrGt0Max(xip)},[],LineSpec,'hhxy',0);
set(hE(2),'LineWidth',5);
% hE2=errorbar(X1,Y0(xip),L0(xip),U0(xip),'LineStyle','none','LineWidth',2,'DisplayName','forwardReversible','Color','b');

%mean dGrt0
plot(Y0(xip),X1,'.','LineStyle','none','Color',[0.3412 0.7961 0.1922]);
%zero line
%cumulative probability that reaction is really forward, assuming a
%normal distribution about the mean dGt0
[AX,H1,H2]=plotyy(zeros(1,length(X1)),X1,P(xip),X1);
set(gca,'XTick',[]);
set(AX(1),'XTickMode','manual','YTick',floor(minX/100)*200:50:maxX);%,'TickDirMode','manual','TickDir','out');
set(AX(2),'YTick',1:length(xip));
set(H1,'LineStyle','none')
set(H2,'LineStyle','-','LineWidth',2,'Color','k')
plot(zeros(1,length(X1)),X1,'w','LineWidth',2,'LineStyle','--');
%axis limits
set(AX(1),'FontSize',10,'YColor','k')
set(AX(1),'YTick',[],'YTickLabelMode','manual');
set(AX(1),'XTickMode','manual','XTick',floor(minX/100)*200:50:maxX);
set(get(AX(1),'Xlabel'),'String','\Delta_{r}G^{\primem}  (blue)    or     \Delta_{r}G^{\prime} (red) (kJ/mol)')
set(get(AX(1),'Xlabel'),'FontSize',10)
set(AX(1),'Position',[0.05 0.1 0.4 0.8]);
% axis(AX(1),[minX maxX 0 length(X1)+0.5 ]);
axis(AX(1),[-350 350 0 length(X1)+0.5 ]);

set(AX(2),'FontSize',10,'YColor','k')
set(AX(2),'YTick',1:length(X1),'YTickLabelMode','manual');
set(AX(2),'XAxisLocation','top');
set(get(AX(2),'Xlabel'),'String','P(\Delta_{r}G^{\primem}<0)');
set(get(AX(2),'Xlabel'),'FontSize',10);
axis(AX(2),[0 1 0.5 length(X1)+0.5 ]);
set(AX(2),'Position',[0.05 0.1 0.4 0.8]);

% ylabel('Reactions, sorted by P(\Delta_{r}G^{\primem}<0) (blue)');
title({'Qualitatively forward transport reactions, but quantitatively reversible'},'FontSize',16)

for n=1:length(xip)
%     textLen(n)=length(model.rxn(xip(n)).officialName)+length(model.rxn(xip(n)).equation);
%     textLen(n)=length(model.rxn(xip(n)).equation);
   textLen(n)=length(model.rxnNames{xip(n)});
end
textLenMax=max(textLen);
for n=1:length(xip)
    equation=printRxnFormula(model,model.rxns{xip(n)},0);
    YTickLabel{n}=[model.rxnNames{xip(n)} blanks(textLenMax-textLen(n)+5) equation{1}];
    %get rid of the cytoplasmic compartment abbreviations
    YTickLabel{n} = strrep(YTickLabel{n}, '[c]', '');
    YTickLabel{n} = strrep(YTickLabel{n}, '_', '\_');
end
set(AX(2),'YTickLabel',YTickLabel,'FontSize',10);
saveas(figure1 ,'forwardTransportQuantReverseBoolSetToForward','fig');


%% Simulation Data
simu = simulationClass();                   % Initialize Simulation Class
simu.simMechanicsFile = 'RM3.slx';          % Specify Simulink Model File
simu.rampTime = 100;                        % Wave Ramp Time [s]
simu.endTime=200;                           % Simulation End Time [s]
simu.dt = 0.1;                              % Simulation Time-Step [s]
simu.explorer = 'off';
simu.cicEndTime = 20;

%% Wave Information
% Irregular Waves using BS Spectrum with State Space Calculation
waves = waveClass('irregular');             % Initialize Wave Class and Specify Type
waves.height = 2.5;                              % Significant Wave Height [m]
waves.period = 8;                                % Peak Period [s]
waves.spectrumType = 'PM';                  % Specify Wave Spectrum Type
waves.phaseSeed = 1;

%% Body Data
% Float
body(1) = bodyClass('../../../../examples/RM3/hydroData/rm3.h5');
body(1).geometryFile = '../../../../examples/RM3/geometry/float.stl';
body(1).mass = 'equilibrium';
body(1).inertia = [20907301 21306090.66 37085481.11];

% Spar/Plate
body(2) = bodyClass('../../../../examples/RM3/hydroData/rm3.h5');
body(2).geometryFile = '../../../../examples/RM3/geometry/plate.stl';
body(2).mass = 'equilibrium';
body(2).inertia = [94419614.57 94407091.24 28542224.82];

%% PTO and Constraint Parameters
% Floating (3DOF) Joint
constraint(1) = constraintClass('Constraint1'); % Initialize Constraint Class for Constraint1
constraint(1).location = [0 0 0];                    % Constraint Location [m]

% Translational PTO
pto(1) = ptoClass('PTO1');                      % Initialize PTO Class for PTO1
pto(1).stiffness = 0;                                   % PTO Stiffness [N/m]
pto(1).damping = 1200000;                             % PTO Damping [N/(m/s)]
pto(1).location = [0 0 0];                           % PTO Location [m]


classdef LDClassifier < Algorithm

    properties (Access = public)
        shouldTrain = false;
    end

    properties (Access = private)
        classifier;
    end

    methods (Access = public)

        function obj = LDClassifier()
            obj.name = 'LinearDiscriminant';
            obj.inputPort = DataType.kTable;
            obj.outputPort = DataType.kTable;
        end

        function dataOut = compute(obj,data)
            if obj.shouldTrain
                obj.train(data);
                dataOut = [];
            else
                dataOut = obj.test(data);
            end
        end

        function train(obj,table)

            obj.classifier = fitcdiscr(...
                table.features, ...
                table.label, ...
                'DiscrimType', 'linear', ...
                'Gamma', 0, ...
                'FillCoeffs', 'off');
        end

        function metrics = computeMetrics(obj,table)
            flops = timeit(@()obj.test(table)) / Constants.kReferenceComputingTime;
            memory = Helper.ComputeObjectSize(obj.classifier);
            outputSize = table.height * Constants.kClassificationResultBytes;
            metrics = Metric(flops,memory,outputSize);
        end

        function labels = test(obj,table)
            labels = predict(obj.classifier,table.features);
        end

        function str = toString(obj)
            str = sprintf('%s',obj.name);
        end
    end
end


%
% Visualize the outcome of the skeleton extraction
% process for a set of characters.
%
nimg = 9;
load('data_background_processed','D');

nrow = ceil(sqrt(nimg));
figure(1)
clf;
list_I = cell(nrow,1);
list_T = cell(nrow,1);
for i=1:nimg
    I = D.get('image','random','random','random');
    T = extract_skeleton(I);
    subplot(nrow,nrow,i);
    viz_skel.plot_trace(I,T);
    fprintf(1,'image %d\n',i);

    list_I{i} = I;
    list_T{i} = T;
end


classdef MeshStructure
    %MeshStructure class
    % contains information about the domain and the mesh size

    properties
        dimension
        dims
        cellsize
        cellcenters
        facecenters
        corners
        edges
    end

    methods
        function meshVar = MeshStructure(dimension, dims, cellsize, ...
          cellcenters, facecenters, corners, edges)
            if nargin>0
                meshVar.dimension = dimension;
                meshVar.dims = dims;
                meshVar.cellsize = cellsize;
                meshVar.cellcenters = cellcenters;
                meshVar.facecenters = facecenters;
                meshVar.corners= corners;
                meshVar.edges= edges;
            end
        end
    end
end


function x = perform_histogram_equalization(x,y,options)

% perform_histogram_equalization - perform histogram equalization
%
%   x = perform_histogram_equalization(x,y,options);
%
%   Change the values of x so that its ordered values match
%   the ordered values of y.
%
%   You can set
%       options.cols=1 to operate along columns
%       options.rows=1 to operate along rows
%       options.absval to operate only on absolute values.
%
%   Copyright (c) 2006 Gabriel Peyr?

options.null = 0;

if isfield(options ,'absval')
    absval = options.absval;
else
    absval = 0;
end
if isfield(options ,'cols')
    cols = options.cols;
else
    cols = 0;
end
if isfield(options ,'rows')
    rows = options.rows;
else
    rows = 0;
end
if isfield(options, 'match_ycbcr')
    match_ycbcr = options.match_ycbcr;
else
    match_ycbcr = 1;
end

% for color images
if size(x,3)>1
    if size(x,3)~=size(y,3)
        error('x and y images must have the same number of components.');
    end

    if size(x,3)==3 && match_ycbcr
        x = rgb2ycbcr(x);
        y = rgb2ycbcr(y);
    end
    % match each color
    for i=1:3
        x(:,:,i) = perform_histogram_equalization(x(:,:,i), y(:,:,i), options);
    end
    if size(x,3)==3 && match_ycbcr
        x = ycbcr2rgb(x);
    end
    return;
end

if cols && rows
    error('You cannote specify both cols and rows');
end
if cols && size(x,2)>1
    if not(size(x,2)==size(y,2))
        error('x and y must have same number of columns');
    end
    for i=1:size(x,2)
        x(:,i) = perform_histogram_equalization(x(:,i),y(:,i),options);
    end
    return;
end
if rows && size(x,1)>1
    if not(size(x,1)==size(y,1))
        error('x and y must have same number of rows');
    end
    for i=1:size(x,1)
        x(i,:) = perform_histogram_equalization(x(i,:),y(i,:),options);
    end
    return;
end

sx = size(x);
x = x(:);
y = y(:);

if absval
    s = sign(x);
    x = abs(x);
    y = abs(y);
end

[vx,Ix] = sort(x);
[vy,Iy] = sort(y);

nx = length(x);
ny = length(y);

ax = linspace(1,ny,nx);
ay = 1:ny;
vx = interp1(ay,vy,ax);
x(Ix) = vx;

if absval
    x = x .* s;
end

x = reshape(x,sx);

function rgb = ycbcr2rgb(in)
%YCBCR2RGB Convert YCbCr values to RGB color space.
%   RGBMAP = YCBCR2RGB(YCBCRMAP) converts the YCbCr values in the
%   colormap YCBCRMAP to the RGB color space. If YCBCRMAP is M-by-3 and
%   contains the YCbCr luminance (Y) and chrominance (Cb and Cr) color
%   values as columns, then RGBMAP is an M-by-3 matrix that contains
%   the red, green, and blue values equivalent to those colors.
%
%   RGB = YCBCR2RGB(YCBCR) converts the YCbCr image to the equivalent
%   truecolor image RGB.
%
%   Class Support
%   -------------
%   If the input is a YCbCr image, it can be of class uint8, uint16,
%   or double; the output image is of the same class as the input
%   image.  If the input is a colormap, the input and output
%   colormaps are both of class double.
%
%   Example
%   -------
%   Convert image from RGB space to YCbCr space and back.
%
%       rgb = imread('board.tif');
%       ycbcr = rgb2ycbcr(rgb);
%       rgb2 = ycbcr2rgb(ycbcr);
%
%   See also NTSC2RGB, RGB2NTSC, RGB2YCBCR.

%   Copyright 1993-2003 The MathWorks, Inc.
%   $Revision: 1.15.4.2 $  $Date: 2003/08/23 05:54:51 $

%   Reference:
%     Charles A. Poynton, "A Technical Introduction to Digital Video",
%     John Wiley & Sons, Inc., 1996

%initialize variables
isColormap = false;
classin = class(in);

%must reshape colormap to be m x n x 3 for transformation
if (ndims(in)==2)
  %colormap
  isColormap=true;
  colors = size(in,1);
  in = reshape(in, [colors 1 3]);
end

%initialize output
rgb = in;

% set up constants for transformation. T alone will transform YCBCR in [0,255]
% to RGB in [0,1]. We must scale T and the offsets to get RGB in the appropriate
% range for uint8 and for uint16 arrays.
T = [65.481 128.553 24.966;...
     -37.797 -74.203 112; ...
     112 -93.786 -18.214];
Tinv = T^-1;
offset = [16;128;128];
Td = 255 * Tinv;
offsetd = Tinv * offset;
T8 = Td;
offset8 = T8 * offset;
T16 = (65535/257) * Tinv;
offset16 = 65535 * Tinv * offset;

switch classin
 case 'double'
  for p = 1:3
    rgb(:,:,p) = Td(p,1) * in(:,:,1) + Td(p,2) * in(:,:,2) + ...
        Td(p,3) * in(:,:,3) - offsetd(p);
  end

 case 'uint8'
  for p = 1:3
    rgb(:,:,p) = imlincomb(T8(p,1),in(:,:,1),T8(p,2),in(:,:,2), ...
                           T8(p,3),in(:,:,3),-offset8(p));
  end

 case 'uint16'
  for p = 1:3
    rgb(:,:,p) = imlincomb(T16(p,1),in(:,:,1),T16(p,2),in(:,:,2), ...
                           T16(p,3),in(:,:,3),-offset16(p));
  end
end

if isColormap
   rgb = reshape(rgb, [colors 3 1]);
end

if isa(rgb,'double')
  rgb = min(max(rgb,0.0),1.0);
end

%%%
%Parse Inputs
%%%
function X = parse_inputs(varargin)

checknargin(1,1,nargin,mfilename);
X = varargin{1};

if ndims(X)==2
  checkinput(X,{'uint8','uint16','double'},'real nonempty',mfilename,'MAP',1);
  if (size(X,2) ~=3 || size(X,1) < 1)
    eid = sprintf('Images:%s:invalidSizeForColormap',mfilename);
    msg = 'MAP must be a m x 3 array.';
    error(eid,'%s',msg);
  end
elseif ndims(X)==3
  checkinput(X,{'uint8','uint16','double'},'real',mfilename,'RGB',1);
  if (size(X,3) ~=3)
    eid = sprintf('Images:%s:invalidTruecolorImage',mfilename);
    msg = 'RGB must a m x n x 3 array.';
    error(eid,'%s',msg);
  end
else
  eid = sprintf('Images:%s:invalidInputSize',mfilename);
  msg = ['RGB2GRAY only accepts two-dimensional or three-dimensional ' ...
         'inputs.'];
  error(eid,'%s',msg);
end

function out = rgb2ycbcr(in)
%RGB2YCBCR Convert RGB values to YCBCR color space.
%   YCBCRMAP = RGB2YCBCR(MAP) converts the RGB values in MAP to
%   the YCBCR color space.  YCBCRMAP is a M-by-3 matrix that contains
%   the YCBCR luminance (Y) and chrominance (Cb and Cr) color values as
%   columns.  Each row represents the equivalent color to the
%   corresponding row in the RGB colormap.
%
%   YCBCR = RGB2YCBCR(RGB) converts the truecolor image RGB to the
%   equivalent image in the YCBCR color space.
%
%   Class Support
%   -------------
%   If the input is an RGB image, it can be of class uint8, uint16,
%   or double; the output image is of the same class as the input
%   image.  If the input is a colormap, the input and output colormaps
%   are both of class double.
%
%   Examples
%   --------
%   Convert RGB image to YCbCr.
%
%      RGB = imread('board.tif');
%      YCBCR = rgb2ycbcr(RGB);
%
%   Convert RGB color space to YCbCr.
%
%      map = jet(256);
%      newmap = rgb2ycbcr(map);

%   See also NTSC2RGB, RGB2NTSC, YCBCR2RGB.

%   Copyright 1993-2003 The MathWorks, Inc.
%   $Revision: 1.13.4.2 $  $Date: 2003/08/23 05:54:37 $

%   Reference:
%     C.A. Poynton, "A Technical Introduction to Digital Video", John Wiley
%     & Sons, Inc., 1996, p. 175

%initialize variables
isColormap = false;
classin = class(in);

%must reshape colormap to be m x n x 3 for transformation
if (ndims(in)==2)
  %colormap
  isColormap=true;
  colors = size(in,1);
  in = reshape(in, [colors 1 3]);
end

% set up constants for transformation
T = [65.481 128.553 24.966;...
     -37.797 -74.203 112; ...
     112 -93.786 -18.214];
offset = [16;128;128];
offset16 = 257 * offset;
fac8 = 1/255;
fac16 = 257/65535;

%initialize output
out = in;

% do transformation
switch classin
 case 'uint8'
  for p=1:3
    out(:,:,p) = imlincomb(T(p,1)*fac8,in(:,:,1),T(p,2)*fac8,in(:,:,2),...
                         T(p,3)*fac8,in(:,:,3),offset(p));
  end
 case 'uint16'
  for p=1:3
    out(:,:,p) = imlincomb(T(p,1)*fac16,in(:,:,1),T(p,2)*fac16,in(:,:,2),...
                         T(p,3)*fac16,in(:,:,3),offset16(p));
  end
 case 'double'
  % These equations transform RGB in [0,1] to YCBCR in [0, 255]
  for p=1:3
    out(:,:,p) =  T(p,1) * in(:,:,1) + T(p,2) * in(:,:,2) + T(p,3) * ...
        in(:,:,3) + offset(p);
  end
  out = out / 255;
end

if isColormap
   out = reshape(out, [colors 3 1]);
end


function fiff_write_double_complex_matrix(fid,kind,mat)
%
% fiff_write_double_complex_matrix(fid,kind,mat)
%
% Writes a double-precision complex matrix tag
%
%     fid           An open fif file descriptor
%     kind          The tag kind
%     mat           The data matrix
%

%
%
%   Author : Matti Hamalainen, MGH Martinos Center
%   License : BSD 3-clause
%
%   Revision 1.1  2006/09/23 14:43:56  msh
%   Added routines for writing complex and double complex matrices.
%   Added routine for writing double-precision real matrix.
%
%

me='MNE:fiff_write_double_complex_matrix';

if nargin ~= 3
        error(me,'Incorrect number of arguments');
end

FIFFT_COMPLEX_DOUBLE = 21;
FIFFT_MATRIX  = bitshift(1,30);
FIFFT_MATRIX_COMPLEX_DOUBLE = bitor(FIFFT_COMPLEX_DOUBLE,FIFFT_MATRIX);
FIFFV_NEXT_SEQ=0;

datasize = 2*8*numel(mat) + 4*3;

count = fwrite(fid,int32(kind),'int32');
if count ~= 1
    error(me,'write failed');
end
count = fwrite(fid,int32(FIFFT_MATRIX_COMPLEX_DOUBLE),'int32');
if count ~= 1
    error(me,'write failed');
end
count = fwrite(fid,int32(datasize),'int32');
if count ~= 1
    error(me,'write failed');
end
count = fwrite(fid,int32(FIFFV_NEXT_SEQ),'int32');
if count ~= 1
   error(me,'write failed');
end
nrow = size(mat,1);
ncol = size(mat,2);
for j = 1:nrow
   for k = 1:ncol
      count = fwrite(fid,real(mat(j,k)),'double');
      if count ~= 1
          error(me,'write failed');
      end
      count = fwrite(fid,imag(mat(j,k)),'double');
      if count ~= 1
          error(me,'write failed');
      end
   end
end
dims(1) = size(mat,2);
dims(2) = size(mat,1);
dims(3) = 2;
count = fwrite(fid,int32(dims),'int32');
if count ~= 3
    error(me,'write failed');
end

return;


function [varargout]=meshView(varargin)

% function [varargout]=meshView(varargin)
% ------------------------------------------------------------------------
% 2018/01/23 Updated to allow for subfigure plotting
% 2018/04/16 Added control of direction of cutting (X,Y, or Z) and also
% what side is viewed/cut away.
% 2019/09/07 Fixed bug in relation to single element/face input
% 2019/09/07 Updated handling of cutting direction
% ------------------------------------------------------------------------
%% Parse input

switch nargin
    case 1
        meshStruct=varargin{1};
        optionStruct=[];
    case 2
        meshStruct=varargin{1};
        optionStruct=varargin{2};
    otherwise
        error('Wrong number of input arguments');
end

defaultOptionStruct.hFig=[];
defaultOptionStruct.numSliceSteps=25; %Number of animation steps
defaultOptionStruct.cMap=[];
defaultOptionStruct.cutDir=2;
defaultOptionStruct.cutSide=1;
defaultOptionStruct.faceAlpha1=0.2;
defaultOptionStruct.faceAlpha2=1;
defaultOptionStruct.lightWeightPlot=1;
defaultOptionStruct.edgeWidth=1;
defaultOptionStruct.edgeColor='k';
[optionStruct]=structComplete(optionStruct,defaultOptionStruct,0);

%% Get control parameters

figHandles=optionStruct.hFig;
if ~isempty(figHandles)
    hFig=figHandles(1);
    if numel(figHandles)==2
        hSub=figHandles(2);
    else
        hSub=[];
    end
else
    hFig=[];
    hSub=[];
end

numSliceSteps=optionStruct.numSliceSteps;
cMap=optionStruct.cMap;
cutDir=optionStruct.cutDir;
cutSide=optionStruct.cutSide;
faceAlpha1=optionStruct.faceAlpha1;
faceAlpha2=optionStruct.faceAlpha2;
lightWeightPlot=optionStruct.lightWeightPlot;
edgeWidth=optionStruct.edgeWidth;
edgeColor=optionStruct.edgeColor;
fontSize=15;

%% Access mesh data

%                 nodes: [415×3 double]
%         facesBoundary: [320×3 double]
%        boundaryMarker: [320×1 double]
%                 faces: [8144×3 double]
%              elements: [2036×4 double]
%     elementMaterialID: [2036×1 double]
%        faceMaterialID: [8144×1 double]
%        loadNameStruct: [1×1 struct]

E=meshStruct.elements;
V=meshStruct.nodes;

if isfield(meshStruct,'facesBoundary')
    Fb=meshStruct.facesBoundary;
    Cb=meshStruct.boundaryMarker;
else
    F=meshStruct.faces;
    indBoundary=tesBoundary(F);
    Fb=F(indBoundary,:);
    Cb=ones(size(Fb,1),1);
end

if isfield(meshStruct,'elementData')
    CE=meshStruct.elementData;
    numColormapLevels=250;
elseif isfield(meshStruct,'elementMaterialID')
    CE=meshStruct.elementMaterialID;
    numColormapLevels=numel(unique(CE(:)));
else
    CE=ones(size(E,1),1);
    numColormapLevels=250;
end

if isempty(cMap)
    cMap=gjet(numColormapLevels);
end

%%
% prepare figure
if isempty(hFig)
    hFig=cFigure; %Store figure handle
    title('Cut view of mesh','FontSize',fontSize);
end

figure(hFig);
if ~isempty(hSub)
    subplot(hSub);
end
hold on;

if ~isempty(Fb)
    gpatch(Fb,V,0.5*ones(1,3),'none',faceAlpha1);
end

hp=gpatch(Fb,V,Cb,edgeColor,faceAlpha2,edgeWidth); %Graphics object to vary property of during animation

camlight headlight;
axisGeom(gca,fontSize);

if abs(max(CE(:))-min(CE(:)))>eps(1)
    caxis([min(CE(:)) max(CE(:))]);
end

colormap(gca,cMap);
if ~isfield(meshStruct,'elementData')
    icolorbar;
else
    colorbar;
end

%%
% Set up animation

[VE]=patchCentre(E,V);
XE=VE(:,cutDir);
animStruct.Time=linspace(0,1,numSliceSteps); %Time vector
cutLevel=linspace(min(XE)-max(eps(XE)),max(XE)+max(eps(XE)),numSliceSteps); %Property to set

for q=1:1:numSliceSteps %Step through time
    cutLevelNow=cutLevel(q); %The current cut level

    if cutSide==1
        logicCutView=XE>=cutLevelNow;
    elseif cutSide==-1
        logicCutView=XE<=cutLevelNow;
    end

    [Fs,Cs]=element2patch(E(logicCutView,:),CE(logicCutView));

    if lightWeightPlot==1
        [indBoundary]=tesBoundary(Fs);
        Fs=Fs(indBoundary,:);
        Cs=Cs(indBoundary,:);
    end

    %Set entries in animation structure
    animStruct.Handles{q}=[hp hp]; %Handles of objects to animate
    animStruct.Props{q}={'Faces','CData'}; %Properties of objects to animate
    animStruct.Set{q}={Fs,Cs}; %Property values for to set in order to animate
end

%Add animation layer
anim8(hFig,animStruct);
set(hFig.UserData.anim8.sliderHandles{1},'Value',round(numSliceSteps/2)); %Set to middle
gdrawnow;

%% Collect output

switch nargout
    case 1
        varargout{1}=hFig;
    case 2
        varargout{1}=hFig;
        varargout{2}=hp;
end

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


function x = p30_start ( n )

%*****************************************************************************80
%
%% P30_START returns a starting point for optimization for problem 30.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    08 January 2001
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the number of variables X.
%
%    Output, real X(N), a starting point for the optimization.
%
  x = [ -1.0, 1.0 ]';

  return
end


%sim_dDiv.m
%Jamie Near, 2020.
%
% USAGE:
% d_out = sim_dDiv(d_in,factor)
%
% DESCRIPTION:
% Divide a density matrix by a scalar.  This function is necessary becuase
% the density matrix is a cell array, so cannot be scaled using simple
% division.
%
% INPUTS:
% d_in      = input density matrix to be divided.
% factor    = scalar factor to divide by.
%
% OUTPUTS:
% d_out     = output, result of d_in/factor.

function d_out = sim_dDiv(d_in,factor)

d_out=cell(size(d_in));
for m=1:length(d_in)
    d_out{m}=d_in{m}./factor;
end


function [params, names] = ggwhiteKernExtractParam(kern)

% GGWHITEKERNEXTRACTPARAM Extract parameters from the GG WHITE kernel structure.
% FORMAT
% DESC Extract parameters from the gaussian
%	gaussian white kernel structure into a vector of parameters for optimisation.
% RETURN param : vector of parameters extracted from the kernel. If the
%	   field 'transforms' is not empty in the kernel matrix, the
%	   parameters will be transformed before optimisation (for example
%	   positive only parameters could be logged before being returned).
% ARG kern : the kernel structure containing the parameters to be
%	   extracted.
%
% FORMAT
% DESC extract parameters and
%	their names from the gaussian gaussian white kernel structure.
% RETURN param : vector of parameters extracted from the kernel. If the
%	   field 'transforms' is not empty in the kernel matrix, the
%	   parameters will be transformed before optimisation (for example
%	   positive only parameters could be logged before being returned).
% RETURN names : cell array of strings containing parameter names.
% ARG kern : the kernel structure containing the parameters to be
%	   extracted.
%
% SEEALSO : ggwhiteKernParamInit, ggwhiteKernExpandParam, kernExtractParam, scg,
% conjgrad
%
% COPYRIGHT : Mauricio A. Alvarez and Neil D. Lawrence, 2008
%
% MODIFICATIONS : Mauricio A Alvarez, 2009

% KERN

params = [kern.precisionG' kern.sigma2Noise kern.variance];

if nargout > 1
    if kern.isArd
        ynames = cell(1,kern.inputDimension);
        for i=1:kern.inputDimension,
            ynames{i}=['inverse width output ' num2str(i) '.'];
        end
        names = {ynames{:}, 'variance latent', 'sensitivity'};
    else
        names = {'inverse width output 1.' , 'variance latent', 'sensitivity'};
    end
end


function varargout = trimMesh(varargin)
%TRIMMESH Reduce memory footprint of a polygonal mesh.
%
%   [V2, F2] = trimMesh(V, F)
%   Unreferenced vertices are removed.
%   Following functions are implemented for only numeric faces:
%       Duplicate vertices are removed.
%       Duplicate faces are removed.
%
%   Example
%     [V, F] = createIcosahedron;
%     F(13:20, :) = [];
%     [V2, F2] = trimMesh(V, F);
%     figure; drawMesh(V2, F2)
%     view(3); axis equal;
%     axis([-1 1 -1 1 0 2])
%
%   See also
%     meshes3d, clipMeshVertices

% ------
% Author: David Legland, oqilipo
% e-mail: david.legland@inra.fr
% Created: 2014-08-01,    using Matlab 8.3.0.532 (R2014a)
% Copyright 2014 INRA - Cepia Software Platform.

% parse input data
[vertices, faces] = parseMeshData(varargin{:});

if isnumeric(faces)
    % Delete duplicate vertices
    [tempVertices, ~, tempFaceVertexIdx] = unique(vertices, 'rows');
    tempFaces = tempFaceVertexIdx(faces);
    % Delete unindexed/unreferenced vertices
    usedVertexIdx = ismember(1:length(tempVertices),unique(tempFaces(:)));
    newVertexIdx = cumsum(usedVertexIdx);
    faceVertexIdx = 1:length(tempVertices);
    faceVertexIdx(usedVertexIdx) = newVertexIdx(usedVertexIdx);
    faceVertexIdx(~usedVertexIdx) = nan;
    tempFaces2 = faceVertexIdx(tempFaces);
    tempVertices2 = tempVertices(usedVertexIdx,:);
    % Delete duplicate faces
    [~, uniqueFaceIdx, ~] = unique(tempFaces2, 'rows');
    duplicateFaceIdx=~ismember(1:size(tempFaces2,1),uniqueFaceIdx);
    [vertices2, faces2] = removeMeshFaces(tempVertices2, tempFaces2, duplicateFaceIdx);
elseif iscell(faces)
    % identify vertices referenced by a face
    vertexUsed = false(size(vertices, 1), 1);
    for iFace = 1:length(faces)
        face = faces{iFace};
        vertexUsed(face) = true;
    end
    vertices2 = vertices(vertexUsed, :);
    % compute map from old index to new index
    inds = find(vertexUsed);
    newInds = zeros(size(vertices, 1), 1);
    for iIndex = 1:length(inds)
        newInds(inds(iIndex)) = iIndex;
    end
    % change labels of vertices referenced by faces
    faces2 = cell(1, length(faces));
    for iFace = 1:length(faces)
        faces2{iFace} = newInds(faces{iFace});
    end
else
    error('Unsupported format!')
end

% format output arguments
varargout = formatMeshOutput(nargout, vertices2, faces2);


function rgb3d=label2rgb3d(varargin)
[label,map,zerocolor,order,fcnflag] = parse_inputs(varargin{:});
%label= 3d image with labels
% map= specified color map
%==================================
numregion = double(max(label(:)));

% If MAP is a function, evaluate it.  Make sure that the evaluated function
% returns a valid colormap.
if  fcnflag == 1
    cmap = feval(map, numregion);
    if ~isreal(cmap) || any(cmap(:) > 1) || any(cmap(:) < 0) || ...
            ~isequal(size(cmap,2),3) || size(cmap,1) < 1
        eid = sprintf('Images:%s:functionReturnsInvalidColormap',mfilename);
        msg = 'function handle MAP must return a n x 3 colormap array';
        error(eid,'%s',msg);
    end
else
    cmap = map;
end

% If ORDER is set to 'shuffle', save original state.  The SHUFFLE keyword
% uses the same state every time it is called. After shuffling is completed,
% go back to original state.
if isequal(order,'shuffle')
    S = rand('state');
    rand('state', 0);
    index = randperm(numregion);
    cmap = cmap(index,:,:);
    rand('state', S);
end

% Issue a warning if the zerocolor (boundary color) matches the color of one
% of the regions.
for i=1:numregion
  if isequal(zerocolor,cmap(i,:))
    wid= sprintf('Images:%s:zerocolorSameAsRegionColor',mfilename);
    msg= sprintf('Region number %d has the same color as the ZEROCOLOR.',i);
    warning(wid,'%s',msg);
  end
end
cmap = [zerocolor;cmap];

% if label is of type double, need to pass 'label + 1' into IND2RGB.
% IND2RGB does not like double arrays containing zero values.
if isa(label, 'double')
    rgb3d = ind2rgb3d(label + 1, cmap);
else
    rgb3d = ind2rgb3d(label, cmap);
end

%======================================================================
%======================================================================
function [L, Map, Zerocolor, Order, Fcnflag] = parse_inputs(varargin)
% L         label 3d matrix: matrix containing non-negative values.
% Map       colormap: name of standard colormap, user-defined map, function
%           handle.
% Zerocolor RGB triple or Colorspec
% Order     keyword if specified: 'shuffle' or 'noshuffle'
% Fcnflag   flag to indicating that Map is a function

valid_order = {'shuffle', 'noshuffle'};
iptchecknargin(1,4,nargin,mfilename);

% set defaults
L = varargin{1};
Map = 'jet';
Zerocolor = [1 1 1];
Order = 'noshuffle';
Fcnflag = 0;

% parse inputs
if nargin > 1
    Map = varargin{2};
end
if nargin > 2
    Zerocolor = varargin{3};
end
if nargin > 3
    Order = varargin{4};
end

% error checking for L
iptcheckinput(L,{'numeric' 'logical'}, ...
              {'real' 'nonsparse' 'finite' 'nonnegative' 'integer'}, ...
              mfilename,'L',1);

% error checking for Map
[fcn, fcnchk_msg] = fcnchk(Map);
if isempty(fcnchk_msg)
    Map = fcn;
    Fcnflag = 1;
else
    if isnumeric(Map)
        if ~isreal(Map) || any(Map(:) > 1) || any(Map(:) < 0) || ...
                    ~isequal(size(Map,2), 3) || size(Map,1) < 1
          eid = sprintf('Images:%s:invalidColormap',mfilename);
          msg = 'Invalid entry for MAP.';
          error(eid,'%s',msg);
        end
    else
        eid = sprintf('Images:%s:invalidFunctionforMAP',mfilename);
        error(eid,'%s',fcnchk_msg);
    end
end

% error checking for Zerocolor
if ~ischar(Zerocolor)
    % check if Zerocolor is a RGB triple
    if ~isreal(Zerocolor) || ~isequal(size(Zerocolor),[1 3]) || ...
                any(Zerocolor> 1) || any(Zerocolor < 0)
      eid = sprintf('Images:%s:invalidZerocolor',mfilename);
      msg = 'Invalid RGB triple entry for ZEROCOLOR.';
      error(eid,'%s',msg);
    end
else
    [cspec, msg] = cspecchk(Zerocolor);
    if ~isempty(msg)
        eid = sprintf('Images:%s:notInColorspec',mfilename);
        error(eid,'%s',msg);
    else
        Zerocolor = cspec;
    end
end

% error checking for Order
idx = strmatch(lower(Order), valid_order);
eid = sprintf('Images:%s:invalidEntryForOrder',mfilename);
if isempty(idx)
    msg = 'Valid entries for ORDER are ''shuffle'' or ''noshuffle''.';
    error(eid,'%s',msg);
elseif length(idx) > 1
    msg = sprintf('Ambiguous string for ORDER: %s.', Order);
    error(eid,'%s',msg);
else
    Order = valid_order{idx};
end

%================================================================
%=================================================================
function [rout,g,b] = ind2rgb3d(a,cm)
%IND2RGB Convert indexed image to RGB image.
%   RGB = IND2RGB(X,MAP) converts the 3d matrix X and corresponding
%   colormap MAP to RGB (truecolor) format.
%
%   Class Support
%   -------------
%   X can be of class uint8, uint16, or double. RGB is an
%   M-by-N-by-3 array of class double.
%
%   See also IND2GRAY, RGB2IND (in the Image Processing Toolbox).

if ~isa(a, 'double')
    a = double(a)+1;    % Switch to one based indexing
end

error(nargchk(2,2,nargin));

% Make sure A is in the range from 1 to size(cm,1)
a = max(1,min(a,size(cm,1)));

% Extract r,g,b components
r = zeros(size(a)); r(:) = cm(a,1);
g = zeros(size(a)); g(:) = cm(a,2);
b = zeros(size(a)); b(:) = cm(a,3);

if nargout==3,
  rout = r;
else
  rout = zeros([size(r),3]);
  rout(:,:,:,1) = r;
  rout(:,:,:,2) = g;
  rout(:,:,:,3) = b;
end


%% Copyright (C) 2019 Colin B. Macdonald
%%
%% This file is part of OctSymPy.
%%
%% OctSymPy is free software; you can redistribute it and/or modify
%% it under the terms of the GNU General Public License as published
%% by the Free Software Foundation; either version 3 of the License,
%% or (at your option) any later version.
%%
%% This software is distributed in the hope that it will be useful,
%% but WITHOUT ANY WARRANTY; without even the implied warranty
%% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
%% the GNU General Public License for more details.
%%
%% You should have received a copy of the GNU General Public
%% License along with this software; see the file COPYING.
%% If not, see <http://www.gnu.org/licenses/>.

%% -*- texinfo -*-
%% @documentencoding UTF-8
%% @defmethod  @@sym ezmesh (@var{z})
%% @defmethodx @@sym ezmesh (@var{f1}, @var{f2}, @var{f3})
%% @defmethodx @@sym ezmesh (@dots{}, @var{dom})
%% @defmethodx @@sym ezmesh (@dots{}, @var{N})
%% Simple 3D wireframe mesh plots of symbolic expressions.
%%
%% Example 3D surface mesh plot:
%% @example
%% @group
%% syms x y
%% z = sin(2*x)*sin(y)
%%   @result{} z = (sym) sin(2⋅x)⋅sin(y)
%% ezmesh(z)                                    % doctest: +SKIP
%% @end group
%% @end example
%%
%% Example parametric mesh of a Möbius strip:
%% @example
%% @group
%% syms u v
%% x = (1+v*cos(u/2))*cos(u)
%%   @result{} x = (sym)
%%       ⎛     ⎛u⎞    ⎞
%%       ⎜v⋅cos⎜─⎟ + 1⎟⋅cos(u)
%%       ⎝     ⎝2⎠    ⎠
%% y = (1+v*cos(u/2))*sin(u);
%% z = v*sin(u/2);
%%
%% ezmesh(x, y, z, [0 2*pi -0.5 0.5], 32)       % doctest: +SKIP
%% axis equal
%% @end group
%% @end example
%%
%% See help for the (non-symbolic) @code{ezmesh}, which this
%% routine calls after trying to convert sym inputs to
%% anonymous functions.
%%
%% @seealso{ezmesh, @@sym/ezsurf, @@sym/ezplot, @@sym/function_handle}
%% @end defmethod

function varargout = ezmesh(varargin)

  % first input is handle, shift
  if (ishandle(varargin{1}))
    firstpotsym = 2;
  else
    firstpotsym = 1;
  end

  maxnumsym = 3;
  firstsym = [];

  for i = firstpotsym:nargin
    if (isa(varargin{i}, 'sym'))
      if (i < firstpotsym + maxnumsym)
        % one of the fcns to plot, covert to handle fcn

        % Each is function of one var, and its the same var for all
        thissym = symvar(varargin{i});
        assert(length(thissym) <= 2, ...
          'ezmesh: parameterized: functions should have at most two inputs');
        if (isempty(thissym))
          % a number, create a constant function in a dummy variable
          % (0*t works around some Octave oddity on 3.8 and hg Dec 2014)
          thisf = inline(sprintf('%g + 0*t', double(varargin{i})), 't');
          %thisf = @(t) 0*t + double(varargin{i});  % no
        else
          % check variables match (sanity check)
          if (isempty(firstsym))
            firstsym = thissym;
          else
            assert(all(logical(thissym == firstsym)), ...
              'ezmesh: all functions must be in terms of the same variables');
          end
          thisf = function_handle(varargin{i});
        end

        varargin{i} = thisf;

      else
        % plot ranges, etc, convert syms to doubles
        varargin{i} = double(varargin{i});
      end
    end
  end

  h = ezmesh(varargin{:});

  if (nargout)
    varargout{1} = h;
  end

end

%!error <all functions must be in terms of the same variables>
%! syms u v t
%! ezmesh(u*v, 2*u*v, 3*v*t)

%!error <functions should have at most two inputs>
%! syms u v t
%! ezmesh(u*v, 2*u*v, u*v*t)


function [CM]=fourthOrderMat(C)

ind_C_all=1:numel(C);
[I,J,K,L]=ind2sub(size(C),ind_C_all);

%Create the 9x9 matrix indices
p=3*(I-1)+K;
q=3*(J-1)+L;

%Treat posible symbolic class
switch class(C)
    case 'sym'
        CM=sym(zeros(9,9));
    otherwise
        CM=zeros(9,9);
end

%Set values
[ind_pq]=sub2ind(size(CM),p,q);
CM(ind_pq(:))=C(:);

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


% complete pipeline for calcium imaging data pre-processing
clear;
addpath(genpath('../NoRMCorre'));               % add the NoRMCorre motion correction package to MATLAB path
gcp;                                            % start a parallel engine
foldername = '';
         % folder where all the files are located.
filetype = 'tif'; % type of files to be processed
        % Types currently supported .tif/.tiff, .h5/.hdf5, .raw, .avi, and .mat files
files = subdir(fullfile(foldername,['*.',filetype]));   % list of filenames (will search all subdirectories)
FOV = size(read_file(files(1).name,1,1));
numFiles = length(files);

%% motion correct (and save registered h5 files as 2d matrices (to be used in the end)..)
% register files one by one. use template obtained from file n to
% initialize template of file n + 1;

motion_correct = true;                            % perform motion correction
non_rigid = true;                                 % flag for non-rigid motion correction
output_type = 'h5';                               % format to save registered files

if non_rigid; append = '_nr'; else; append = '_rig'; end        % use this to save motion corrected files

options_mc = NoRMCorreSetParms('d1',FOV(1),'d2',FOV(2),'grid_size',[128,128],'init_batch',200,...
                'overlap_pre',32,'mot_uf',4,'bin_width',200,'max_shift',24,'max_dev',8,'us_fac',50,...
                'output_type',output_type);

template = [];
col_shift = [];
for i = 1:numFiles
    fullname = files(i).name;
    [folder_name,file_name,ext] = fileparts(fullname);
    output_filename = fullfile(folder_name,[file_name,append,'.',output_type]);
    options_mc = NoRMCorreSetParms(options_mc,'output_filename',output_filename,'h5_filename','','tiff_filename',''); % update output file name
    if motion_correct
        [M,shifts,template,options_mc,col_shift] = normcorre_batch_even(fullname,options_mc,template);
        save(fullfile(folder_name,[file_name,'_shifts',append,'.mat']),'shifts','-v7.3');           % save shifts of each file at the respective folder
    else    % if files are already motion corrected convert them to h5
        convert_file(fullname,'h5',fullfile(folder_name,[file_name,'_mc.h5']));
    end
end

%% downsample h5 files and save into a single memory mapped matlab file

if motion_correct
    registered_files = subdir(fullfile(foldername,['*',append,'.',output_type]));  % list of registered files (modify this to list all the motion corrected files you need to process)
else
    registered_files = subdir(fullfile(foldername,'*_mc.h5'));
end

fr = 30;                                         % frame rate
tsub = 5;                                        % degree of downsampling (for 30Hz imaging rate you can try also larger, e.g. 8-10)
ds_filename = [foldername,'/ds_data.mat'];
data_type = class(read_file(registered_files(1).name,1,1));
data = matfile(ds_filename,'Writable',true);
data.Y  = zeros([FOV,0],data_type);
data.Yr = zeros([prod(FOV),0],data_type);
data.sizY = [FOV,0];
F_dark = Inf;                                    % dark fluorescence (min of all data)
batch_size = 2000;                               % read chunks of that size
batch_size = round(batch_size/tsub)*tsub;        % make sure batch_size is divisble by tsub
Ts = zeros(numFiles,1);                          % store length of each file
cnt = 0;                                         % number of frames processed so far
tt1 = tic;
for i = 1:numFiles
    name = registered_files(i).name;
    info = h5info(name);
    dims = info.Datasets.Dataspace.Size;
    ndimsY = length(dims);                       % number of dimensions (data array might be already reshaped)
    Ts(i) = dims(end);
    Ysub = zeros(FOV(1),FOV(2),floor(Ts(i)/tsub),data_type);
    data.Y(FOV(1),FOV(2),sum(floor(Ts/tsub))) = zeros(1,data_type);
    data.Yr(prod(FOV),sum(floor(Ts/tsub))) = zeros(1,data_type);
    cnt_sub = 0;
    for t = 1:batch_size:Ts(i)
        Y = read_file(name,t,min(batch_size,Ts(i)-t+1));
        F_dark = min(nanmin(Y(:)),F_dark);
        ln = size(Y,ndimsY);
        Y = reshape(Y,[FOV,ln]);
        Y = cast(downsample_data(Y,'time',tsub),data_type);
        ln = size(Y,3);
        Ysub(:,:,cnt_sub+1:cnt_sub+ln) = Y;
        cnt_sub = cnt_sub + ln;
    end
    data.Y(:,:,cnt+1:cnt+cnt_sub) = Ysub;
    data.Yr(:,cnt+1:cnt+cnt_sub) = reshape(Ysub,[],cnt_sub);
    toc(tt1);
    cnt = cnt + cnt_sub;
    data.sizY(1,3) = cnt;
end
data.F_dark = F_dark;
%% now run CNMF on patches on the downsampled file, set parameters first

sizY = data.sizY;                       % size of data matrix
patch_size = [40,40];                   % size of each patch along each dimension (optional, default: [32,32])
overlap = [8,8];                        % amount of overlap in each dimension (optional, default: [4,4])

patches = construct_patches(sizY(1:end-1),patch_size,overlap);
K = 7;                                            % number of components to be found
tau = 8;                                          % std of gaussian kernel (half size of neuron)
p = 2;                                            % order of autoregressive system (p = 0 no dynamics, p=1 just decay, p = 2, both rise and decay)
merge_thr = 0.8;                                  % merging threshold
sizY = data.sizY;

options = CNMFSetParms(...
    'd1',sizY(1),'d2',sizY(2),...
    'deconv_method','constrained_foopsi',...    % neural activity deconvolution method
    'p',p,...                                   % order of calcium dynamics
    'ssub',2,...                                % spatial downsampling when processing
    'tsub',2,...                                % further temporal downsampling when processing
    'merge_thr',merge_thr,...                   % merging threshold
    'gSig',tau,...
    'max_size_thr',300,'min_size_thr',10,...    % max/min acceptable size for each component
    'spatial_method','regularized',...          % method for updating spatial components
    'df_prctile',50,...                         % take the median of background fluorescence to compute baseline fluorescence
    'fr',fr/tsub,...                            % downsamples
    'space_thresh',0.35,...                     % space correlation acceptance threshold
    'min_SNR',2.0,...                           % trace SNR acceptance threshold
    'cnn_thr',0.2,...                           % cnn classifier acceptance threshold
    'nb',1,...                                  % number of background components per patch
    'gnb',3,...                                 % number of global background components
    'decay_time',0.5...                         % length of typical transient for the indicator used
    );

%% Run on patches (the main work is done here)

[A,b,C,f,S,P,RESULTS,YrA] = run_CNMF_patches(data.Y,K,patches,tau,0,options);  % do not perform deconvolution here since
                                                                               % we are operating on downsampled data
%% compute correlation image on a small sample of the data (optional - for visualization purposes)
Cn = correlation_image_max(data,8);

%% classify components

rval_space = classify_comp_corr(data,A,C,b,f,options);
ind_corr = rval_space > options.space_thresh;           % components that pass the correlation test
                                                        % this test will keep processes

%% further classification with cnn_classifier
try  % matlab 2017b or later is needed
    [ind_cnn,value] = cnn_classifier(A,FOV,'cnn_model',options.cnn_thr);
catch
    ind_cnn = true(size(A,2),1);                        % components that pass the CNN classifier
end

%% event exceptionality

fitness = compute_event_exceptionality(C+YrA,options.N_samples_exc,options.robust_std);
ind_exc = (fitness < options.min_fitness);

%% select components

keep = (ind_corr | ind_cnn) & ind_exc;

%% run GUI for modifying component selection (optional, close twice to save values)
% run_GUI = false;
% if run_GUI
%     Coor = plot_contours(A,Cn,options,1); close;
%     GUIout = ROI_GUI(A,options,Cn,Coor,keep,ROIvars);
%     options = GUIout{2};
%     keep = GUIout{3};
% end

%% view contour plots of selected and rejected components (optional)
throw = ~keep;
Coor_k = [];
Coor_t = [];
figure;
    ax1 = subplot(121); plot_contours(A(:,keep),Cn,options,0,[],Coor_k,[],1,find(keep)); title('Selected components','fontweight','bold','fontsize',14);
    ax2 = subplot(122); plot_contours(A(:,throw),Cn,options,0,[],Coor_t,[],1,find(throw));title('Rejected components','fontweight','bold','fontsize',14);
    linkaxes([ax1,ax2],'xy')

%% keep only the active components

A_keep = A(:,keep);
C_keep = C(keep,:);

%% extract residual signals for each trace

if exist('YrA','var')
    R_keep = YrA(keep,:);
else
    R_keep = compute_residuals(data,A_keep,b,C_keep,f);
end

%% extract fluorescence on native temporal resolution

options.fr = options.fr*tsub;                   % revert to origingal frame rate
N = size(C_keep,1);                             % total number of components
T = sum(Ts);                                    % total number of timesteps
C_full = imresize(C_keep,[N,T]);                % upsample to original frame rate
R_full = imresize(R_keep,[N,T]);                % upsample to original frame rate
F_full = C_full + R_full;                       % full fluorescence
f_full = imresize(f,[size(f,1),T]);             % upsample temporal background

S_full = zeros(N,T);

P.p = 0;
ind_T = [0;cumsum(Ts(:))];
options.nb = options.gnb;
for i = 1:numFiles
    inds = ind_T(i)+1:ind_T(i+1);   % indeces of file i to be updated
    [C_full(:,inds),f_full(:,inds),~,~,R_full(:,inds)] = update_temporal_components_fast(registered_files(i).name,A_keep,b,C_full(:,inds),f_full(:,inds),P,options);
    disp(['Extracting raw fluorescence at native frame rate. File ',num2str(i),' out of ',num2str(numFiles),' finished processing.'])
end

%% extract DF/F and deconvolve DF/F traces

[F_dff,F0] = detrend_df_f(A_keep,[b,ones(prod(FOV),1)],C_full,[f_full;-double(F_dark)*ones(1,T)],R_full,options);

C_dec = zeros(N,T);         % deconvolved DF/F traces
S_dec = zeros(N,T);         % deconvolved neural activity
bl = zeros(N,1);            % baseline for each trace (should be close to zero since traces are DF/F)
neuron_sn = zeros(N,1);     % noise level at each trace
g = cell(N,1);              % discrete time constants for each trace
if p == 1; model_ar = 'ar1'; elseif p == 2; model_ar = 'ar2'; else; error('This order of dynamics is not supported'); end

for i = 1:N
    spkmin = options.spk_SNR*GetSn(F_dff(i,:));
    lam = choose_lambda(exp(-1/(options.fr*options.decay_time)),GetSn(F_dff(i,:)),options.lam_pr);
    [cc,spk,opts_oasis] = deconvolveCa(F_dff(i,:),model_ar,'method','thresholded','optimize_pars',true,'maxIter',20,...
                                'window',150,'lambda',lam,'smin',spkmin);
    bl(i) = opts_oasis.b;
    C_dec(i,:) = cc(:)' + bl(i);
    S_dec(i,:) = spk(:);
    neuron_sn(i) = opts_oasis.sn;
    g{i} = opts_oasis.pars(:)';
    disp(['Performing deconvolution. Trace ',num2str(i),' out of ',num2str(N),' finished processing.'])
end


% SP_EVAL_BOUNDARY_SIDE: Construct the space structure of one side of the boundary.
%
%     sp_side = sp_eval_boundary_side (sp, msh_side)
%
% INPUTS:
%
%     sp:       space object (see sp_scalar)
%     msh_side: mesh structure containing the information of the quadrature
%               rule on the boundary edge (see msh_cartesian/msh_eval_boundary_side)
%
% OUTPUT:
%
%     sp_side: structure that contains the following fields
%              (see the article for a detailed description)
%
%     FIELD_NAME      (SIZE)                                   DESCRIPTION
%     ncomp           (scalar)                                 number of components of the functions of the space (actually, 1)
%     nsh_max         (scalar)                                 maximum number of shape functions per element
%     nsh             (1 x msh_side.nel vector)                actual number of shape functions per each element
%     ndof            (scalar)                                 total number of degrees of freedom
%     connectivity    (nsh_max x msh_side.nel vector)          indices of basis functions that do not vanish in each element
%     shape_functions (msh_side.nqn x nsh_max x msh_side.nel)  basis functions evaluated at each quadrature node in each element
%     dofs            (1 x ndof vector)                        numbering of the degrees of freedom in the volumetric space
%
% Copyright (C) 2009, 2010 Carlo de Falco
% Copyright (C) 2011, 2015 Rafael Vazquez
%
%    This program is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.

%    This program is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with this program.  If not, see <http://www.gnu.org/licenses/>.

function sp_side = sp_eval_boundary_side (sp, msh_side)

  iside = msh_side.side_number;
  sp_side = sp_precompute (sp.boundary(iside), msh_side);

end


function line = edgeToLine(edge)
%EDGETOLINE Convert an edge to a straight line
%
%   LINE = edgeToLine(EDGE);
%   Returns the line containing the edge EDGE.
%
%   Example
%       edge = [2 3 4 5];
%       line = edgeToLine(edge);
%       figure(1); hold on; axis([0 10 0 10]);
%       drawLine(line, 'color', 'g')
%       drawEdge(edge, 'linewidth', 2)
%
%   See also
%   edges2d, lines2d
%
% ------
% Author: David Legland
% e-mail: david.legland@grignon.inra.fr
% Created: 2009-07-23,    using Matlab 7.7.0.471 (R2008b)
% Copyright 2009 INRA - Cepia Software Platform.

line = [edge(:, 1:2) edge(:, 3:4)-edge(:, 1:2)];


% PQ_TOP queries for the topmost element of the priority queue (not removing it)
%
% SYNTAX
% [idx, cost] = pq_top(pq)
%
% INPUT PARAMETERS
%   pq: a pointer to the priority queue
%
% OUTPUT PARAMETERS
%   idx: the index of the topmost element
%   cost: the cost of the topmost element
%
% DESCRIPTION
% Queries the topmost element from a priority queue returning its
% index and associated cost.
%
% See also:
% PQ_DEMO, PQ_CREATE, PQ_PUSH, PQ_POP, PQ_SIZE, PQ_TOP, PQ_DELETE
%
% References:
% Gormen, T.H. and Leiserson, C.E. and Rivest, R.L., "introduction to
% algorithms", 1990, MIT Press/McGraw-Hill, Chapter 6.

% Copyright (c) 2008 Andrea Tagliasacchi
% All Rights Reserved
% email: andrea.tagliasacchi@gmail.com
% $Revision: 1.0$  Created on: May 22, 2009


function [splitPsi, logQ] = getSplitConfig_SeqAllocation( Psi, data_struct, hyperparams, model, anchorObjIDs, featIDs, TargetPsi )

if ~exist( 'TargetPsi', 'var' )
    TargetPsi = [];
end

if isfield( Psi, 'theta' );
    Psi = rmfield( Psi, 'theta');
    Psi = rmfield( Psi, 'TS');
end
nObj = size(Psi.F,1);
logQ = struct( 'F', 0, 'z', 0 );

obsModel = model.obsModel;

ii = anchorObjIDs(1);
jj = anchorObjIDs(2);

kold = featIDs(1);

otherFeatIDs = setdiff( 1:size(Psi.F,2), featIDs );

otherObjIDs = setdiff( find( Psi.F( :, kold ) > 0   )', anchorObjIDs );
allObjIDs = [anchorObjIDs otherObjIDs];

kA = size(Psi.F,2) + 1;
kB = size(Psi.F,2) + 2;
propFeatIDs = [kA kB];

propF = Psi.F;
propF(:, [kold] ) = 0;
propF(ii, [kA kB] ) = [1 0];
propF(jj, [kA kB] ) = [0 1];

% First, draw starting value for theta from sequence ii and jj
propStateSeq = Psi.stateSeq;
propStateSeq( ii ).z(  propStateSeq( ii ).z == kold )  = kA;
propStateSeq( jj ).z(  propStateSeq( jj ).z == kold )  = kB;

% Create deterministic trans params Eta
propTS = getEta_PriorMean( propF, [], hyperparams, model, allObjIDs, propFeatIDs );

% Create deterministic Theta for ALL features: others + [kA kB]
[Xstats] = getXSuffStats( propF, propStateSeq, data_struct, model, 1:nObj, [otherFeatIDs propFeatIDs] );
myTheta = setThetaToPosteriorMean( [], Xstats, obsModel, [otherFeatIDs propFeatIDs] );

if exist( 'TargetPsi', 'var' ) && ~isempty( TargetPsi )
    TargetPsi.externalFeatIDs = propFeatIDs;
end

% Keep *only* the params for the feature kA, kB being split
%   this is all we update
AXstats  = getXSuffStats( propF, propStateSeq, data_struct, model, [ii jj], [propFeatIDs] );

% Initialize some key sufficient stats
featCounts = sum( propF( anchorObjIDs, propFeatIDs ), 1 );
nObj = length( anchorObjIDs );
counter=0;

for aa = [ otherObjIDs( randperm(length(otherObjIDs)) ) ii jj]
    counter=counter+1;

    if aa == ii || aa == jj
        % Make sure to update F suff. stats for anchors
        %  since we've already "seen" them before, unlike other sequences
        featCounts = featCounts - propF(aa, propFeatIDs);
        nObj = nObj - 1;

        Xdelta = getXSuffStats( propF, propStateSeq, data_struct, model, aa, propFeatIDs );
        AXstats = decXStats( AXstats, Xdelta, model.obsModel );
    end

    % Calc Soft Evidence for the current sequence, including both new feats
    curFeatIDs = find( propF(aa,:));
    allPropFeatIDs = union( curFeatIDs, propFeatIDs );
    LL = calcLogCondPrObsGivenTheta( data_struct(aa), myTheta, obsModel, allPropFeatIDs, size(propF,2) );

    % Propose new feature assignments for the cur. seq.
    myFPr = featCounts ./ ( nObj + hyperparams.c );
    [newFaa, logQ_Faa] = sampleFfromRestrictedSet( aa, anchorObjIDs, LL, propFeatIDs, propTS.obj( aa ), myFPr, TargetPsi );
    propF(aa, propFeatIDs) = newFaa;

    % Keep track of probability of making this specific proposal
    logQ.F = logQ.F + logQ_Faa;

    % In case we chose not to include one of the proposed new split feats,
    %   we need to remove that feature's transition weights from propTS
    %   and also remove that feature's entries in soft ev. matrix LL
    availFeatIDs = propTS.obj(aa).availFeatIDs;
    kiloc = find( availFeatIDs == propFeatIDs(1) );
    kjloc = find( availFeatIDs == propFeatIDs(2) );
    switch ( newFaa * [10;1] )
        case 01
            keepIDs = [1:kiloc-1 kiloc+1:length(availFeatIDs)];
        case 10
            keepIDs = [1:kjloc-1 kjloc+1:length(availFeatIDs)];
        case 11
            keepIDs = 1:length(availFeatIDs);
    end
    curEta.availFeatIDs = propTS.obj(aa).availFeatIDs( keepIDs );
    curEta.pi_z = propTS.obj(aa).pi_z( keepIDs, keepIDs );
    activeFeatIDs = union( curFeatIDs, propFeatIDs(newFaa==1) );
    activeLL = LL( activeFeatIDs, : );

    % Propose new State Seq for current sequence
    %[propStateSeq, logQaa] = sampleZ_RGS(data_struct, propTS, propF, myTheta, obsModel, propStateSeq, aa, TargetPsi);
    [propStateSeq(aa).z, logPrQ_z] = sampleStateSeq_PrecompSoftEv( aa, curEta, activeLL, TargetPsi);
    logQ.z = logQ.z + logPrQ_z;

    % Update suff. stats for F sampling
    featCounts = featCounts + propF(aa, propFeatIDs);
    nObj = nObj + 1;

    % Update Emission Params for new proposed features
    %   using the newly allocated data from the current sequence
    Xdelta = getXSuffStats( propF, propStateSeq, data_struct, model, aa, propFeatIDs );
    AXstats = incXStats( AXstats, Xdelta, model.obsModel );
    myTheta = setThetaToPosteriorMean( myTheta, AXstats, obsModel, [propFeatIDs] );

end

% Record final launch state
splitPsi.F = propF;
splitPsi.stateSeq = propStateSeq;
splitPsi.activeFeatIDs = propFeatIDs;
splitPsi.anchorObjIDs  = anchorObjIDs;
end


classdef TestInitUndistortRectifyMap
    %TestInitUndistortRectifyMap

    methods (Static)
        function test_1
            camMat = eye(3);
            distCoeffs = zeros(1,4);
            sz = [50 100];  % [w,h]
            [map1,map2] = cv.initUndistortRectifyMap(...
                camMat, distCoeffs, sz, 'M1Type','int16', ...
                'NewCameraMatrix',camMat, 'R',eye(3));
            validateattributes(map1, {'int16'}, {'size',[sz(2) sz(1) 2]});
            validateattributes(map2, {'uint16'}, {'size',[sz(2) sz(1)]});
        end

        function test_2
            camMat = eye(3);
            distCoeffs = zeros(1,4);
            sz = [50 100];  % [w,h]
            [map1,map2] = cv.initUndistortRectifyMap(...
                camMat, distCoeffs, sz, 'M1Type','single1');
            validateattributes(map1, {'single'}, {'size',[sz(2) sz(1)]});
            validateattributes(map2, {'single'}, {'size',[sz(2) sz(1)]});
        end

        function test_3
            camMat = eye(3);
            distCoeffs = zeros(1,4);
            sz = [50 100];  % [w,h]
            [map1,map2] = cv.initUndistortRectifyMap(...
                camMat, distCoeffs, sz, 'M1Type','single2');
            validateattributes(map1, {'single'}, {'size',[sz(2) sz(1) 2]});
            assert(isempty(map2));
        end

        function test_error_argnum
            try
                cv.initUndistortRectifyMap();
                throw('UnitTest:Fail');
            catch e
                assert(strcmp(e.identifier,'mexopencv:error'));
            end
        end
    end

end


function sliceThicknessV = deduceSliceWidths(planC,scanNum)
%function sliceThicknessV = deduceSliceWidths(planC)
%
%This function deduces slice thicknesses when the treatment planning system
%provides only z Values.
%
%
%Created:  30 Apr 03, JOD.
% copyright (c) 2001-2006, Washington University in St. Louis.
% Permission is granted to use or modify only for non-commercial,
% non-treatment-decision applications, and further only if this header is
% not removed from any file. No warranty is expressed or implied for any
% use whatever: use at your own risk.  Users can request use of CERR for
% institutional review board-approved protocols.  Commercial users can
% request a license.  Contact Joe Deasy for more information
% (radonc.wustl.edu@jdeasy, reversed).
indexS = planC{end};

zValuesV = [planC{indexS.scan}(scanNum).scanInfo(:).zValue];

sliceThicknessV = ones(size(zValuesV)) * nan;

for i = 2 : length(zValuesV) - 1
  nextDelta = abs(zValuesV(i+1) - zValuesV(i));
  sliceThicknessV(i) = nextDelta;
end
if length(zValuesV) > 1
    sliceThicknessV(1) = 2 * (abs(zValuesV(2) - zValuesV(1)) - 0.5 * sliceThicknessV(2));
    sliceThicknessV(end) = 2 * (abs(zValuesV(end) - zValuesV(end - 1)) - 0.5 * sliceThicknessV(end - 1));
end