%% Simplicial Complex in Two Dimensions
%
% We dsecribe the data structure of the simplicial complex associated to a
% two dimensional trianglulation give by |node,elem| . The |node| records
% the coordinates of vertices and |elem| is the pointer from local to
% global incices of vertices. See <meshdoc.html meshdoc> for details.
%
% A brief summary of ordering and orientation
%
% * edge: asecond ordering, i.e. edge(:,1)<edge(:,2)
%
% * elem: positive ordering or ascend ordering. The default one is positive
% ordering and the asecond ordering is used for edge elements.
%
% * local edge:
%   consistent orientation [2 3; 3 1; 1 2];
%   asecond orientation    [2 3; 1 3; 1 2];
% The default one is the consistent orientation which will be
% counter-clockwise if elem is positive ordered. The asecond orientation
% will be used for edge elements.
%
% * elem2edgeSign: records the inconsistency of the edge
%  orientation and the induced orientation.
%
% Local edge is the induced orientation [2 3; 3 1; 1 2].
%  elem2edgeSign(1:NT,1:4) records the elementwise inconsistency of local
%  edge orientation and global edge orientation. It can be obtained from
%  |dofedge|. This is used to correct the consistency of the local basis
%  with the global basis.
%
% Both elem and local edges are ascend ordering. Then elem2edgeSign =
%  [1 -1 1] records the inconsistency of the edge orientation and the
%  induced orientation. This is used to construct differential operators.
%
% Function to call
%
%  [elem2edge,edge,elem2edgeSign,edgeSign] = dofedge(elem);
%
% Functions to read on the usage
%
%  PoissonRT0;

%%
% The basic data structure of a mesh consists of node and elem:
node = [0,0; 1,0; 1,1; 0,1];    % nodes
elem = [2,3,1; 4,1,3];          % elements
%%
% In iFEM, |N, NE, NT| represents the muber of vertice, edges, triangles
% respectively.
%
N = size(node,1); NT = size(elem,1); % NE = size(edge,1);

%%
% The corresponding simplicial complex consists of vertices, edges and
% triangles. We shall discuss the following three issues:
%
% * *Indexing* of simplexes
% * *Ordering* of vertices of simplexes
% * *Orientatoin* of simplexes
%
% The indexing and ordering are related and the ordering and orientation
% are mixed together. However the indexing has nothing to do with the
% orientation. The indexing and ordering are the combinarotry structure,
% i.e. only |elem| is needed, while the orientation also depends on |node|,
% the geometry emembdding of vertices.
%
% For indexing, ordering and orientation, there are always local and global
% version. The relation between the local and global version is the most
% complicated issue.

%% Indexing of Simplexes
%
% The indexing refers to the numbering of simplexes, e.g., which edge is
% numbered as the first one. There are two types of the indexing: local and
% global. Each simplex in the simplicial complex has a unique index which
% is called the global index. In one triangle, the three vertices and three
% edges have their local index from 1:3.
%
% In the assembling procedure of finite element methods, an element-wise
% matrix using local indexing is first computed and then assembled to get a
% big matrix using global indexing. Thus the pointer from the local
% indexing to the global indexing is indispensible. For bases independent of
% the ordering and orientation, e.g., |P1| and |P2| elements, the pointer
% is sufficient, otherwise, the inconsistency of local ordering/orientation
% and global ordering/orientation should be taken into account.
%
% *Indexing pointers of vertices*
%
% The |NT| by 3 matrix |elem| is indeed the pointer from the local to the
% global indices of vertices of triangles. For example |elem(t,1)=25| means
% the first vertex of the triangle t is the 25-th vertex.
%
% Similiary, the |NE| by 2 matrix |edge| records the pointer from the local
% to the global indices of vertices of edges.
%
% *Local indexing of edges*
%
% The triangle constists of three vertices indexed as [1,2,3]. Each
% triangle contains three edges. There are two indexing schemes for edges.
%
% * Opposite indexing     |locEdge = [2,3; 3,1; 1,2]|
%
% In |locEdge|, the |i-th| edge is opposite to the |i-th| verices and thus
% called _opposite indexing_.
%
% * Lexicogrphic indexing |locEdgel = [1,2; 1,3; 2,3]|
%
% In |locEdgel|, the indexing is induced from the lexicographic ordering of
% the three edges.
%
% For 2-D triangulations, *we shall always chose opposite indexing*. The
% lexicographic indexing is mainly used in the construction of |face2edge|
% of 3-D triangulations; see <sc3doc.html Simplicial Complex in Three
% Dimensions> for details. Note that the ordering of vertices of each edge
% will not change the indexing. For example, |locEdge = [2,3; 1,3; 1,2]|
% use the same opposite indexing but different ordering. Chosing |[1 3]| or
% |[3 1]| for the second edge will depend on the consideration of
% orientation and ordering.
%
% *Global indexing of edges*
%
% One can easily collect all edges elementwise. The issue is the
% duplication. For example, each interior edge will be counted twice. The
% |unique| funciton is applied such that each edge has a unique global
% index.
%
totalEdge = uint32([elem(:,[2,3]); elem(:,[3,1]); elem(:,[1,2])]);
sortedTotalEdge = sort(totalEdge,2);
[edge,tempvar,je] = unique(sortedTotalEdge,'rows');
NE = size(edge,1);
%%
% *Edge pointer*
%
% |elem2edge(1:NT,1:3)| records the pointer from the local index to the
% global index of edges. For example, |elem2edge(t,1)| = 10 means the first
% edge of triangle |t| (which is formed by [2 3] vertices of |t|) is the
% |10-th| one in the |edge| array.
%
% Such information is stored in the third output of |unique| function.
%%
elem2edge = uint32(reshape(je,NT,3));
%%
% Note that the pointer |elem2edge| depends on the local indexing of edges
% used in the generation of |totalEdge|. Here the opposite indexing of
% three local edges is used.

%% Ordering of Vertices
%
% We discuss the ordering of vertices of simplexes. Again there are local
% ordering and global ordering. They may not be consistent and a sign array
% is used to record the inconsistency if any.
%
% The local ordering refers to the ordering of local veritces of a simplex.
% The local ordering could be used in the formulation of the local basis
% and thus the ordering does matter.
%
% The global ordering refers to the ordering of the global index of
% vertices of a simplex.
%
% *elem*. The local ordering is always [1,2,3]. Any permutation of three
% veritces of a triangle still represents the same triangle. Such
% freedom provide a room to record more information like:
%
% * global ordering of vertices
% * orientation of triangles
% * refinement rule
%
% Two types of ordering of |elem| is of particular importance
%
% * Positive ordering
% * Ascend ordering
%
% In the positive ordering, the three vertices are ordered such that the
% signed area, det(v12,v13), is positive. If |elem| is not positive
% ordered, |elem = fixorder(node,elem)| will compute the signed area by
% |simplexvolume(node,elem)| and switch the vertices for triangles with
% negative areas.
%
% For 2-D triangulations, three vertices of a triangle in 2-D is sorted
% counter-cloclwise and the first vertex is chosen as the newest vertex.
% Such ordering enables the efficient implementation of local refinement
% and coarsening in 2-D; see <bisectdoc.html Bisection in Two Dimensions>
% and <coarsendoc.html Coarsening in Two Dimensions>. *Such ordering scheme
% is the default choice and used in most places*.
%
%
% In ascend ordering, the vertices of |elem| is sorted such that
% |elem(t,1)<elem(t,2)<elem(t,3)|. This can be easily achieved by |elem =
% sort(elem,2)|. Howevery, one has to rotate the boundary flag
% accordingly using |sortelem|.
bdFlag = setboundary(node,elem,'Dirichlet');
display('Before rotation'); display(elem); display(bdFlag);

[elem,bdFlag] = sortelem(elem,bdFlag);
display('After rotation'); display(elem); display(bdFlag);

%%
% Ascend ordering will benefit the construction of local bases for high
% order basis or basis with orientation.
%
% We may switch the default positive ordering of |elem| to ascend ordering
% when generating data structure for finite element basis. However such
% sorting is always hidden in the subroutines when a finite element basis
% requiring ordering is generated; see |PoissonRT0| and |PoissonBDM1|.

%%
% *edge*. The global ordering of edges is always ascended, i.e.
edge(:,1) < edge(:,2);
%%
% Indeed in the generation of |edge|, the |totalEdge| is sorted to the
% ascend ordering such that |unique| can be applied.
%%
%
% Recall that we always use the opposite indexing of edges. We could use
% _ascend ordering_ , i.e.
locEdge = [2 3; 1 3; 1 2]; % Ascend ordering of local edges
%%
% or the _consistent (orientation) ordering_
locEdge = [2 3; 3 1; 1 2]; % Consistent ordering of local edges
%%
% It is consistent since the local ordering orientation of edges is
% consistent with the induced orientation of the three edges; see the
% discussion on the orientation.
%
% There might be an inconsistency between the local and global ordering
% (even for the consistent orientation ordering). That is
% |edge(elem2edge(t,1),1)| may not be smaller than
% |edge(elem2edge(t,1),2)|. It will be more clear from the discussion of
% the corresponding orientation.

%% Orientation of Simplexes
%
% The orientation of a triangle is either positive or negative, the
% orientation of an edge is given by a tangential or normal vector. A
% normal vector is obtained by rotate a given tangential vector by 90
% degree clockwise. For example, when edges are given counter clockwise
% orientation, the corresponding normal vector is the outwards normal
% vector.
%
% The orientation of a d-simplex will induce an orientation of its d-1
% subcomplex and is called _induced orientation_. For example, a positive
% orientated triangle will induce the counter clockwise orientation of its
% three edges.
%
% The ordering of vertices will naturally introduce an orientation and will
% be called _ordering orientation_. More specifically
%
% * The vector from |edge(:,1)| to |edge(:,2)| defines an orientation of
% edges.
% * The sign of det(v12,v13) defines an orientation of the triangle.
%
% The orientation of a simplex in the simplicial complex should be
% uniquely determined which will be called _global orientation_. It can be
% chosen as the global ordering orientation but not always the case.
%
% Inside one triangle, the local orientation of three edges is more
% involved. The local ordering of edges will introduce a local ordering
% orientation. The orientation of the triangle will also induce an induced
% orientation. The local ordering orientation is used in the computing of
% local bases and the induced orientation is used when computing the
% differential operator locally. They may or may not be consisitent with
% the global orientation of edges.
%
% In general, there will be an inconsistency of the following types of
% orientation and apporipate data structure should be constructured to
% record such inconsistency.
%
% * a global orientation
% * the global ordering orientation
% * the local ordering orientation
% * the local induced orientation
%
% *elem*. The orientation of a triangle is either positive or negative. For
% the global ordering orientation, it is the sign of the signed area
% (output of |simplexvolume|).
%
[Dlambda,area,elemSign] = gradbasis(node,elem);
%%
% In the output of |gradbasis|, |area| is always positive and an additional
% array |elemSign| is used to record the sign of the signed area.
%
% |Dlambda(t,:,k)| is the gradient of $\lambda_k$. Therefore the outward
% normal direction of the kth face can be obtained by |-Dlambda(t,:,k)|
% which is independent of the ordering and orientation.
%
% *edge*. For 2-D triangulations, *we shall always chose global ordering
% orientation*, i.e., from the lower index to the bigger index.
%
% The local ordering orientation is implicitly used when computing finite
% element basis in each element. For example, the edge element on edge |[i j]|
% in |locEdge| is defined as
%
% $$\phi_{i,j} = 2(\lambda_i \nabla \lambda_j - \lambda_j \nabla \lambda_i).$$
%
% Permutation of |[i j]| to |[j i]| will change the sign of the basis. Note
% that this is locally, i.e., element by element.
%
% The global basis associated to an edge, however, depends only on the
% global orientation of this edge. We introduce |elem2edgeSign(1:NT, 1:3)|
% to record the inconsistency of a local ordering orientation and a global
% orientation.
%
% For the consistent local ordering [2 3; 3 1; 1 2] and global ascend
% ordering orientation, the elem2edgeSign can be generated as follows:

elem2edgeSign = ones(NT,3,'int8');
totalEdge = uint32([elem(:,[2,3]); elem(:,[3,1]); elem(:,[1,2])]);
idx = (totalEdge(:,1)>totalEdge(:,2));
elem2edgeSign(idx) = -1;

%%
% There is one more inconsistency between the induced orientation and the
% global orientation of edges. If a triangle is positive orientated, the
% induced edge orientation should be given by the outwards (relative to a
% triangle) normal vector. This induced orientation may not be consistent
% with the global orientation of edges.
%
% It depends on the ordering of |elem| and |locEdge|. When |elem| is
% positive ordered and |locEdge| is consistently ordered, it is.
%
% For ascend ordering of |elem| and |edge|, we denote the direction as +1
% if the direction of an edge is the same with the induced direction in a
% certain elem, and -1 otherwise. Then the consistency is given by
elem2edgeSign = [+1 -1 +1];

%%
% The second sign is -1 because the local edge in ascend ordering is [1
% 3] not [3 1].
%%
% The |elem2edgeSign| will be used when assembling differential operators.
% For example, when computing |div| operators on a positive orientated
% triangle, the edge should have outwards normal direction or equivalently
% the counter clockwise orientation.
%%
% We summarize the two popular ordering and orientation schemes below.

%% Positive Ordering and Orientation
%
% The vertice of the |eleme| is sorted such that the area is always
% positive. i.e. the three vertices of the elem are ordered
% counter-clockwisely. Furthermore the first vertex is always the newest
% vertex of the triangle for the easy of local mesh refinement and
% coarsening.
%
% The local edge is using opposite indexing and consistent ordering
%
% |locEdge = [2,3; 3,1; 1,2]|
%
% The ascend ordering is used for global edges, i.e., |edge| is sorted s.t.
%
% |edge(:,1) < edge(:,2)|
%
% The inconsistency of the orientation is recorded in|elem2edgeSign|.
%
% *Where to use*: This is the default ordering and orientation scheme.
%
%% Ascend Ordering and Orientation
%
% *Ascend ordering*. The vertices of |elem| is sorted such that
%
% |elem(t,1)<elem(t,2)<elem(t,3)|
%
% The local edge is also in the ascend ordering
%
% |locEdge = [2,3; 1,3; 1,2]|
%
% The ascend ordering is used for edges, i.e., |edge| is sorted s.t.
%
% |edge(:,1) < edge(:,2)|
%
% It is easy to see the benefit of ascend ordering: the ordering of local
% edges is consistent with the global ones and so is the corresponding
% orientation.
%
% *Orientation*. We choose the ordering orientation.
%
% |elem: sign(det(v12,v13))|
%
% |edge: from the node with smaller global index to bigger one|
%
% For |edge|, the orientation of the global ordering and the local
% ordering is consistent. But they are not consistent with the induced
% orientation inside one triangle. Such inconsistency is recorded in
%
% |elem2edgeSign = [+1 -1 +1]|
%
%
% *Where to use*: for H(curl) and H(div) elements and high order (cubic and
% above) H(grad) elements.

%% An Example
%
node = [0,0; 1,0; 1,1; 0,1];    % nodes
elem = [2,3,1; 4,1,3];          % elements
% [node,elem] = uniformrefine(node,elem);
%%
% Poistive ordering and orientation
[elem2edge,edge,elem2edgeSign] = dofedge(elem);
% plot
set(gcf,'Units','normal');
set(gcf,'Position',[0,0.25,0.25,0.25]);
showmesh(node,elem);
findnode(node);
findelem(node,elem);
findedge(node,edge);
%%
display(elem);
display(edge);
display(elem2edge);
display(elem2edgeSign);

%%
% Ascend Ordering and Orientation
bdFlag = setboundary(node,elem,'Dirichlet');
[elem,bdFlag] = sortelem(elem,bdFlag);
[elem2edge,edge,elem2edgeSign] = dofedge(elem);
display(elem);
display(edge);
display(elem2edge);
display(elem2edgeSign);
elem2edgeSign = [1,-1,1];


function srcPatch = sc_prep_source_patch(img, uvTform, optS)

% SC_PREP_SOURCE_PATCH
%
% Prepare source patches according to uvTform
%
% Input:
%   - img:       input image
%   - uvPixSub:  target patch position
%   - optS:      parameter
% Output:
%   - srcPatch: [pNumPix] x [3] x [numUvPix]

numUvPix =  size(uvTform, 1);

% Prepare source patch sampling position
% srcPatchPos = zeros(optS.pNumPix, 3, numUvPix);

% Get srcPatchPos
c1 = reshape(uvTform(:,1:3)', 1, 3, numUvPix);
c2 = reshape(uvTform(:,4:6)', 1, 3, numUvPix);
c3 = reshape(uvTform(:,7:9)', 1, 3, numUvPix);

% Get the source patch pixel positions
srcPatchPos = bsxfun(@times, optS.refPatchPos(:,1), c1) + ...
              bsxfun(@times, optS.refPatchPos(:,2), c2);
srcPatchPos = bsxfun(@plus, srcPatchPos, c3);

% Convert back to Eucledian coordinate
srcPatchPos = bsxfun(@rdivide, srcPatchPos, srcPatchPos(:, 3, :));

% Grab the color values of source patch using bilinear interpolation
srcPatch = vgg_interp2(img, srcPatchPos(:,1,:), srcPatchPos(:,2,:), 'linear', 0);

% Convert to the format [pNumPix] x [3] x [numUvPix]
srcPatch = permute(srcPatch, [1,3,2]);

% for i = 1 : optS.pNumPix
%     dx = optS.refPatchPos(1,i);
%     dy = optS.refPatchPos(2,i);
%
%     srcPatchPos(i, 1, :) = uvTform(1,:)*dx + uvTform(4,:)*dy + uvTform(7,:);
%     srcPatchPos(i, 2, :) = uvTform(2,:)*dx + uvTform(5,:)*dy + uvTform(8,:);
%     srcPatchPos(i, 3, :) = uvTform(3,:)*dx + uvTform(6,:)*dy + uvTform(9,:);
% end
% srcPatchPos(:, 1:2,:) = bsxfun(@rdivide, srcPatchPos(:, 1:2,:), srcPatchPos(:, 3,:));

% % Avoid sample out of boundary positions
% % srcPatchPos(:,1,:) = sc_clamp(srcPatchPos(:,1,:), 1, size(img,2));
% % srcPatchPos(:,2,:) = sc_clamp(srcPatchPos(:,2,:), 1, size(img,1));
%
% % Sampling source patch
% srcPatch = mirt2D_mexinterp(img, srcPatchPos(:, 1, :), srcPatchPos(:, 2, :));

% srcPatch = permute(srcPatch, [1,3,2]);
end


% DEMSILHOUETTEGP2 Model silhouette data with independent MLP GPs.

% FORMAT
% DESC runs a simple regression on the Agawal and Triggs data.
%
% SEEALSO : gpCreate, demInterpolation
%
% COPYRIGHT : Neil D. Lawrence, 2008

% GP

randn('seed', 1e7)
rand('seed', 1e7)

dataSetName = 'silhouette';
experimentNo = 2;

% load data
[X, y, XTest, yTest] = mapLoadData(dataSetName);

% Set up the model
options = gpOptions('ftc');
options.kern{1} = 'mlp';

% Scale outputs to variance 1.
options.scale2var1 = true;

% Use the full Gaussian process model.
q = size(X, 2);
d = size(y, 2);
model = gpCreate(q, d, X, y, options);

display = 1;
iters = 1000;

model = gpOptimise(model, display, iters);
modelDisplay(model)

% Save results
fileBaseName = modelWriteResult(dataSetName, experimentNo);
demSilhouettePlot


function [xyz, XYZmm, Z, class] = cluster_local_maxima(cl, dthresh, verbose)
% Clusters are chosen so that they must be at least dthresh mm apart
% default is 10 mm
%
% :Usage:
% ::
%
%    [xyz, XYZmm, Z, class] = cluster_local_maxima(cl, [dthresh], [verbose])
%
% verbose output: 1/0, default is 0
%
% additional optional outputs (slower):
%
% class: vector of integers for which subcluster this cluster belongs to
%
% ..
%    tor wager
% ..

    if nargin < 2 || isempty(dthresh), dthresh = 10; end
    if nargin < 3, verbose = 0; end

    [N Z xyz] = spm_max(abs(cl.Z), cl.XYZ);

    XYZmm = voxel2mm(xyz, cl.M);

    ncoord = size(cl.XYZmm, 2);
    class = zeros(1, ncoord);

    if isempty(xyz), return, end   % no peak maximum

    if verbose, fprintf(1, 'Local maxima (initial): %3.0f\n', length(Z)); end

    % find maxima within 10 mm and collapse
    d = pdist(XYZmm');
    nd = length(d);
    tooclose = d < dthresh;

    while any(tooclose)

        [d, nd, tooclose, xyz, XYZmm, Z] = omit_lowz_of_closest_pair(d, nd, tooclose, xyz, XYZmm, Z, dthresh, verbose);

    end

    if verbose, fprintf(1, 'Local maxima (final): %3.0f\n', length(Z)); end

    if nargout > 3
        % assign each voxel a subcluster based on closest local max
        speaks = XYZmm';
        npeaks = length(Z);

        % this is slower even for only 1000 vox
        %d = squareform(pdist([speaks; cl.XYZmm']));
        %d = d(1:npeaks, npeaks+1:end);   % peaks x voxels

        for i = 1:ncoord
            d = distance(cl.XYZmm(:, i)', speaks);
            [mind, whclose] = min(d);
            class(i) = whclose(1);
        end
    end
end

function [d, nd, tooclose, xyz, XYZmm, Z] = omit_lowz_of_closest_pair(d, nd, tooclose, xyz, XYZmm, Z, dthresh, verbose)

    tooclose = tooclose .* d;

    % find minimum distance
    tooclose(tooclose == 0) = Inf;
    [mindist, wh] = min(tooclose);

    % get indices of two local maxima that are too close (in rows)
    closest = zeros(1, nd);
    closest(wh(1)) = mindist;
    closest = squareform(closest);
    [rows, cols] = find(closest);    % need to return cols to get correct behavior

    % find which has the lowest Z-score
    [lowZ, whz] = min(Z(rows));      % rows is sufficient b/c there is only one pair

    wh_to_omit = rows(whz); % which in list to omit

    if verbose
        fprintf(1, 'Omitting index: %3.0f with z-value of %3.2f, which is %3.2f mm from another max whose z is %3.2f\n', ...
            wh_to_omit, lowZ, mindist, max(Z(rows)));
    end

    % eliminate important variables
    xyz(:, wh_to_omit) = [];
    XYZmm(:, wh_to_omit) = [];
    Z(wh_to_omit) = [];

    % find maxima within 10 mm and collapse
    d = pdist(XYZmm');
    nd = length(d);
    tooclose = d < dthresh;

end

function d = distance(u, v)
% d = distance(u, v)
% Euclidean distance between u and v
% u and v should be column vectors or matrices in k-dim space, where k is
% the number of columns of u and v.
%
% if u is a single row, replicates u to size(v,1)

if size(u,1) < size(v,1)
    u = repmat(u,size(v,1),1);
    if size(u,1) < size(v,1), error('Inputs must have same number of rows, or one row for 1st input!'),end
end

delt = u - v;
d = (sum(delt .^ 2,2)) .^.5;

end


function [f] = spm_fx_NMDA(x_V,x_G,P,M)

VN = 60;
%% Pyamidal Cells & interneuron NMDA receptos

mag_block = 1/(1 + 0.2*exp(-0.062*(exp(P.scale_NMDA)*x_V)));
f =  (x_G*(VN - x_V)*mag_block);


function X = tenrand(varargin)
%TENRAND Uniformly distributed pseudo-random tensor.
%
%   X = TENRAND(SZ) forms a tensor of size SZ with pseudo-random
%   values drawn from a uniform distribution on the unit interval.
%
%   TENRAND(SZ) is equivalent to TENSOR(RAND(SZ(1),SZ(2),...),SZ).
%
%   See also TENSOR, SPTENRAND, RAND.
%
%MATLAB Tensor Toolbox.
%Copyright 2012, Sandia Corporation.

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

if nargin == 1
    sz = varargin{1};
else
    sz = cell2mat(varargin);
end

data = rand([sz 1 1]);
X = tensor(data,sz);


function triangle_dunavant_rule_test02 ( )

%*****************************************************************************80
%
%% TRIANGLE_DUNAVANT_RULE_TEST02 tests DUNAVANT_RULE.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    11 December 2006
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TRIANGLE_DUNAVANT_RULE_TEST02\n' );
  fprintf ( 1, '  DUNAVANT_RULE returns the points and weights\n' );
  fprintf ( 1, '  of a Dunavant rule for the triangle.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  In this test, we simply check that the weights\n' );
  fprintf ( 1, '  sum to 1.\n' );

  rule_num = dunavant_rule_num ( );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Number of available rules = %d\n', rule_num );

  fprintf ( 1, '\n' );
  fprintf ( 1, '      Rule    Order    Sum of weights\n' );
  fprintf ( 1, '\n' );

  for rule = 1 : rule_num

    order_num = dunavant_order_num ( rule );

    [ xy, w ] = dunavant_rule ( rule, order_num );

    w_sum = sum ( w(1:order_num) );

    fprintf ( 1, '  %8d  %8d  %14f\n', rule, order_num, w_sum );

  end

  return
end


function linpack_c_test04 ( )

%*****************************************************************************80
%
%% TEST04 tests CGBCO.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    25 June 2009
%
%  Author:
%
%    John Burkardt
%
  ml = 1;
  mu = 1;
  n = 3;
  lda = 2*ml+mu+1;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST04\n' );
  fprintf ( 1, '  For a complex general band storage matrix:\n' );
  fprintf ( 1, '  CGBCO factors the matrix and estimates the\n' );
  fprintf ( 1, '  reciprocal condition number.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  The matrix order is N = %d\n', n );
  fprintf ( 1, '  The lower band is ML =  %d\n', ml );
  fprintf ( 1, '  The upper band is MU =  %d\n', mu );
%
%  Set the values of the matrix A.
%
  a_save(1:n,1:n) = 0.0;

  m = ml + mu + 1;

  seed = 123456789;

  for j = 1 : n
    i1 = max ( 1, j - mu );
    i2 = min ( n, j + ml );
    for i = i1 : i2
      k = i - j + m;
      [ a(k,j), seed ] = c4_uniform_01 ( seed );
      a_save(i,j) = a(k,j);
    end
  end

  fprintf ( 1, '\n' );
  fprintf ( 1, '  The matrix A:\n' );
  fprintf ( 1, '\n' );

  for i = 1 : n
    for j = 1 : n
      fprintf ( 1, '  (%8f  %8f)', real ( a_save(i,j) ), imag ( a_save(i,j) ) );
    end
    fprintf ( 1, '\n' );
  end
%
%  Factor the matrix A.
%
  [ a, ipvt, rcond ] = cgbco ( a, lda, n, ml, mu );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Estimated reciprocal condition RCOND = %f\n', rcond );

  return
end


function prior = invgammaPriorParamInit(prior, params)

% INVGAMMAPRIORPARAMINIT Inverse gamma prior model's parameter initialisation.
% FORMAT
% DESC initialises the parameters of the inverse gamma prior with some
% default parameters.
% ARG prior : prior structure to be initialised.
% RETURN prior : prior structure with initial values in place.
%
% SEEALSO : priorCreate, gammaPriorParamInit
%
% COPYRIGHT : Neil D. Lawrence, 2004, 2005, 2006
%
% MODIFICATIONS: Andreas C. Damianou, 2013
%
% PRIOR

if nargin < 2
    prior.a = 1e-6;
    prior.b = 1e-6;
else
    prior.a = params(1);
    prior.b = params(2);
end

prior.transforms.index = [1 2];
prior.transforms.type =  optimiDefaultConstraint('positive');
prior.nParams = 2;


function [m] = dm2m(dm)
% Convert length from decimeters to meters.
% Chad A. Greene 2012
m = dm/10;


function stats = plot_obs_spa_for_ranks( fig_ind, saveResults )
% plot obs % vs corruption % for a few ranks

load ..\..\data\syn-lr-tnames   % load tnames

marker = { 'r-*', 'b-*', 'k-*', 'g-*' };
Ntens = length(tnames);
Itens = [ 1,2,3 ];
Ntens = length(Itens);
Nobs = 20;
Nnoise = 9;
Nrep = 1;
Imag = 1;
alg = 2;
rRatio = 1;
lambdaS = 1;
IsTC = true;
verbose = false;
err_bar = 0.01;

stats.obs = [];
stats.spa = zeros( Ntens, Nobs );
stats.exp = 'obs-spa-for-ranks';

figure( fig_ind );

for t = 1:Ntens
    tname = tnames{Itens(t)};
    load( ['..\..\data\',tname] );
    maxNoise = Nnoise;

    for i = Nobs:-1:1

        for j = maxNoise:-1:1
            err = zeros( 1, Nrep );
            for k = 1:Nrep
                dtemp = gen_syn_data( data, i, j, Imag, k );
                results = test_trpca( dtemp, alg, rRatio, lambdaS, IsTC, verbose );
                err(k) = results.rel_err1;
            end
            avg_err = mean(err);
            fprintf( '%s,  obs: %1.2f,  spa: %1.2f,  err: %1.2e\n', tname, data.obsPct(i), data.noisePct(j), avg_err );
            if avg_err <= err_bar
                % record spa
                stats.spa( t, i ) = data.noisePct(j);
                break;  % found the largest corruption % tolerated
            end
        end

        maxNoise = j;
        if j == 1 && stats.spa(t,i) == 0    % no noise tolerated from now on
            break;
        end
    end

    stats.obs = data.obsPct(1:Nobs);
    plot( stats.obs, stats.spa(t,:), marker{t}, 'LineWidth', 2 );
    hold on;
end

title( 'obs % v.s. max corruption % for various ranks' );
xlabel( 'obs %' );
ylabel( 'max corruption %' );
legend( tnames(1:Ntens) );
hold off;

if exist( 'saveResults', 'var' ) && ~isempty(saveResults) && saveResults
    save ..\..\data\syn-obs-spa stats
end

end


function F= GetCharacteristicBasedFilter(level,dBand,dataClass)

F=cell(3,level);
for l=1:level
  cubeSize=8;
  [P ,PF]=GeneratePyramidSection(cubeSize);

  numDir=dBand{level}{l}(1,1);
  shift=cubeSize/numDir;
  F{1,l}=cell(numDir,numDir);
  F{2,l}=cell(numDir,numDir);
  F{3,l}=cell(numDir,numDir);
  SF=PF{1}+PF{2}+PF{3};
  mRadial =ones(shift,cubeSize,shift);

  A=zeros(cubeSize,cubeSize,cubeSize);

   for l2=1:numDir
    for l1=1:numDir
      for c=1:3
      mRadialIdx=[(l1-1)*shift+1  l1*shift ;1 cubeSize ; (l2-1)*shift+1  l2*shift  ];

      F{c,l}{l2,l1}=PolarToRec(mRadialIdx,mRadial,cubeSize,P{c},SF);
       A=A+F{c,l}{l2,l1};
%       F{c,l}{l2,l1}=squeeze(real(fftshift(ifftn(fftshift(F{c,l}{l2,l1})))));

%       F{2,l}{l2,l1}=PolarToRec(mRadialIdx,mRadial,cubeSize,P{2},SF);
%       A=A+F{2,l}{l2,l1};
%       F{2,l}{l2,l1}=real(fftshift(ifftn(fftshift(F{2,l}{l2,l1}))));
%       F{3,l}{l2,l1}=PolarToRec(mRadialIdx,mRadial,cubeSize,P{3},SF);
%       A=A+F{3,l}{l2,l1};
%       F{3,l}{l2,l1}=real(fftshift(ifftn(fftshift(F{3,l}{l2,l1}))));
      end
    end
   end
for c=1:3
  for l2=1:numDir
    for l1=1:numDir
       F{c,l}{l2,l1}=F{c,l}{l2,l1}./A;
        F{c,l}{l2,l1}=squeeze(real(fftshift(ifftn(fftshift(F{c,l}{l2,l1})))));
     end
   end
 end
end

Temp=F(1,:);
F(1,:)=F(2,:);
F(2,:)=Temp;


function [detrended_data, trend] = strongDeTrend(data, thr_perc, thr_perc_global, n_sigma)
% Returns the detrend per column with a certaint percentile of values in data
% The code uses only the data filtered by the requested percentile to estimate
% an detred column by column
% With this estimation only the data within n_sigma range are used for the
% robust detrend estimation
%
% SYNTAX:
%   smean = strongDeTrend(data, thr_perc, thr_perc_global, n_sigma)
%
% INPUT:
%   data                matrix of values
%   thr_perc            percentile requested [0 1] per column
%   thr_perc_global     percentile requested [0 1] global
%   n_sigma             number of sigmas
%
% OUTPUT:
%   detrended_data   strong detrend per column

%--- * --. --- --. .--. ... * ---------------------------------------------
%               ___ ___ ___
%     __ _ ___ / __| _ | __|
%    / _` / _ \ (_ |  _|__ \
%    \__, \___/\___|_| |___/
%    |___/                    v 1.0RC1
%
%--------------------------------------------------------------------------
%  Copyright (C) 2021 Geomatics Research & Development srl (GReD)
%  Written by:        Andrea Gatti
%  Contributors:      Andrea Gatti ...
%  A list of all the historical goGPS contributors is in CREDITS.nfo
%--------------------------------------------------------------------------
%
%   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/>.
%
%--------------------------------------------------------------------------
% 01100111 01101111 01000111 01010000 01010011
%--------------------------------------------------------------------------

    if nargin < 2 || isempty(thr_perc)
        thr_perc = 0.99;
    end

    if nargin < 3 || isempty(thr_perc_global)
        thr_perc_global = 0.97;
    end

    if nargin < 4 || isempty(n_sigma)
        n_sigma = 5;
    end

    % filter data
    detrended_data = data;
    data(abs(data) >= perc(abs(data(:)), thr_perc_global)) = nan;
    x_in = (1 : size(data,1))';
    for c = 1 : size(data, 2)
        data(:,c) = data(:,c) - movmean(data(:,c), 5, 'omitnan'); % reduce the signal with moving mean(to remove the trend)
        data((abs(data(:, c)) >= perc(abs(data(:, c)), thr_perc)), c) = nan; % keep thr_perc of data
        thr = n_sigma * std(data(:, c), 'omitnan');
        lid_ok =  abs(data(:,c)) <= thr;
        try
            warning off
            trend = Core_Utils.interp1LS(x_in(lid_ok), detrended_data(lid_ok, c), 1, x_in); % use the current filtered data to compute the trend
            warning on;
        catch
            trend = 0;
        end
        data(:,c) = detrended_data(:,c) - trend;
        thr = n_sigma * std(data(lid_ok, c), 'omitnan'); % repeat the filtering with the new detrended data
        lid_ok =  abs(data(:,c)) <= thr;
        try
            warning off
            trend = Core_Utils.interp1LS(x_in(lid_ok), detrended_data(lid_ok, c), 1, x_in); % recompute trend with the new
            warning on;
        catch
            trend = 0;
        end
        detrended_data(:,c) = detrended_data(:,c) - trend;
    end
end


%% FTAlignStack

function S=AlignStack(stack)

%% 081010 Tobias Henn

S=stack;
stackcontainer=stack.spectr;

clear S.spectr

[ymax,xmax,emax]=size(stackcontainer);

xresolution=S.Xvalue/xmax;
yresolution=S.Yvalue/ymax;

center=ceil(emax/4*3);

spectr=zeros(ymax,xmax,emax);

shifts=zeros(emax,4);

%calculate image shifts for each energy,perform shift with FT method

for k=1:emax

    shifts(k,:)=dftregistration(fft2(stackcontainer(:,:,center)),fft2(stackcontainer(:,:,k)),10);
    spectr(:,:,k)=FTMatrixShift(stackcontainer(:,:,k),-shifts(k,3),-shifts(k,4));

end

%Reduce image size

shiftymax=ceil(max(shifts(:,3)));
shiftxmax=ceil(max(shifts(:,4)));
shiftymin=ceil(abs(min(shifts(:,3))));
shiftxmin=ceil(abs(min(shifts(:,4))));

shiftmatrix=zeros(ymax-shiftymin-shiftymax,xmax-shiftxmax-shiftxmin,emax);

shiftmatrix(:,:,:)=spectr((1+shiftymax):(ymax-shiftymin),(1+shiftxmax):(xmax-shiftxmin),:);

S.spectr=abs(shiftmatrix);

S.Xvalue=size(S.spectr,2)*xresolution;
S.Yvalue=size(S.spectr,1)*yresolution;

return


function net = cnnff(net, x)
    n = numel(net.layers);
    net.layers{1}.a{1} = x;
    inputmaps = 1;

    for l = 2 : n   %  for each layer
        if strcmp(net.layers{l}.type, 'c')
            %  !!below can probably be handled by insane matrix operations
            for j = 1 : net.layers{l}.outputmaps   %  for each output map
                %  create temp output map
                z = zeros(size(net.layers{l - 1}.a{1}) - [net.layers{l}.kernelsize - 1 net.layers{l}.kernelsize - 1 0]);
                for i = 1 : inputmaps   %  for each input map
                    %  convolve with corresponding kernel and add to temp output map
                    z = z + convn(net.layers{l - 1}.a{i}, net.layers{l}.k{i}{j}, 'valid');
                end
                %  add bias, pass through nonlinearity
                net.layers{l}.a{j} = sigm(z + net.layers{l}.b{j});
            end
            %  set number of input maps to this layers number of outputmaps
            inputmaps = net.layers{l}.outputmaps;
        elseif strcmp(net.layers{l}.type, 's')
            %  downsample
            for j = 1 : inputmaps
                z = convn(net.layers{l - 1}.a{j}, ones(net.layers{l}.scale) / (net.layers{l}.scale ^ 2), 'valid');   %  !! replace with variable
                net.layers{l}.a{j} = z(1 : net.layers{l}.scale : end, 1 : net.layers{l}.scale : end, :);
            end
        end
    end

    %  concatenate all end layer feature maps into vector
    net.fv = [];
    for j = 1 : numel(net.layers{n}.a)
        sa = size(net.layers{n}.a{j});
        net.fv = [net.fv; reshape(net.layers{n}.a{j}, sa(1) * sa(2), sa(3))];
    end
    %  feedforward into output perceptrons
    net.o = sigm(net.ffW * net.fv + repmat(net.ffb, 1, size(net.fv, 2)));

end


function linpack_s_test19 ( )

%*****************************************************************************80
%
%% TEST19 tests SPPCO.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    24 June 2009
%
%  Author:
%
%    John Burkardt
%
  n = 5;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST19\n' );
  fprintf ( 1, '  For a positive definite symmetric packed matrix,\n' );
  fprintf ( 1, '  SPPCO estimates the reciprocal condition number.\n' );
  fprintf ( 1, '  The matrix size is N = %d\n', n );
%
%  Set the matrix A.
%
  k = 0;
  for j = 1 : n
    for i = 1 : j
      k = k + 1;
      if ( i == j - 1 )
        a(k) = -1.0;
      elseif ( i == j )
        a(k) = 2.0;
      else
        a(k) = 0.0;
      end
    end
  end
%
%  Estimate the condition.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Estimate the condition number.\n' );

  [ a, rcond, z, info ] = sppco ( a, n );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Reciprocal condition number = %f\n', rcond );

  return
end


function [bestAlgo, inliers] = prtUtilRansac(data,algo,evalFn,varargin)
%[bestAlgo, inliers] = prtUtilRansac(data,algo,evalFn)
%   Perform RANSAC on prtDataSet data.
%
%[bestAlgo, inliers] = prtUtilRansac(data,algo,evalFn,param1,value1,...)
%   Enables inputs of parameter/value pairs as described below:
%
%   Parameters:
%       nIterations (100)
%       nBootstrapSamples (10) - the number of samples to use at each
%         iteration to fit a model.
%       fitErrorThreshold (0.2) - absolute error between truth and guess
%         should be less than fitErrorThreshold to be included inliers.
%
%   Example usage:
%
%       ds = prtDataGenRansac(100,0.2);
%       [~,inliers] = prtUtilRansac(ds,prtRegressLslr,@(a,b)abs(a-b));
%       plot(ds.X(inliers),ds.Y(inliers),'ro',...
%            ds.X(setdiff(1:100,inliers)),ds.Y(setdiff(1:100,inliers)),'bs')

% Copyright (c) 2014 Patrick Wang, Peter Torrione, Kenneth Morton
%
% Permission is hereby granted, free of charge, to any person obtaining a
% copy of this software and associated documentation files (the
% "Software"), to deal in the Software without restriction, including
% without limitation the rights to use, copy, modify, merge, publish,
% distribute, sublicense, and/or sell copies of the Software, and to permit
% persons to whom the Software is furnished to do so, subject to the
% following conditions:
%
% The above copyright notice and this permission notice shall be included
% in all copies or substantial portions of the Software.
%
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
% USE OR OTHER DEALINGS IN THE SOFTWARE.

%% parse input options
p = inputParser;

p.addParamValue('nIterations',100);
p.addParamValue('nBootstrapSamples',10);
p.addParamValue('fitErrorThreshold',0.2);

p.parse(varargin{:});
inputStructure = p.Results;

%% iterate
bestNFit = 0;
bestAlgo = [];
for iter = 1:inputStructure.nIterations
	% bootstrap
	indices = randperm(data.nObservations);
	indices = indices(1:inputStructure.nBootstrapSamples);
	dataIn = data.retainObservations(indices);
	dataOut = data.removeObservations(indices);

	% train on bootstrapped samples
	algoTrained = algo.train(dataIn);

	% test on left-out samples
	guessOut = algoTrained.run(dataOut);

	% find how many left-out samples fit model well
	error = evalFn(guessOut.X,dataOut.Y); % dataOut.Y?
	nFit = sum(error<inputStructure.fitErrorThreshold);

	% keep the best model
	if nFit > bestNFit
		bestNFit = nFit;
		bestAlgo = algoTrained;
	end
end

%% find all inliers and retrain model
guess = bestAlgo.run(data);
error = evalFn(guess.X,data.Y); % data.Y?
inliers = find(error<inputStructure.fitErrorThreshold);
bestAlgo = algo.train(data.retainObservations(inliers));


function ind = buscamin(x);
% It searches the first minimum of the modulus of x.

x = abs(x);
localmin = (x(2:end-1)<=x(1:end-2))...
         & (x(2:end-1)<=x(3:end));

ind = min(find(localmin));


function [grad]= B_sigmoid(future_layers, curr_layer)
output = curr_layer.a;
future_grad = GetFutureGrad(future_layers, curr_layer);
if isfield(curr_layer, 'rho')
    L1 = curr_layer.L1;
    L1weight = curr_layer.L1weight;
    rho = curr_layer.rho;

    tmp = -L1./max(1e-3,rho) + (1-L1)./max(1e-3,(1-rho));
    future_grad = future_grad + repmat(L1weight * tmp, 1, size(future_grad,2));
end

grad = future_grad .* output .* (1-output);

end


function [M, inliers] = RANSAC(x, fittingfn, distfn, degenfn, s, t)

    maxTrials = 1000;
    maxDataTrials = 100;

    [rows, npts] = size(x);

    % Desired probability of choosing at least one sample free from outliers (probably should be a parameter)
    p = 0.99;

    bestM = NaN;
    trialcount = 0;
    bestscore =  0;
    N = 1;

    while N > trialcount

        % Select at random s datapoints to form a trial model, M.
        degenerate = 1;
        count = 1;
        while degenerate
            % Generate s random indicies in the range 1..npts
            ind = randsample(npts, s);
            % Su Tan
%             while tooDense(x(:, ind), 10)
%                 ind = randsample(npts, s);
%             end
            % Test that these points are not a degenerate configuration.
            degenerate = feval(degenfn, x(:,ind));

            if ~degenerate
                M = feval(fittingfn, x(:,ind));
                if isempty(M)
                    degenerate = 1;
                end
            end

            % Safeguard against being stuck in this loop forever
            count = count + 1;
            if count > maxDataTrials
                disp('Unable to select a nondegenerate data set');
                break
            end
        end

%         if scoreX1 ~= 0
%             l = min([scoreX1(ind) scoreX2(ind)]);
%             t = (l + 0.6) * t;
%         end

        [inliers, score, M] = feval(distfn, M, x, t);

        % Find the number of inliers to this model.
        ninliers = length(inliers);

        if score > bestscore
            bestscore = score;
            bestinliers = inliers;
            bestM = M;

            % Update estimate of N
            fracinliers =  ninliers/npts;
            pNoOutliers = 1 -  fracinliers^s;
            pNoOutliers = max(eps, pNoOutliers);
            pNoOutliers = min(1-eps, pNoOutliers);
            N = log(1-p)/log(pNoOutliers);
        end

        trialcount = trialcount+1;

        % Safeguard against being stuck in this loop forever
        if trialcount > maxTrials
            fprintf('ransac reached the maximum number of %d trials\n', maxTrials);
            break
        end

        %fprintf('Iter: %d \n', trialcount);
    end

    if ~isnan(bestM)
        M = bestM;
        inliers = bestinliers;
    else
        M = [];
        inliers = [];
        disp('ransac was unable to find a useful solution');
    end
end


% Downsampling procedure.
%
% Arguments:
%   grayscale I image
%   downsampling filter 'filter', should be a 1D separable filter.
%   'border_mode' should be 'circular', 'symmetric', or 'replicate'. See 'imfilter'.
%
% If image width W is odd, then the resulting image will have width (W-1)/2+1,
% Same for height.
%
% tom.mertens@gmail.com, August 2007
%

function R = downsample_(I, filter)

border_mode = 'symmetric';

% low pass, convolve with separable filter
R = imfilter(I,filter,border_mode);     %horizontal
R = imfilter(R,filter',border_mode);    %vertical

% decimate
r = size(I,1);
c = size(I,2);
R = R(1:2:r, 1:2:c, :);


function plotRelativeProjectedAmps(view)
%
% plotRelativeProjectedAmplitudes(view)
%
% Bar plot of the amplitudes for each scan, averaging across
% all pixels (in all slices) in the current ROI.  The bar heights
% and a coarse SEM can be obtained from get(gca,'UserData').
%
% gmb  5/25/98
% bw   2/19/99  Added seY field to the UserData field.
%	    seY is an estimate of the variability in the
%      amplitudes.  It is the SEM of the in the complex
%      (amp*exp(-i*ph)) representation.  The values are
%      computed in vectorMean.m
% fwc   11/07/02 plots data relative to current view

% Compute means across scans, for all pixels in the
% currently selected ROI.  The seZ value is the mean
% distance from the mean.
[meanAmps,meanPhs,seZ] = vectorMeans(view);

%Reference scan is the current scan
refScan = getCurScan(view);

% Compute the amplitude projected onto the reference phase
meanProjectedAmps = meanAmps.*cos(meanPhs-meanPhs(refScan));

meanRelProjAmps=meanProjectedAmps/meanProjectedAmps(refScan);

selectGraphWin

% Header
ROIname = view.ROIs(view.selectedROI).name;
headerStr = ['Mean of projected amplitudes relative to reference scan, ROI ',ROIname];
set(gcf,'Name',headerStr);

%plot the bar graph
clf
fontSize = 14;
h=mybar(meanRelProjAmps);
xlabel('Scan','FontSize',fontSize);
ylabel('Relative Mean Projected Amplitude','FontSize',fontSize);
ylim =get(gca,'YLim');
set(gca,'YLim',ylim*1.1);
set(gca,'FontSize',fontSize);

foo=cell2struct(h,'bar');
hbar=foo(refScan).bar;
set(hbar,'FaceColor','r')

%Save the data in gca('UserData')
data.y = meanRelProjAmps;
data.refScan = refScan;
data.seY = seZ/meanProjectedAmps(refScan); % this should probably be adapted

set(gca,'UserData',data);

return;


function [outputs] = mhe(inputs)

persistent first s b

if isempty(first)
    % initialization
    s = 'http://byu.apmonitor.com';
    b = 'mhe';
    msg = mhe_init(s,b)
    addpath('apm')
end

T_meas = inputs(1);
Q1 = inputs(2);

% input measurements
apm_meas(s,b,'TC',T_meas);
apm_meas(s,b,'Q1',Q1);

% solve MPC
output = apm(s,b,'solve');

% test for successful solution
if (apm_tag(s,b,'nlc.appstatus')==1)
    % retrieve the parameter values

    % option %2 retrieval (apm_tag)
    Kp = apm_tag(s,b,'Kp.Newval');
    tau = apm_tag(s,b,'tau.Newval');
    zeta = apm_tag(s,b,'zeta.Newval');
    TC_ss = apm_tag(s,b,'TC_ss.Newval');
    TC = apm_tag(s,b,'TC.Model');
else
    % display output for debugging
    disp(output)
    % not successful, set default parameters
    Kp = 0.359806899452;
    tau = 47.7311112863;
    zeta = 1.56206738412;
    TC_ss = 23.0;
    TC = 23.0;
end
params(1) = TC;
params(2) = Kp;
params(3) = tau;
params(4) = zeta;
params(5) = TC_ss;

outputs = params;

if isempty(first)
    apm_web(s,b);
    first = false;
end

return


function [rotImg3M,rotMask3M] = perturbImageRotation(img3M,mask3M,angl)
% function [rotImg3M,rotMask3M] = perturbImageRotation(img3M,mask3M,angl)
% angl is in degrees.
%
% Rotates img3M and mask3M by angle angl.
%
% APA, 2/25/2019

rotMask3M = zeros(size(mask3M),'like',mask3M);
rotImg3M = zeros(size(img3M),'like',img3M);
sizV = size(mask3M);
iCtr = round(sizV(1)/2);
jCtr = round(sizV(2)/2);
for slc = 1:size(mask3M,3)
    %     fullSiz = size(mask3M(:,:,slc));
    %     [iV,jV] = find3d(mask3M(:,:,slc));
    %     maskM = mask3M(min(iV):max(iV),min(jV):max(jV),slc);
    maskM = mask3M(:,:,slc);
    imgM = img3M(:,:,slc);
    %     di = max(iV) - min(iV);
    %     dj = max(jV) - min(jV);
    %     iCtr = ceil((max(iV) + min(iV))/2);
    %     jCtr = ceil((max(jV) + min(jV))/2);
    %     minRow = -di*pctJitter/100;
    %     maxRow = di*pctJitter/100;
    %     minCol = -dj*pctJitter/100;
    %     maxCol = dj*pctJitter/100;
    %     numRows = minRow + (maxRow-minRow)*rand(1);
    %     numCols = minCol + (maxCol-minCol)*rand(1);
    %     minAng = -pctJitter/100*180;
    %     maxAng = pctJitter/100*180;
    %     angl = minAng + (maxAng-minAng)*rand(1);
    %     scl = (100-pctJitter)/100 + 2*pctJitter/100*rand(1);
    %     maskM = imtranslate(maskM,[numRows,numCols],'nearest','FillValues',0);
    maskM = imrotate(maskM,angl,'nearest');
    imgM = imrotate(imgM,angl,'nearest');
    %     maskM = imresize(maskM, scl, 'nearest');
    newSiz = size(maskM);
    iStart = 1;
    jStart = 1;
    iEnd = 0;
    jEnd = 0;
    iMin = iCtr - ceil(newSiz(1)/2);
    if iMin < 0
        iStart = 1-iMin;
        iMin = 1;
    else
        iMin = iMin + 1;
    end
    iMax = iCtr + floor(newSiz(1)/2);
    if iMax > sizV(1)
        iEnd = iMax - sizV(1);
        iMax = sizV(1);
    end
    jMin = jCtr - ceil(newSiz(2)/2);
    if jMin < 0
        jStart = 1-jMin;
        jMin = 1;
    else
        jMin = jMin + 1;
    end
    jMax = jCtr + floor(newSiz(2)/2);
    if jMax > sizV(2)
        jEnd = jMax - sizV(2);
        jMax = sizV(2);
    end
    %mask3M(:,:,slc) = 0;
    rotMask3M(iMin:iMax,jMin:jMax,slc) = maskM(iStart:end-iEnd,jStart:end-jEnd);
    rotImg3M(iMin:iMax,jMin:jMax,slc) = imgM(iStart:end-iEnd,jStart:end-jEnd);
end


function besk0_test ( )

%*****************************************************************************80
%
%% BESK0_TEST tests R4_BESK0 and R8_BESK0.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    25 September 2011
%
%  Author:
%
%    John Burkardt
%
  addpath ( '../test_values' );

  fprintf ( 1, '\n' );
  fprintf ( 1, 'BESK0_TEST:\n' );
  fprintf ( 1, '  Test BESK0_VALUES, R4_BESK0, R8_BESK0\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '             X       BESK0(X)\n' );
  fprintf ( 1, '                  R4_BESK0(X)         Diff\n' );
  fprintf ( 1, '                  R8_BESK0(X)         Diff\n' );

  n_data = 0;

  while ( 1 )

    [ n_data, x, fx1 ] = bessel_k0_values ( n_data );

    if ( n_data == 0 )
      break
    end

    fx2 = r4_besk0 ( single ( x ) );
    fx3 = r8_besk0 ( x );

    fprintf ( 1, '\n' );
    fprintf ( 1, '  %14.4f  %14.6g\n', x, fx1 );
    fprintf ( 1, '                  %14.6g  %14.6g\n', fx2, abs ( fx1 - fx2 ) );
    fprintf ( 1, '                  %14.6g  %14.6g\n', fx3, abs ( fx1 - fx3 ) );

  end

  rmpath ( '../test_values' );

  return
end


function NDFUN
%NDFUN Matrix operations on N-D matrices
%   NDFUN treats an N-D matrix of double precision values as a set of pages
%   of 2D matrices, and performs various matrix operations on those pages.
%   The BLAS and LAPACK routines compiled into MATLAB are used for all these
%   operations, so results will be very close, and are usually identical, to
%   "native MATLAB results".  Available commands are:
%
%   C = NDFUN('mult', A, B)
%   C = NDFUN('backslash', A, B)
%   C = NDFUN('inv', A)
%   C = NDFUN('eig', A)
%   [C, D] = NDFUN('eig', A)
%   C = NDFUN('version')
%
%   The two-argument commands perform operations equivalent to:
%       for i=1:N
%           C(:,:,i) = A(:,:,i) * B(:,:,i);
%       end
%   The one-argument command
%       for i=1:N
%           C(:,:,i) = inv(A(:,:,i));
%       end
%
%   Any number of dimensions is supported, but dimensions > 2 must match:
%       C = ndfun('mult', rand(4,3,2,2,2), rand(3,1,2,2,2))
%   C will have size = [4 1 2 2 2]
%
%   NDFUN will reuse 2D arguments when needed, much like scalar
%   operations.  A single 2D matrix can be multiplied (or solved with)
%   each 2D page of the other argument.  For instance:
%       A = rand(4,3);  B = rand(3,10,100);
%       C = ndfun('mult', A, B);
%   is equivalent to:
%       for i=1:100
%           C(:,:,i) = A * B(:,:,i);
%       end
%   The reverse also works.  These types of operations are especially
%   efficient for the backslash operator.
%
%
%   Author: Peter Boettcher <boettcher@ll.mit.edu>
%   Source: www.mit.edu/~pwb/matlab/ndfun/
%
% Last modified: <Mon Nov 25 14:31:39 2002 by pwb>
%
% NOTES:
%   1) The option 'backslash' has given a segmentation fault.
%   2) Avoid NaNs. NaNs are not handled well in general.
%   3) Unpredictable behavior: the options 'inv' and 'eig' will
%       sometimes not give an answer. Chances are better if output
%       variables are one capital eltter and do not exist (?!)
%

  error('MEX file not found.  Try ''mex ndfun.c'' to compile.');


function [mu,isig] = spm_affine_priors(typ)
% Distribution of the priors used in affine registration
%
% The parameters for this distribution were derived empirically from 227
% scans, that were matched to the ICBM space.
%__________________________________________________________________________
% Copyright (C) 2003-2018 Wellcome Trust Centre for Neuroimaging

% John Ashburner
% $Id: spm_affine_priors.m 7377 2018-07-23 13:56:24Z guillaume $

% % Values can be derived by...
% sn = spm_select(Inf,'.*seg_inv_sn.mat$');
% X  = zeros(size(sn,1),12);
% for i=1:size(sn,1),
%     p  = load(deblank(sn(i,:)));
%     M  = p.VF(1).mat*p.Affine/p.VG(1).mat;
%     J  = M(1:3,1:3);
%     V  = sqrtm(J*J');
%     R  = V\J;
%     lV      =  logm(V);
%     lR      = -logm(R);
%     P       = zeros(12,1);
%     P(1:3)  = M(1:3,4);
%     P(4:6)  = lR([2 3 6]);
%     P(7:12) = lV([1 2 3 5 6 9]);
%     X(i,:)  = P';
% end
% mu   = mean(X(:,7:12));
% XR   = X(:,7:12) - repmat(mu,[size(X,1),1]);
% isig = inv(XR'*XR/(size(X,1)-1))

switch deblank(lower(typ))

case 'mni' % For registering with MNI templates...
    mu   = [0.0667 0.0039 0.0008 0.0333 0.0071 0.1071]';
    isig = 1e4 * [
        0.0902   -0.0345   -0.0106   -0.0025   -0.0005   -0.0163
       -0.0345    0.7901    0.3883    0.0041   -0.0103   -0.0116
       -0.0106    0.3883    2.2599    0.0113    0.0396   -0.0060
       -0.0025    0.0041    0.0113    0.0925    0.0471   -0.0440
       -0.0005   -0.0103    0.0396    0.0471    0.2964   -0.0062
       -0.0163   -0.0116   -0.0060   -0.0440   -0.0062    0.1144];

case 'imni' % For registering with MNI templates...
    mu   = -[0.0667 0.0039 0.0008 0.0333 0.0071 0.1071]';
    isig = 1e4 * [
        0.0902   -0.0345   -0.0106   -0.0025   -0.0005   -0.0163
       -0.0345    0.7901    0.3883    0.0041   -0.0103   -0.0116
       -0.0106    0.3883    2.2599    0.0113    0.0396   -0.0060
       -0.0025    0.0041    0.0113    0.0925    0.0471   -0.0440
       -0.0005   -0.0103    0.0396    0.0471    0.2964   -0.0062
       -0.0163   -0.0116   -0.0060   -0.0440   -0.0062    0.1144];

case 'rigid' % Constrained to be almost rigid...
    mu   = zeros(6,1);
    isig = eye(6)*1e8; % spm_affreg used 1e9

case 'subj' % For inter-subject registration...
    mu   = zeros(6,1);
    isig = 1e3 * [
        0.8876    0.0784    0.0784   -0.1749    0.0784   -0.1749
        0.0784    5.3894    0.2655    0.0784    0.2655    0.0784
        0.0784    0.2655    5.3894    0.0784    0.2655    0.0784
       -0.1749    0.0784    0.0784    0.8876    0.0784   -0.1749
        0.0784    0.2655    0.2655    0.0784    5.3894    0.0784
       -0.1749    0.0784    0.0784   -0.1749    0.0784    0.8876];

case 'eastern' % For East Asian brains to MNI...
    mu   = [0.0719   -0.0040   -0.0032    0.1416    0.0601    0.2578]';
    isig = 1e4 * [
        0.0757    0.0220   -0.0224   -0.0049    0.0304   -0.0327
        0.0220    0.3125   -0.1555    0.0280   -0.0012   -0.0284
       -0.0224   -0.1555    1.9727    0.0196   -0.0019    0.0122
       -0.0049    0.0280    0.0196    0.0576   -0.0282   -0.0200
        0.0304   -0.0012   -0.0019   -0.0282    0.2128   -0.0275
       -0.0327   -0.0284    0.0122   -0.0200   -0.0275    0.0511];

case 'none' % No regularisation...
    mu   = zeros(6,1);
    isig = zeros(6);

otherwise
    error('"%s" not recognised as type of regularisation.',typ);
end


function D = driving_function_mono_nfchoa_fs(x0,xs,f,N,conf)
%DRIVING_FUNCTION_MONO_NFCHOA_FS driving signal for a focused source in NFC-HOA
%
%   Usage: D = driving_function_mono_nfchoa_fs(x0,xs,f,N,conf)
%
%   Input parameters:
%       x0          - position of the secondary sources / m [nx3]
%       xs          - position of focused source / m [nx3]
%       f           - frequency of the monochromatic source / Hz
%       N           - maximum order of spherical harmonics
%       conf        - configuration struct (see SFS_config)
%
%   Output parameters:
%       D           - driving function signal [nx1]
%
%   See also: driving_function_mono_nfchoa, driving_function_imp_nfchoa_fs

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

%% ===== Checking of input  parameters ==================================
nargmin = 5;
nargmax = 5;
narginchk(nargmin,nargmax);
isargmatrix(x0,xs);
isargpositivescalar(f,N);
isargstruct(conf);

%% ===== Configuration ==================================================
xref = conf.xref;
dimension = conf.dimension;
driving_functions = conf.driving_functions;

%% ===== Computation ====================================================

if strcmp('2D',dimension)

    % === 2-Dimensional ==================================================

    switch driving_functions
    case 'default'
        % --- SFS Toolbox ------------------------------------------------
        to_be_implemented;
    otherwise
        error(['%s: %s, this type of driving function is not implemented ', ...
            'for a 2D focused source.'],upper(mfilename),driving_functions);
    end

elseif strcmp('2.5D',dimension)

    % === 2.5-Dimensional ================================================

    % Reference point
    xref = repmat(xref,[size(x0,1) 1]);

    switch driving_functions
    case 'default'
        % --- SFS Toolbox ------------------------------------------------
        to_be_implemented;
    otherwise
        error(['%s: %s, this type of driving function is not implemented ', ...
            'for a 2.5D focused source.'],upper(mfilename),driving_functions);
    end

elseif strcmp('3D',dimension)

    % === 3-Dimensional ==================================================

    switch driving_functions
    case 'default'
        % --- SFS Toolbox ------------------------------------------------
        to_be_implemented;
    otherwise
        error(['%s: %s, this type of driving function is not implemented ', ...
            'for a 3D focused source.'],upper(mfilename),driving_functions);
    end

else
    error('%s: the dimension %s is unknown.',upper(mfilename),dimension);
end


function S1 = my_min2(S1, sig, varargin)
% 2D radius filtering

sig = ceil(sig);

xs = repmat([-sig:sig], 2*sig+1, 1);
ys = xs';

rs = (xs.^2 + ys.^2).^.5;

xs = xs(rs<=sig);
ys = ys(rs<=sig);

dsnew = size(S1);
S1 = S1(:,:,:);

[Ly, Lx, NT] = size(S1);

Smax = S1;
for j = 1:numel(xs)
    yc = [1:Ly] + ys(j);
    ig = ~(yc<1 | yc>Ly);
    yc = yc(ig);

    xc = [1:Lx] + xs(j);
    ig = ~(xc<1 | xc>Lx);
    xc = xc(ig);

    Smax(yc - ys(j),xc-xs(j), :) = min(Smax(yc - ys(j), xc-xs(j),:), S1(yc, xc, :));
end

S1 = reshape(Smax, dsnew);


%IM_INVERT Fixed mapping for images inversion
%
% A = IM_INVERT(A)
% A = A*IM_INVERT
%
% DESCRIPTION
% Inverts image A by subtracting it from its maximum. Note that binary
% images can better be inverted by A = ~A. In that case also A = 1-A can
% be done.
%
% SEE ALSO (PRTools Guide)
% DATASETS, DATAFILES

% Copyright: D. de Ridder, R.P.W. Duin, r.p.w.duin@37steps.com
% Faculty EWI, Delft University of Technology
% P.O. Box 5031, 2600 GA Delft, The Netherlands

function b = im_invert(a)

  if nargin < 1 | isempty(a)
    b = prmapping(mfilename,'fixed');
    b = setname(b,'Image inverse');
  elseif isa(a,'prdataset') % allows datafiles too
    isobjim(a);
    b = filtim(a,mfilename);
  elseif isa(a,'double') | isa(a,'dip_image') % here we have a single image
		if isa(a,'dip_image'), a = double(a); end
		b = max(max(max(a)))-a;
  else
    error('Illegal input')
	end

return


function r = sqr(a)
%SQR          Hessian (elementwise) square
%

% written  04/04/04     S.M. Rump
% modified 04/06/05     S.M. Rump  rounding unchanged
% modified 09/28/08     S.M. Rump  check for rounding to nearest improved
% modified 08/26/12     S.M. Rump  global variables removed
%

  e = 1e-30;
  if 1+e==1-e                           % fast check for rounding to nearest
    rndold = 0;
  else
    rndold = getround;
    setround(0)
  end

  K = prod(size(a.x));
  if K==1                   % scalar hessian

    r.x = sqr(a.x);
    r.dx = (2*a.x) * a.dx;
    r.hx = a.hx * (2*a.x) + reshape(a.dx * a.dx.',size(a.hx));

  else                      % matrix hessian

    N = getappdata(0,'INTLAB_HESSIAN_NUMVAR');
    N2 = N^2;

    r.x = sqr(a.x);
    if issparse(a.hx)               % input sparse

      ax = 2*a.x(:);
      sizeax = length(ax);
      [ia,ja,sa] = find(a.dx);
      % check for emptyness: cures Matlab bug
      % a=sparse([],[],[],2,1), [i,j,s]=find(a), s(i).*s(:)  yields error
      if isempty(ia)
        r.dx = sparse([],[],[],N,sizeax);
        r.hx = sparse([],[],[],N2,sizeax);
      else
        if isa(a.x,'intval')          % sparse intval
          rdx = times(ax(ja),sa(:),0);
          if rdx.complex
            r.dx = intval( sparse(ia,ja,rdx.mid,N,sizeax) , sparse(ia,ja,rdx.rad,N,sizeax) , 'midrad' );
          else
            r.dx = intval( sparse(ia,ja,rdx.inf,N,sizeax) , sparse(ia,ja,rdx.sup,N,sizeax) , 'infsup' );
          end
        else                          % sparse point
          r.dx = sparse(ia,ja,ax(ja).*sa(:),N,sizeax);
        end
        r.hx = adx2rhx(N,sizeax,a.dx);
      end
      [ia,ja,sa] = find(a.hx);        % sparse point or intval
      % check for emptyness: cures Matlab bug
      % a=sparse([],[],[],2,1), [i,j,s]=find(a), s(i).*s(:)  yields error
      if ~isempty(ia)
        if isa(a.x,'intval')
          rhx = times(ax(ja),sa(:),0);
          if rhx.complex
            r.hx = r.hx + intval( sparse(ia,ja,rhx.mid,N2,sizeax) , sparse(ia,ja,rhx.rad,N2,sizeax) , 'midrad' );
          else
            r.hx = r.hx + intval( sparse(ia,ja,rhx.inf,N2,sizeax) , sparse(ia,ja,rhx.sup,N2,sizeax) , 'infsup' );
          end
        else
          r.hx = r.hx + sparse(ia,ja,ax(ja).*sa(:),N2,sizeax);
        end
      end

    else                            % input full

      ax = 2*a.x(:).';
      ax = ax(ones(N2,1),:);
      r.dx = a.dx .* ax(1:N,:);
      r.hx = a.hx .* ax + a.dx(repmat(1:N,N,1),:) .* a.dx(repmat(1:N,1,N),:);

    end

  end

  r = class(r,'hessian');

  if rndold
    setround(rndold)
  end


function gX = matern32KernDiagGradX(kern, X)

% MATERN32KERNDIAGGRADX Gradient of MATERN32 kernel's diagonal with respect to X.
% FORMAT
% DESC computes the gradient of the diagonal of the matern kernel with nu=3/2 kernel matrix with
% respect to the elements of the design matrix given in X.
% ARG kern : the kernel structure for which gradients are being computed.
% ARG X : the input data in the form of a design matrix.
% RETURN gX : the gradients of the diagonal with respect to each element
% of X. The returned matrix has the same dimensions as X.
%
% SEEALSO : matern32KernParamInit, kernDiagGradX, matern32kernGradX
%
% COPYRIGHT : Neil D. Lawrence, 2006

% KERN

gX = zeros(size(X));


function [varargout]=image_numeric(varargin)

% function image_numeric(M)
% ------------------------------------------------------------------------
% Plots the intensities of an image (rounded to fit 4 digits) in the image
% at the pixel coordinates.
%
% Kevin Mattheus Moerman
% gibbon.toolbox@gmail.com
%
% 2008/08/28: Created
%
%
% ------------------------------------------------------------------------

%%

switch nargin
    case 1
        M=varargin{1};
        hf=gcf;
        numDigits=2;
        fontSize=10;
        textColor='k';
        interpreter='tex';
    case 2
        M=varargin{1};
        hf=varargin{2};
        numDigits=2;
        fontSize=10;
        textColor='k';
        interpreter='tex';
    case 3
        M=varargin{1};
        hf=varargin{2};
        numDigits=varargin{3};
        fontSize=10;
        textColor='k';
        interpreter='tex';
    case 4
        M=varargin{1};
        hf=varargin{2};
        numDigits=varargin{3};
        fontSize=varargin{4};
        textColor='k';
        interpreter='tex';
    case 5
        M=varargin{1};
        hf=varargin{2};
        numDigits=varargin{3};
        fontSize=varargin{4};
        textColor=varargin{5};
        interpreter='tex';
    case 6
        M=varargin{1};
        hf=varargin{2};
        numDigits=varargin{3};
        fontSize=varargin{4};
        textColor=varargin{5};
        interpreter=varargin{6};
end

if isempty(hf)
    hf=gcf;
end

% textFormat=['%6.',num2str(numDigits),'e'];
textFormat=['%0.',num2str(numDigits),'f';];

%%
figure(hf);
H=zeros(1,numel(M));
qh=1;
for qi=1:size(M,1)
    for qj=1:size(M,2)
        m=M(qi,qj);
        switch class(m)
            case'sym'
                try %to convert to double
                    m=double(m);
                    image_text=sprintf(textFormat,m);
                catch %Contains symbolic expressions
                    switch interpreter
                        case 'none'
                            image_text=char(m);
                        case 'latex'
                            image_text=latex(m);
                        case 'tex'
                            image_text=texlabel(m);
                    end
                    %image_text = strsplit(image_text,' '); %Places space
                    %separated elements on new line
                end
            otherwise
                image_text=sprintf(textFormat,m);
        end
        H(qh)=text(qj,qi, image_text,'horizontalAlignment','center','color',textColor,'FontWeight','demi','FontSize',fontSize,'interpreter',interpreter);
        qh=qh+1;
    end
end
if nargout==1
    varargout{1}=H;
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 h = explode_tetramesh(T,V,steps)
  % EXPLODE_TETRAMESH animated, interactive tetramesh plot of tets of a tet
  % mesh being pulled away from each
  %
  % h = explode_tetramesh(T,V)
  %
  % Inputs:
  %   T  #T by 4 list of tetrahedra indices
  %   V  #V by dim by #{frames | 1} list of vertex positions
  %   steps  # of explosion animation steps {100}
  % Outputs:
  %   h  handle to plot
  %
  % See also: tsurf, trisurf, tetramesh, animated_trisurf, animated_tetramesh
  %

  % Remap vertices and tets so that all corners are separated
  V = [ ...
    V(T(:,1),:); ...
    V(T(:,2),:); ...
    V(T(:,3),:); ...
    V(T(:,4),:); ...
  ];
  T = [ ...
    0*size(T,1) + (1:size(T,1)); ...
    1*size(T,1) + (1:size(T,1)); ...
    2*size(T,1) + (1:size(T,1)); ...
    3*size(T,1) + (1:size(T,1)); ...
    ]';
  factor = 4;
  if ~exist('steps','var')
    steps = 100;
  end
  s = linspace(1,factor,steps);
  % centroid
  c = mean(V);
  VV = zeros(size(V,1),size(V,2),steps);
  for ii = 1:steps
    sii = s(ii);
    % dialate globally
    Vii = bsxfun(@plus,sii*V,-sii*c+c);
    % contract locally
    % centroids of each tet
    Cii = ( ...
      Vii(T(:,1),:) + ...
      Vii(T(:,2),:) + ...
      Vii(T(:,3),:) + ...
      Vii(T(:,4),:))/4;
    Vii = Vii/sii+repmat(Cii,4,1)*(1-1/sii);
    VV(:,:,ii) = Vii;
  end
  h = animated_tetramesh(T,VV);
  axis equal;
  A = reshape(axis,2,[]);
  % grow by factor about center
  dA = [A(1,:)-A(2,:);A(2,:)-A(1,:)];
  axis(reshape(A+dA,1,prod(size(A))));
  % don't resize mesh
  axis manual;

end


function out = iszero( f )
%ISZERO   Check if a SEPARABLEAPPROX is identically zero on its domain.
%   OUT = ISZERO( F ) return 1 if the SEPARABLEAPPROX is exactly the zero function, and
%   0 otherwise.

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

% Get data:
pivots = f.pivotValues;
cols = f.cols;
rows = f.rows;

% Trivial check: If all the pivots are zero, then the SEPARABLEAPPROX is zero:
if ( norm(1./pivots, inf) == 0 )
    out = 1;
    return
end

% Quick check: Evaluate on a meshgrid. If the matrix is nonzero then the
% SEPARABLEAPPROX is nonzero.
dom = f.domain;
x = linspace(dom(1), dom(2), 10);
y = linspace(dom(3), dom(4), 10);
vals = fevalm(f, x, y);
if ( norm( vals, inf ) > 0 )
   out = 0;
   return
end

% Slower check: A pivot may be positive, but the columns or rows may be zero:
rk = length( pivots );
out_cols = zeros( length( pivots ), 1 );
out_rows = zeros( length( pivots ), 1 );
for j = 1:rk
    out_cols( j ) = iszero( cols(:, j) );
    out_rows( j ) = iszero( rows(:, j) );
end
bolslices = ( all(out_cols) || all(out_rows) );
out = bolslices;

end


% VL_NNROIPOOL  CNN region of interest pooling.
%   Y = VL_NNROIPOOL(X, ROIS) pools each feature channel in X in
%   the specified regions of interest ROIS. ROIS is a 5 x K array
%   containing K regions. Each region has five coordinates `[t, u0,
%   v0, u1, v1]` where `u0`, `v0` is the upper-left corner of a ROI,
%   `u1`, `v1` is the bottom-right corner, and `t` is the index of the
%   image that contains the region. Spatial coordiantes start at (1,1),
%   with `u` indexing the horizontal axis and `v` the vertical one.
%   The image indeces ranges from 1 to the number of images stored
%   in the tensor X.
%
%   If X has C feature channels, then the output Y is a 1 x 1 x C x K
%   array, with one image instance per region. Arguments can be SINGLE
%   or DOUBLE and CPU or GPU arrays; however, they must all be of the
%   same type (unless empty).
%
%   DZDX = VL_NNROIPOOL(X, ROIS, DZDY) computes the derivative of
%   the layer projected on DZDY with respect to X.
%
%   VL_NNROIPOOL(___, 'opt', value, ...) accepts the following
%   options:
%
%   `Method`:: `'max'`
%     Choose between `'max'` and `'avg'` (average) pooling.
%
%   `Subdivisions`:: `[1 1]`
%     Specifies the number [SH,SW] of vertical and horizontal tiles of
%     a region. This makes the output a SH x SW x C x K array.
%
%   `Transform`:: `1`
%     Specifies a spatial transformation to apply to region vertices before
%     they are applied to the input tensor. If T is a scalar, then
%     the transformation is a scaling centered at the origin:
%
%        u' = T (u - 1) + 1,
%        v' = T (v - 1) + 1.
%
%     If T is a 2D vector, then different scaling factors for the
%     `u` and `v` can be specified. Finally, if T is a 2 x 2 matrix, then:
%
%        u' = T(1,1) u + T(1,2) v + T(1,3),
%        v' = T(2,1) u + T(2,2) v + T(2,3).
%
%     Note that only the upper-left and bottom-right corners of each
%     rectangular region are transformed. Thus this is mostly useful
%     for axis-aligned transformations; the generality of the expression
%     allows, however, to swap `u` and `v`, which may be needed
%     to match different conventions for the box coordiantes.
%
%   See also: VL_NNPOOL().

% Copyright (C) 2016 Hakan Bilen, Abishek Dutta, and Andrea Vedaldi.
% All rights reserved.
%
% This file is part of the VLFeat library and is made available under
% the terms of the BSD license (see the COPYING file).


function cost = snd_costfunction(mpcModel, u, varargin)

%%
% costfunction(mpcModel, u, varargin)
%UNTITLED3 Summary of this function goes here
%	evaluates the cost function of the
%   optimal control problem over the horizon
%   N with sampling time T for the current
%   data of the optimization method t0, snd.xmeasure
%  	and u.
% 	The function return the computed cost
%	function value.

    cost = 0;
    x = zeros(mpcModel.horizon+1, length(mpcModel.xmeasure));
    x = snd_computeOpenloopSolution(mpcModel, u );

    for k=1:mpcModel.horizon
        cost = cost+mpcModel.runningcosts(k, x(k,:), u(:,k), mpcModel.u0_ref, mpcModel.battery); %, varargin
    end
    cost = cost+ 0.5*mpcModel.terminalcosts((mpcModel.horizon+1), x(mpcModel.horizon+1,:));
     %, varargin
end


function gridplot(xy,ev,bound,ebound)
%gridplot   quadrilateral grid verification
%   gridplot(xy,ev,bound,ebound);
%
%   IFISS function: DJS; 7 May 2006.
% Copyright (c) 2006 D.J. Silvester, H.C. Elman, A. Ramage
fprintf('\nGrid logistics ..\n')
nvtx=length(xy(:,1));
fprintf('  %g nodes \n',nvtx)
nelement=length(ev(:,1));
fprintf('  %g elements \n',nelement)
nboundvtx=length(bound);
fprintf('  %g nodes on Dirichlet boundary \n',nboundvtx)
nboundedge=length(ebound(:,1));
fprintf('  %g element edges on Dirichlet boundary \n\n',nboundedge)
%
%
adj=sparse(nvtx,nvtx); adx=sparse(nvtx,nvtx);
for i=1:nelement
   adj(ev(i,1),ev(i,2)) =1;
   adj(ev(i,2),ev(i,3)) =1;
   adj(ev(i,3),ev(i,4)) =1;
   adj(ev(i,4),ev(i,1)) =1;
end
%
%% define element edges
adjb=sparse(nvtx,nvtx);
% bottom boundary edges
k1=find(ebound(:,2)==1)';
for k=ebound(k1)
   adjb(ev(k,1),ev(k,2))=1;
end
% right boundary edges
k2=find(ebound(:,2)==2)';
for k=ebound(k2)
   adjb(ev(k,2),ev(k,3))=1;
end
% top boundary edges
k3=find(ebound(:,2)==3)';
for k=ebound(k3)
   adjb(ev(k,3),ev(k,4))=1;
end
% left boundary edges
k4=find(ebound(:,2)==4)';
for k=ebound(k4)
   adjb(ev(k,4),ev(k,1))=1;
end
%
figure(1)
gplot(adj,xy,'b')
hold on
stnode=int2str([1:nvtx]');
text(xy(:,1),xy(:,2),stnode)
axis('equal'),axis('off')
title('Indices of nodes of the element grid')
hold off
figure(2)
gplot(adj,xy,'b')
hold on
gplot(adjb,xy,'r')
xybd=xy(bound,:);
stbd=int2str([1:nboundvtx]');
text(xybd(:,1),xybd(:,2),stbd,'color','black')
title('Indices of nodes on the Dirichlet boundary')
axis('equal'),axis('off')
hold off
return


function net  = merge_batch_norm(net)
% MERGE_BATCH_NORM function merges Batch Normalization layers into preceding Conv layers.
%
%   NET = merge_batch_norm(NET)
%
% Authors: F. Radenovic, G. Tolias, O. Chum. 2017.

  % find BatchNorm layers
  names = dagFindLayersOfType(net, 'dagnn.BatchNorm') ;

  % if no BatchNorm return
  if isempty(names), return;  end

  fprintf('>> Merging batch norm layers with the preceding conv layers\n');
  for name = names
    name = char(name) ;
    layer = net.layers(net.getLayerIndex(name)) ;

    % merge into previous conv layer
    playerName = dagFindLayersWithOutput(net, layer.inputs{1}) ;
    playerName = playerName{1} ;
    playerIndex = net.getLayerIndex(playerName) ;
    player = net.layers(playerIndex) ;
    if ~isa(player.block, 'dagnn.Conv')
      error('!!! Batch normalization cannot be merged as it is not preceded by a conv layer.') ;
    end

    % if the convolution layer does not have a bias,
    % recreate it to have one
    if ~player.block.hasBias
      block = player.block ;
      block.hasBias = true ;
      net.renameLayer(playerName, 'tmp') ;
      net.addLayer(playerName, ...
                   block, ...
                   player.inputs, ...
                   player.outputs, ...
                   {player.params{1}, sprintf('%s_b',playerName)}) ;
      net.removeLayer('tmp') ;
      playerIndex = net.getLayerIndex(playerName) ;
      player = net.layers(playerIndex) ;
      biases = net.getParamIndex(player.params{2}) ;
      net.params(biases).value = zeros(block.size(4), 1, 'single') ;
    end

    filters = net.getParamIndex(player.params{1}) ;
    biases = net.getParamIndex(player.params{2}) ;
    multipliers = net.getParamIndex(layer.params{1}) ;
    offsets = net.getParamIndex(layer.params{2}) ;
    moments = net.getParamIndex(layer.params{3}) ;

    [filtersValue, biasesValue] = mergeBatchNorm(...
      net.params(filters).value, ...
      net.params(biases).value, ...
      net.params(multipliers).value, ...
      net.params(offsets).value, ...
      net.params(moments).value) ;

    net.params(filters).value = filtersValue ;
    net.params(biases).value = biasesValue ;
  end

  % Remove Batch Norm layers, they are already merged
  names = dagFindLayersOfType(net, 'dagnn.BatchNorm') ;
  for i = 1:numel(names)
    layer = net.layers(net.getLayerIndex(names{i})) ;
    net.removeLayer(names{i}) ;
    net.renameVar(layer.outputs{1}, layer.inputs{1}, 'quiet', true) ;
  end

  % -------------------------------------------------------------------------
  function layers = dagFindLayersWithOutput(net, outVarName)
  % -------------------------------------------------------------------------
  layers = {} ;
  for l = 1:numel(net.layers)
    if any(strcmp(net.layers(l).outputs, outVarName))
      layers{1,end+1} = net.layers(l).name ;
    end
  end

  % -------------------------------------------------------------------------
  function layers = dagFindLayersOfType(net, type)
  % -------------------------------------------------------------------------
  layers = [] ;
  for l = 1:numel(net.layers)
    if isa(net.layers(l).block, type)
      layers{1,end+1} = net.layers(l).name ;
    end
  end

  % -------------------------------------------------------------------------
  function [filters, biases] = mergeBatchNorm(filters, biases, multipliers, offsets, moments)
  % -------------------------------------------------------------------------
  % wk / sqrt(sigmak^2 + eps)
  % bk - wk muk / sqrt(sigmak^2 + eps)
  a = multipliers(:) ./ moments(:,2) ;
  b = offsets(:) - moments(:,1) .* a ;
  biases(:) = biases(:) + b(:) ;
  sz = size(filters) ;
  numFilters = sz(4) ;
  filters = reshape(bsxfun(@times, reshape(filters, [], numFilters), a'), sz) ;


function [tri, inds] = triangulateFaces(faces)
%TRIANGULATEFACES Convert face array to an array of triangular faces
%
%   TRI = triangulateFaces(FACES)
%   Returns a 3-columns array of indices, based on the data stored in the
%   argument FACES:
%   - if FACES is a N-by-3 array, returns the same array
%   - if FACES is a N-by-4 array, returns an array with 2*N rows and 3
%       columns, splitting each square into 2 triangles (uses first and
%       third vertex of each square as diagonal).
%   - if FACES is a cell array, split each face into a set of triangles,
%       and returns the union of all triangles. Faces are assumed to be
%       convex.
%
%   [TRI INDS] = triangulateFaces(FACES)
%   Also returns original face index of each new triangular face. INDS has
%   the same number of rows as TRI, and has values between 1 and the
%   number of rows of the original FACES array.
%
%
%   Example
%     % create a basic shape
%     [n e f] = createCubeOctahedron;
%     % draw with plain faces
%     figure;
%     drawMesh(n, f);
%     % draw as a triangulation
%     tri = triangulateFaces(f);
%     figure;
%     patch('vertices', n, 'faces', tri, 'facecolor', 'r');
%
%   See also
%   meshes3d, drawMesh, mergeCoplanarFaces
%

% ------
% Author: David Legland
% e-mail: david.legland@nantes.inra.fr
% Created: 2008-09-08,    using Matlab 7.4.0.287 (R2007a)
% Copyright 2008 INRA - BIA PV Nantes - MIAJ Jouy-en-Josas.

%% Tri mesh case: return original set of faces

if isnumeric(faces) && size(faces, 2) == 3
    tri = faces;
    if nargout > 1
        inds = (1:size(faces, 1))';
    end
    return;
end

%% Square faces: split each square into 2 triangles

if isnumeric(faces) && size(faces, 2) == 4
    nf = size(faces, 1);
    tri = zeros(nf * 2, 3);
    tri(1:2:end, :) = faces(:, [1 2 3]);
    tri(2:2:end, :) = faces(:, [1 3 4]);

    if nargout > 1
        inds = kron(1:size(faces, 1), ones(1,2))';
    end

    return;
end

%% Pentagonal faces (for dodecahedron...): split into 3 triangles

if isnumeric(faces) && size(faces, 2) == 5
    nf = size(faces, 1);
    tri = zeros(nf * 3, 3);
    tri(1:3:end, :) = faces(:, [1 2 3]);
    tri(2:3:end, :) = faces(:, [1 3 4]);
    tri(3:3:end, :) = faces(:, [1 4 5]);

    if nargout > 1
        inds = kron(1:size(faces, 1), ones(1,2))';
    end

    return;
end

%% Faces as cell array

% number of faces
nf  = length(faces);

% compute total number of triangles
ni = zeros(nf, 1);
for i = 1:nf
    % as many triangles as the number of vertices minus 1
    ni(i) = length(faces{i}) - 2;
end
nt = sum(ni);

% allocate memory for triangle array
tri = zeros(nt, 3);
inds = zeros(nt, 1);

% convert faces to triangles
t = 1;
for i = 1:nf
    face = faces{i};
    nv = length(face);
    v0 = face(1);
    for j = 3:nv
        tri(t, :) = [v0 face(j-1) face(j)];
        inds(t) = i;
        t = t + 1;
    end
end


function [clustCent,data2cluster,cluster2dataCell] = mean_shift_algorithm(dataPts,bandwidth,threshold);

[dim_dataset,no_data_dataset] = size(dataPts);
no_cluster = 0;         bandSq = (bandwidth).^2;
dataset_index = 1:no_data_dataset;
threshold_convergence =  threshold;% bandwidth(1,1)*exp(-3);  % this condition is taken from a reference paper on the web
tracking_array= false(1,no_data_dataset); % tracking: if a points been seen already
no_point_4_initial = no_data_dataset; % number of points to posibaly use as initilization points
clusterV = zeros(1,no_data_dataset,'uint16'); % cluster allotment method
clustMembsCell = [];
clustCent = []; % center of clust

while no_point_4_initial
    % choosing random data set for and then converging it
    random_index = ceil( (no_point_4_initial-1e-6)*rand); % pick a random seed point
    random_data_point = dataset_index(random_index); % use this point as start of mean
    mean_cur = dataPts(:,random_data_point);  % intilize mean to this points location
    cluster_members = []; % points that will get added to this cluster
    cluster_mem = zeros(1,no_data_dataset,'uint16');
    % convergence loop
    while true
        squ_Euclidean_distance(1,:) = sum(bsxfun(@minus,mean_cur(1:2,:),dataPts(1:2,:)).^2); % dist squared from mean to all points still active
        squ_Euclidean_distance(2,:) = sum(bsxfun(@minus,mean_cur(3:5,:),dataPts(3:5,:)).^2);
        kernel_range_datapoint_index = find(squ_Euclidean_distance(1,:) < bandSq(1,1)  );% points within bandWidth
        kernel_range_datapoint_index= find(squ_Euclidean_distance(2,:) < bandSq(1,2) );
        cluster_mem(kernel_range_datapoint_index) = cluster_mem(kernel_range_datapoint_index)+1;
        mean_previous = mean_cur; % save the old mean
        mean_cur = gaussian_kernel(dataPts(:,kernel_range_datapoint_index),sqrt(squ_Euclidean_distance(1,kernel_range_datapoint_index)),sqrt(squ_Euclidean_distance(2,kernel_range_datapoint_index)),bandwidth); % compute the new mean
        cluster_members = [cluster_members kernel_range_datapoint_index]; % add any point within bandWidth to the cluster
        tracking_array(cluster_members) = true; % mark that these points have been visited
        % converging condition
        if norm(mean_cur-mean_previous) < threshold_convergence
            join_cluster = 0;
            for cno = 1:no_cluster
                dist1 = norm(mean_cur(1:2)-clustCent(1:2,cno)); % spatial
                dist2 = norm(mean_cur(3:5)-clustCent(3:5,cno)); %range
                if( dist1 < bandwidth(1,1) &&dist2<bandwidth(1,2)) % condition to join the kernel
                    join_cluster = cno;
                    break;
                end
            end

            if join_cluster > 0
                nc = numel(cluster_members);
                no = numel(clustMembsCell{join_cluster});
                nw = [nc;no]/(nc+no);
                clustMembsCell{join_cluster} = unique([clustMembsCell{join_cluster},cluster_members]);
                clustCent(:,join_cluster) = mean_cur*nw(1) + mean_previous*nw(2);
                clusterV(join_cluster,:) = clusterV(join_cluster,:) + cluster_mem;
            else
                no_cluster = no_cluster+1;
                clustCent(:,no_cluster) = mean_cur;
                clustMembsCell{no_cluster} = cluster_members;
                clusterV(no_cluster,:) = cluster_mem;
            end
            break;
        end
    end
    dataset_index = find(~tracking_array);
    no_point_4_initial = length(dataset_index);
end
[~,data2cluster] = max(clusterV,[],1);
if nargout > 2
    cluster2dataCell = cell(no_cluster,1);
    for cno = 1:no_cluster
        cluster_members = find(data2cluster == cno);
        cluster2dataCell{cno} = cluster_members;
    end
end

end


function y = powcone(x,y,z,alpha)
%POWCONE Defines a power cone x^alpha y^(1-alpha) > norm(z)
%
% Input
%    x,y,z     : SDPVAR objects or doubles
%    alpha     : scalar double 0<=alpha<=1
%
% Example
%    F = pcone(x,y,z,alpha)
%
% An alternative syntax with only one argument is also possible
%    F = pcone(Z) # where Z = [x;y;z;alpha]
%
% A vectorized version is also possible
%    F = pcone(Z) # where Z(:,i) = [x;y;z;alpha]
%
% See also @sdpvar/CONE, @sdpvar/EXPCONE

if nargin == 1
    [n,m] = size(x);
    if n < 4
        error('x must be a vector or matrix of height 4 or more ')
    end
    y = x;
    if m > 1
        y.typeflag = 58;
    else
        y.typeflag = 20;
    end
    y = lmi(y);
else
    y = powcone([x;y;reshape(z,[],1);alpha]);
end


function G = getGroupSuperNonOverlapColor(I, param)

    N = size(I,1) * size(I, 2);

    g = sparse(N,N);

    imlab = vl_xyz2lab(vl_rgb2xyz(I)) ;
    imlab = single(imlab);
    slicParam = param.superpixel.slicParam;

    groupCount = 0;

    segments = vl_slic(imlab, slicParam(1,1),  slicParam(1,2)) ;
    segments = segments(:);

    for j = 0:segments(N)
        g(:, groupCount+j+1) = segments==j;
    end
    groupCount  = groupCount+ segments(N)+1;

    % croping G
    g =g(:, 1:groupCount);

%     G = [g;g;g];

    groupCount = size(g,2);

    G = sparse( 3*N, 3*groupCount);

    G(1:N, 1:groupCount) = g;
    G(N+1:2*N, groupCount+1:2*groupCount) =g;
    G(2*N+1:3*N, 2*groupCount+1:3*groupCount) =g;
end


%  anova2_cell() - compute F-values in cell array using ANOVA.
%
% Usage:
%    >> [FC FR FI dfc dfr dfi] = anova2_cell( data );
%
% Inputs:
%   data       = data consisting of PAIRED arrays to be compared. The last
%                dimension of the data array is used to compute ANOVA.
% Outputs:
%   FC   - F-value for columns.
%   FR   - F-value for rows.
%   FI   - F-value for interaction.
%   dfc  - degree of freedom for columns.
%   dfr  - degree of freedom for rows.
%   dfi  - degree of freedom for interaction.
%
% Note: the advantage over the ANOVA2 function of Matlab statistical
%       toolbox is that this function works on arrays (see examples). Note
%       also that you still need the statistical toolbox to assess
%       significance using the fcdf() function. The other advantage is that
%       this function will work with complex numbers.
%
% Example:
%   a = { rand(1,10) rand(1,10) rand(1,10); rand(1,10) rand(1,10) rand(1,10) }
%   [FC FR FI dfc dfr dfi] = anova2_cell(a)
%   signifC = 1-fcdf(FC, dfc(1), dfc(2))
%   signifR = 1-fcdf(FR, dfr(1), dfr(2))
%   signifI = 1-fcdf(FI, dfi(1), dfi(2))
%
%   % for comparison
%   anova2(  [ a{1,1}' a{1,2}' a{1,3}'; a{2,1}' a{2,2}' a{2,3}' ], 10)
%
%   b = { [ a{1,1}; a{1,1} ] [ a{1,2}; a{1,2} ] [ a{1,3}; a{1,3} ];
%         [ a{2,1}; a{2,1} ] [ a{2,2}; a{2,2} ] [ a{2,3}; a{2,3} ] }
%   [FC FR FI dfc dfr dfi] = anova2_cell(b)
%
%   c{1,1} = reshape(repmat(b{1,1}, [2 1]),2,2,10);
%   c{1,2} = reshape(repmat(b{1,2}, [2 1]),2,2,10);
%   c{1,3} = reshape(repmat(b{1,3}, [2 1]),2,2,10);
%   c{2,3} = reshape(repmat(b{2,3}, [2 1]),2,2,10);
%   c{2,2} = reshape(repmat(b{2,2}, [2 1]),2,2,10);
%   c{2,1} = reshape(repmat(b{2,1}, [2 1]),2,2,10)
%   [FC FR FI dfc dfr dfi] = anova2_cell(c)
%
% Author: Arnaud Delorme, SCCN/INC/UCSD, La Jolla, 2005
%
% Reference:
%   Schaum's outlines in statistics (3rd edition). 1999. Mc Graw-Hill.

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

function [FC, FR, FI, freeC, freeR, freeI] = anova2_cell(data)

    % compute all means and all std
    % -----------------------------
    a = size(data,1);
    b = size(data,2);
    nd = myndims( data{1} );
    c  = size(data{1}, nd);

    % dataabs if for complex data only
    % --------------------------------
    dataabs = data;
    if ~isreal(data{1})
        for i = 1:a
            for ii = 1:b
                dataabs{i,ii} = abs(data{i,ii});
            end;
        end;
    end;

    if nd == 1

        VE = 0;
        m  = zeros( size(data), 'single' );
        for i = 1:a
            for ii = 1:b
                m(i,ii) = mymean(data{i,ii});
                VE      = VE+sum( (dataabs{i,ii}-m(i,ii)).^2 );
            end;
        end;
        X  = mean(mean(m));
        Xj = mean(m,2);
        Xk = mean(m,1);
        VR = b*c*sum( (Xj-X).^2 );
        VC = a*c*sum( (Xk-X).^2 );

        Xj = repmat(Xj, [1 size(m,2) ]);
        Xk = repmat(Xk, [size(m,1)  1]);
        VI = c*sum( sum( ( m - Xj - Xk + X ).^2 ) );

    elseif nd == 2

        VE = zeros( size(data{1},1),1, 'single');
        m  = zeros( [ size(data{1},1) size(data) ], 'single' );
        for i = 1:a
            for ii = 1:b
                tmpm = mymean(data{i,ii}, 2);
                m(:,i,ii) = tmpm;
                VE        = VE+sum( (dataabs{i,ii}-repmat(tmpm, [1 size(data{i,ii},2)])).^2, 2);
            end;
        end;
        X  = mean(mean(m,3),2);
        Xj = mean(m,3);
        Xk = mean(m,2);
        VR = b*c*sum( (Xj-repmat(X, [1 size(Xj,2)])).^2, 2 );
        VC = a*c*sum( (Xk-repmat(X, [1 1 size(Xk,3)])).^2, 3 );

        Xj = repmat(Xj, [1 1 size(m,3) ]);
        Xk = repmat(Xk, [1 size(m,2)  1]);
        VI = c*sum( sum( ( m - Xj - Xk + repmat(X, [1 size(m,2) size(m,3)]) ).^2, 3), 2 );

    elseif nd == 3

        VE = zeros( size(data{1},1), size(data{1},2), 'single' );
        m  = zeros( [ size(data{1},1) size(data{1},2) size(data) ], 'single' );
        for i = 1:a
            for ii = 1:b
                tmpm = mymean(data{i,ii}, 3);
                m(:,:,i,ii) = tmpm;
                VE          = VE+sum( (dataabs{i,ii}-repmat(tmpm, [1 1 size(data{i,ii},3)])).^2, 3);
            end;
        end;
        X  = mean(mean(m,4),3);
        Xj = mean(m,4);
        Xk = mean(m,3);
        VR = b*c*sum( (Xj-repmat(X, [1 1 size(Xj,3)  ])).^2, 3 );
        VC = a*c*sum( (Xk-repmat(X, [1 1 1 size(Xk,4)])).^2, 4 );

        Xj = repmat(Xj, [1 1 1 size(m,4) ]);
        Xk = repmat(Xk, [1 1 size(m,3)  1]);
        VI = c*sum( sum( ( m - Xj - Xk + repmat(X, [1 1 size(m,3) size(m,4)]) ).^2, 4 ), 3 );

    else % nd == 4

        VE = zeros( size(data{1},1), size(data{1},2), size(data{1},3), 'single' );
        m  = zeros( [ size(data{1},1) size(data{1},2) size(data{1},3) size(data) ], 'single' );
        for i = 1:a
            for ii = 1:b
                tmpm = mymean(data{i,ii}, 4);
                m(:,:,:,i,ii) = tmpm;
                VE            = VE+sum( (dataabs{i,ii}-repmat(tmpm, [1 1 1 size(data{i,ii},4)])).^2, 4);
            end;
        end;
        X  = mean(mean(m,5),4);
        Xj = mean(m,5);
        Xk = mean(m,4);
        VR = b*c*sum( (Xj-repmat(X, [1 1 1 size(Xj,4)  ])).^2, 4 );
        VC = a*c*sum( (Xk-repmat(X, [1 1 1 1 size(Xk,5)])).^2, 5 );

        Xj = repmat(Xj, [1 1 1 1 size(m,5) ]);
        Xk = repmat(Xk, [1 1 1 size(m,4)  1]);
        VI = c*sum( sum( ( m - Xj - Xk + repmat(X, [1 1 1 size(m,4) size(m,5)]) ).^2, 5 ), 4 );

    end;

    SR2 = VR/(a-1);
    SC2 = VC/(b-1);
    SI2 = VI/(a-1)/(b-1);
    SE2 = VE/(a*b*(c-1));

    FR = SR2./SE2; % rows
    FC = SC2./SE2; % columns
    FI = SI2./SE2; % interaction

    freeR = [ a-1 a*b*(c-1) ];
    freeC = [ b-1 a*b*(c-1) ];
    freeI = [ (a-1)*(b-1) a*b*(c-1) ];

function val = myndims(a)
    if ndims(a) > 2
        val = ndims(a);
    else
        if size(a,1) == 1,
            val = 2;
        elseif size(a,2) == 1,
            val = 1;
        else
            val = 2;
        end;
    end;

function res = mymean( data, varargin) % deal with complex numbers
    res = mean( data, varargin{:});
    if ~isreal(data)
        res = abs( res );
    end;