function [eigvector, eigvalue] = IsoP(options, data)
% IsoP: Isometric Projection
%
%       [eigvector, eigvalue] = IsoP(options, data)
%
%             Input:
%               data    - Data matrix. Each row vector of data is a data point.
%
%               options - Struct value in Matlab. The fields in options
%                         that can be set:
%
%                      NeighborMode -  Indicates how to construct the graph. Choices
%                           are:
%                           'KNN'     -  Put an edge between two nodes if and
%                                        only if they are among the k nearst
%                                        neighbors of each other. Default
%                                        option.
%                       'Supervised'  -  Two variations:
%                                       1. k=0, Put an edge between two nodes
%                                          if and only if they belong to
%                                          same class.
%                                       2. k>0, The distance between two nodes
%                                          in the same class will be smaller than
%                                          two nodes have diff. labels
%                                          The label information 'gnd' should be
%                                          provided.
%
%                       k           -   The number of neighbors.
%                                       Default k = 5;
%                       gnd         -   The parameter needed under 'Supervised'
%                                       NeighborMode.  Colunm vector of the label
%                                       information for each data point.
%
%                         Please see LGE.m for other options.
%
%
%             Output:
%               eigvector - Each column is an embedding function, for a new
%                           data point (row vector) x,  y = x*eigvector
%                           will be the embedding result of x.
%               eigvalue  - The eigvalue of LPP eigen-problem. sorted from
%                           smallest to largest.
%               elapse    - Time spent on different steps
%
%
%    Examples:
%
%
%
%       fea = rand(50,70);
%       gnd = [ones(10,1);ones(15,1)*2;ones(10,1)*3;ones(15,1)*4];
%       options = [];
%       options.k = 0;
%       options.NeighborMode = 'Supervised';
%       options.gnd = gnd;
%       [eigvector, eigvalue] = IsoP(options, fea);
%       Y = fea*eigvector;
%
%
%
% See also LPP, LGE
%
%Reference:
%
%   Deng Cai, Xiaofei He, and Jiawei Han, "Isometric Projection",
%   Twenty-Second Conference on Artificial Intelligence (AAAI-07), 2007
%
%   Deng Cai, Xiaofei He and Jiawei Han, "Isometric Projection", Technical
%   report, Computer Science Department, UIUC, UIUCDCS-R-2006-2747, July 2006
%
%   Joshua B. Tenenbaum, Vin de Silva, and John C. Langford. "A Global
%   Geometric Framework for Nonlinear Dimensionality Reduction", Science,
%   v.290 no.5500 , Dec.22, 2000. pp.2319-2323.
%
%
%   version 2.1 --June/2007
%   version 2.0 --May/2007
%   version 1.1 --May/2006
%   version 1.0 --Nov/2005
%
%   Written by Deng Cai (dengcai2 AT cs.uiuc.edu)

INFratio = 1000;

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

if ~isfield(options,'NeighborMode')
    options.NeighborMode = 'KNN';
end

if ~isfield(options,'k')
    options.k = 5;
end

nSmp = size(data,1);

if options.k >= nSmp
    error('k is too large!');
end

if options.k <= 0  % Always supervised!
    if ~isfield(options,'gnd')
        error('gnd should be provided!');
    end
    if length(options.gnd) ~= nSmp
        error('gnd and data mismatch!');
    end

    Label = unique(options.gnd);
    nLabel = length(Label);

    G = zeros(nSmp,nSmp);
    for i=1:nLabel
        classIdx = find(options.gnd==Label(i));
        D = EuDist2(data(classIdx,:),[],1);
        G(classIdx,classIdx) = D;
    end
    maxD = max(max(G));
    INF = maxD*INFratio;  % effectively infinite distance

    D = INF*ones(nSmp,nSmp);
    for i=1:nLabel
        classIdx = find(options.gnd==Label(i));
        D(classIdx,classIdx) = G(classIdx,classIdx);
    end

    clear G
else
    switch lower(options.NeighborMode)
        case {lower('KNN')}
            D = EuDist2(data);
            maxD = max(max(D));
            INF = maxD*INFratio;  % effectively infinite distance

            [dump,iidx] = sort(D,2);
            iidx = iidx(:,(2+options.k):end);
            for i=1:nSmp
                D(i,iidx(i,:)) = 0;
            end
            D = max(D,D');

            D = sparse(D);
            D = dijkstra(D, 1:nSmp);

            D = reshape(D,nSmp*nSmp,1);
            infIdx = find(D==inf);
            if ~isempty(infIdx)
                D(infIdx) = INF;
            end
            D = reshape(D,nSmp,nSmp);

        case {lower('Supervised')}
            if ~isfield(options,'gnd')
                error('gnd should be provided!');
            end
            if length(options.gnd) ~= nSmp
                error('gnd and data mismatch!');
            end

            Label = unique(options.gnd);
            nLabel = length(Label);

            G = zeros(nSmp,nSmp);
            maxD = 0;
            for idx=1:nLabel
                classIdx = find(options.gnd==Label(idx));
                nSmpClass = length(classIdx);
                D = EuDist2(data(classIdx,:),[],1);
                if maxD < max(max(D))
                    maxD = max(max(D));
                end
                if options.k >= nSmpClass
                    G(classIdx,classIdx) = D;
                else
                    [dump,iidx] = sort(D,2);
                    iidx = iidx(:,(2+options.k):end);
                    for i=1:nSmpClass
                        D(i,iidx(i,:)) = 0;
                    end
                    D = max(D,D');
                    D = sparse(D);
                    D = dijkstra(D, 1:nSmpClass);
                    G(classIdx,classIdx) = D;
                end
            end

            INF = maxD*INFratio;  % effectively infinite distance

            D = INF*ones(nSmp,nSmp);
            for i=1:nLabel
                classIdx = find(options.gnd==Label(i));
                D(classIdx,classIdx) = G(classIdx,classIdx);
            end
            clear G

        otherwise
            error('NeighborMode does not exist!');
    end
end

S = D.^2;
sumS = sum(S);
H = sumS'*ones(1,nSmp)/nSmp;
TauDg = -.5*(S - H - H' + sum(sumS)/(nSmp^2));

TauDg = max(TauDg,TauDg');

%==========================
% If data is too large, the following centering codes can be commented
%==========================
if isfield(options,'keepMean') && options.keepMean
else
    if issparse(data)
        data = full(data);
    end
    sampleMean = mean(data);
    data = (data - repmat(sampleMean,nSmp,1));
end
%==========================

[eigvector, eigvalue] = LGE(TauDg, [], options, data);

eigIdx = find(eigvalue < 1e-3);
eigvalue (eigIdx) = [];
eigvector(:,eigIdx) = [];


function X = recon(D,P)

X = D.*cos(P) + i*D.*sin(P);


function [ net,res,opts ] = lstm_bp( net,res,opts )
%LSTM_BP Summary of this function goes here
%   Detailed explanation goes here

    n_frames=opts.parameters.n_frames;
    n_cell_nodes=opts.parameters.n_hidden_nodes;

    %1: calculate the gradients of the data fitting transform

    for f=1:n_frames
        opts.dzdy=res.Fit{f}(numel(net{end}.layers)+1).dzdx;
        [net{4},res.Fit{f},opts] = net_bp(net{4},res.Fit{f},opts);
    end

    %2: BPTT: calculate the gradient wrt memory cell

    dzdc=0;
    for f=n_frames:-1:1
        %gradient from the output gate
        opts.dzdy=res.Gates{f}(end).x(2*n_cell_nodes+1:3*n_cell_nodes,:).*res.Fit{f}(1).dzdx;
        [net{3},res.Cell{f+1},opts] = net_bp(net{3},res.Cell{f+1},opts);
        %
        res.Cell{f+1}(1).dzdx=dzdc+res.Cell{f+1}(1).dzdx;
        dzdc=res.Cell{f+1}(1).dzdx.*res.Gates{f}(end).x(n_cell_nodes+1:2*n_cell_nodes,:);
    end

    res.Cell{1}(end+1).x=0;%just some padding

    %3: calculate the gradients of the input transform
    for f=1:n_frames
        opts.dzdy= res.Gates{f}(end).x(1:n_cell_nodes,:).*res.Cell{f+1}(1).dzdx;
        [net{2},res.Input{f},opts] = net_bp(net{2},res.Input{f},opts);
    end

    %4: calculate the gradients of the input,forget,output gates:
    for f=1:n_frames
        %input gate gradient;forget gate gradient; output gate gradient;
        opts.dzdy=[ res.Input{f}(end).x .*res.Cell{f+1}(1).dzdx;...
            res.Cell{f}(1).x .*res.Cell{f+1}(1).dzdx;...
            res.Fit{f}(1).dzdx.*res.Cell{f+1}(end).x];
        [net{1},res.Gates{f},opts] = net_bp(net{1},res.Gates{f},opts);
    end

    %%%accumulate gradients in all time frames

    res.Fit=average_gradients_in_frames(res.Fit);
    res.Input=average_gradients_in_frames(res.Input);
    res.Gates=average_gradients_in_frames(res.Gates);
    res.Cell=average_gradients_in_frames(res.Cell);

end


function cS =  biotite
% Mica

cs_Bt = crystalSymmetry('2/m',[0.577 1 1.105], [90, 100.2, 90]*degree);
N = Miller({0,0,1},{0,1,0},{3,3,1},cs_Bt);
dist = [0.2, 1, 5];
cS = crystalShape(N./dist);


function [overlap, only1, only2] = calculate_overlap(T1, T2, bounds)
% calculate_overlap  Calculates overlap for two trajectories
%
% The function calculates per-frame overlap between two trajectories. Besides the
% region overlap the function also returns cointainment of the second trajectory in the
% first and containment of the first trajectory in the second.
%
% If the trajectories are not of equal length, then the overlaps are calculated up
% to the end of the shorter one.
%
% Input:
% - T1 (cell): The first trajectory.
% - T2 (cell): The second trajectory.
% - bounds (vector): An optional bounds of valid region where the overlap is calculated.
%
% Output:
% - overlap: A vector of per-frame overlaps.
% - only1: A vector of per-frame containment of the second trajectory in the first.
% - only2: A vector of per-frame containment of the first trajectory in the second.

len = min(size(T1, 1), size(T2, 1));
T1 = T1(1:len, :);
T2 = T2(1:len, :);

if (~iscell(T1))
    T1 = num2cell(T1, 2);
end

if (~iscell(T2))
    T2 = num2cell(T2, 2);
end

if nargin < 3
    bounds = [];
end

if get_global_variable('legacy_rasterization', true)
    mode = 'legacy';
else
    mode = 'default';
end;

results = region_overlap(T1, T2, bounds, mode);

%results = cell2mat(cellfun(@(r1, r2) region_overlap(r1, r2), T1, T2, 'UniformOutput', false));

overlap = results(:, 1);
only1 = results(:, 2);
only2 = results(:, 3);


% Test file for chebtech/minandmax.m

function pass = test_minandmax(pref)

% Get preferences.
if ( nargin < 1 )
    pref = chebtech.techPref();
end

for n = 1:2
    if ( n == 1 )
        testclass = chebtech1();
    else
        testclass = chebtech2();
    end

    %%
    % Spot-check the extrema for a few functions.

    pass(n, 1) = test_spotcheck_minmax(testclass, @(x) ...
        ((x-0.2).^3 -(x-0.2) + 1).*sec(x-0.2), ...
        0.710869767377087, 1.884217141925336, pref);
    pass(n, 2) = test_spotcheck_minmax(testclass, @(x) sin(10*x), -1, 1, pref);
    pass(n, 3) = test_spotcheck_minmax(testclass, @airy, airy(1), airy(-1), ...
        pref);
    pass(n, 4) = test_spotcheck_minmax(testclass, @(x) -1./(1 + x.^2), -1, ...
        -0.5, pref);
    pass(n, 5) = test_spotcheck_minmax(testclass, ...
        @(x) (x - 0.25).^3.*cosh(x), ...
        (-1.25)^3*cosh(-1), 0.75^3*cosh(1), pref);

    %%
    % Check operation for array-valued inputs.

    fun_op = @(x) [sin(10*x) airy(x) (x - 0.25).^3.*cosh(x)];
    f = testclass.make(fun_op, [], pref);
    [y, x] = minandmax(f);
    y_exact = [-1 airy(1)  (-1.25)^3*cosh(-1);
                1 airy(-1) 0.75^3*cosh(1)];

    pass(n, 6) = all(abs(y(:) - y_exact(:)) < 10*max(vscale(f)*eps));

    % Check that the points x are indeed extreme points of the function
    % operator.
    for k = 1:1:size(f.coeffs, 2)
        fx = fun_op(x(:, k));
        if ( max(abs(fx(:, k) - y_exact(:, k))) > 1e1*max(vscale(f)*eps) )
            pass(n, 6) = 0;
            break;
        end
    end

    % Test complex-array-valued CHEBTECH objects.
    f = testclass.make(@(x) [exp(sin(2*x)), 1i*cos(20*x)]);
    [vals, pos] = minandmax(f);
    f1 = testclass.make(@(x) exp(sin(2*x)));
    [vals1, pos1] = minandmax(f1);
    f2 = testclass.make(@(x) 1i*cos(20*x));
    [vals2, pos2] = minandmax(f2);
    pass(n, 7) = norm(abs(vals) - abs([vals1 vals2]), inf) < ...
        1e2*max(vscale(f)*eps);
    % Note, we don't expect pos(:,2) = pos2 as the min and max are not unique.
    pass(n, 8) = norm(pos(:,1) - pos1, inf) < 500*max(vscale(f)*eps);

end

end

% Spot-check the results for a given function.
function result = test_spotcheck_minmax(testclass, fun_op, exact_min, ...
    exact_max, pref)

f = testclass.make(fun_op, [], pref);
[y, x] = minandmax(f);
y_exact = [exact_min ; exact_max];
fx = fun_op(x);
result = ((max(abs(y - y_exact)) < 10*vscale(f)*eps) && ...
          (max(abs(fx - y_exact)) < 10*vscale(f)*eps));

end


function [chd,Ichd] = ffmSubdivide(X,prt,edg,fig)
%+========================================================================+
%|                                                                        |
%|         OPENFFM - LIBRARY FOR FAST AND FREE MEMORY CONVOLUTION         |
%|           openFfm is part of the GYPSILAB toolbox for Matlab           |
%|                                                                        |
%| COPYRIGHT : Matthieu Aussal (c) 2017-2019.                             |
%| PROPERTY  : Centre de Mathematiques Appliquees, Ecole polytechnique,   |
%| route de Saclay, 91128 Palaiseau, France. All rights reserved.         |
%| LICENCE   : This program is free software, distributed in the hope that|
%| it will be useful, but WITHOUT ANY WARRANTY. Natively, you can use,    |
%| redistribute and/or modify it under the terms of the GNU General Public|
%| License, as published by the Free Software Foundation (version 3 or    |
%| later,  http://www.gnu.org/licenses). For private use, dual licencing  |
%| is available, please contact us to activate a "pay for remove" option. |
%| CONTACT   : matthieu.aussal@polytechnique.edu                          |
%| WEBSITE   : www.cmap.polytechnique.fr/~aussal/gypsilab                 |
%|                                                                        |
%| Please acknowledge the gypsilab toolbox in programs or publications in |
%| which you use it.                                                      |
%|________________________________________________________________________|
%|   '&`   |                                                              |
%|    #    |   FILE       : ffmSubdivide.m                                |
%|    #    |   VERSION    : 0.6                                           |
%|   _#_   |   AUTHOR(S)  : Matthieu Aussal                               |
%|  ( # )  |   CREATION   : 14.03.2017                                    |
%|  / 0 \  |   LAST MODIF : 05.09.2019                                    |
%| ( === ) |   SYNOPSIS   : Recursive subdivision using an octree         |
%|  `---'  |                                                              |
%+========================================================================+

% Initialisation des enfants par subdivision type Octree
Nprt    = length(prt.ind);
chd.ctr = zeros(8*Nprt,3);
chd.ind = cell(8*Nprt,1);
chd.nbr = zeros(8*Nprt,1);
Ichd    = zeros(Nprt,8);

% Boucle sur les parents
l = 0;
for i = 1:Nprt
    % Subdivision centrale
    ind  = prt.ind{i};
    cutx = X(ind,1)<=prt.ctr(i,1);
    cuty = X(ind,2)<=prt.ctr(i,2);
    cutz = X(ind,3)<=prt.ctr(i,3);

    % Repartition des indices
    cut = logical([ ...
        cutx  .*  cuty  .*  cutz , ...
        ~cutx  .*  cuty  .*  cutz , ...
        cutx  .* ~cuty  .*  cutz , ...
        ~cutx  .* ~cuty  .*  cutz , ...
        cutx  .*  cuty  .* ~cutz , ...
        ~cutx  .*  cuty  .* ~cutz , ...
        cutx  .* ~cuty  .* ~cutz , ...
        ~cutx  .* ~cuty  .* ~cutz ] );
    Ncut = sum(cut,1);

    % Centres des enfants
    ctr = ones(8,1)*prt.ctr(i,1:3) + 0.25*edg .* [...
        -1 -1 -1 ; 1 -1 -1; -1 1 -1 ; 1 1 -1 ;...
        -1 -1  1 ; 1 -1  1; -1 1  1 ; 1 1  1 ];

    % Ajout d'une boite pour chaque enfant non vide
    for j = find(Ncut)
        chd.ctr(l+1,:) = ctr(j,:);
        chd.ind{l+1}   = ind(cut(:,j));
        chd.nbr(l+1)   = Ncut(j);
        Ichd(i,j)      = l+1;
        l = l + 1;
    end
end

% Extraction des boites vides
chd.ctr = chd.ctr(1:l,:);
chd.ind = chd.ind(1:l);
chd.nbr = chd.nbr(1:l);

% Verification que chaque pot a son couvercle
if abs( sum(chd.nbr) - sum(prt.nbr) ) > 1e-12
    error('ffmSubDivide.m - error 1')
end
if abs( sum(cell2mat(chd.ind)) - sum(cell2mat(prt.ind)) ) > 1e-12
    error('ffmSubDivide.m - error 2')
end

% Representation graphique
if fig
    % Configuration
    figure(fig); clf
    hold on
    title('Box plot')
    grid on ; axis equal

    % Representation des centres
    plot3(chd.ctr(:,1),chd.ctr(:,2),chd.ctr(:,3),'ok','MarkerSize',8)

    % Representation des points par boites
    for i = 1:length(chd.ind)
        plot3(X(chd.ind{i},1),X(chd.ind{i},2),X(chd.ind{i},3),'.','Color',rand(1,3))
    end
end
end


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

%% -*- texinfo -*-
%% @documentencoding UTF-8
%% @defmethod  @@sym symprod (@var{f}, @var{n}, @var{a}, @var{b})
%% @defmethodx @@sym symprod (@var{f}, @var{n}, [@var{a} @var{b}])
%% @defmethodx @@sym symprod (@var{f}, @var{a}, @var{b})
%% @defmethodx @@sym symprod (@var{f}, [@var{a} @var{b}])
%% @defmethodx @@sym symprod (@var{f}, @var{n})
%% @defmethodx @@sym symprod (@var{f})
%% Symbolic product.
%%
%% The product of the expression @var{f} as variable @var{n} changes
%% from @var{a} to @var{b}.  When @var{n} is omitted it is determined
%% using @code{symvar} and defaults to @code{x} if @var{f} is
%% constant. The limits @var{a} and @var{b} default to @code{1} and
%% @var{n} respectively.
%%
%% Examples:
%% @example
%% @group
%% syms n m x
%% symprod(sin(n*x), n, [1 3])
%%   @result{} (sym) sin(x)⋅sin(2⋅x)⋅sin(3⋅x)
%% symprod(n, n, 1, m)
%%   @result{} (sym) m!
%% @end group
%% @end example
%%
%% Unevaluated product:
%% @example
%% @group
%% syms x m
%% symprod(sin(x), x, [1 m])
%%   @result{} (sym)
%%         m
%%       ─┬─┬─
%%        │ │ sin(x)
%%        │ │
%%       x = 1
%% @end group
%% @end example
%%
%% @seealso{@@sym/symsum, @@sym/prod}
%% @end defmethod

function S = symprod(f, n, a, b)

  if (nargin > 4)
    print_usage ();
  end

  idx1.type = '()';
  idx1.subs = {1};
  idx2.type = '()';
  idx2.subs = {2};

  if (nargin == 1)
    n = symvar(f, 1);
    if (isempty(n))
      n = sym('x');
    end
    a = sym(1);
    b = n;
  elseif (nargin == 2) && (length(n) == 2)
    f = sym(f);
    %a = n(1);  % issue #17
    %b = n(2);
    a = subsref(n, idx1);
    b = subsref(n, idx2);
    n = symvar(f, 1);
    if (isempty(n))
      n = sym('x');
    end
  elseif (nargin == 2)
    f = sym(f);
    n = sym(n);
    a = sym(1);
    b = n;
  elseif (nargin == 3) && (length(a) == 2)
    f = sym(f);
    n = sym(n);
    %b = a(2);  % issue #17
    %a = a(1);
    b = subsref(a, idx2);
    a = subsref(a, idx1);
  elseif (nargin == 3)
    f = sym(f);
    b = a;
    a = n;
    n = symvar(f, 1);
    if (isempty(n))
      n = sym('x');
    end
  else
    f = sym(f);
    n = sym(n);
    a = sym(a);
    b = sym(b);
  end

  cmd = { '(f, n, a, b) = _ins'
          'S = sp.product(f, (n, a, b))'
          'return S,' };

  S = pycall_sympy__ (cmd, sym(f), sym(n), sym(a), sym(b));

end

%!error symprod (sym(1), 2, 3, 4, 5)

%!test
%! % simple
%! syms n
%! assert (isequal (symprod(n, n, 1, 10), factorial(sym(10))))
%! assert (isequal (symprod(n, n, sym(1), sym(10)), factorial(10)))

%!test
%! % one input
%! syms n
%! f = symprod (n);
%! g = factorial (n);
%! assert (isequal (f, g))
%! f = symprod (2*n);
%! g = 2^n * factorial (n);
%! assert (isequal (f, g))

%!test
%! % constant input
%! f = symprod (sym(2));
%! syms x
%! g = 2^x;
%! assert (isequal (f, g))

%!test
%! % two inputs
%! syms n
%! f = symprod (2*n, n);
%! g = 2^n * factorial (n);
%! assert (isequal (f, g))

%!test
%! % two inputs, second is range
%! syms n
%! f = symprod (n, [1 6]);
%! g = 720;
%! assert (isequal (f, g))
%! f = symprod (n, [sym(1) 6]);
%! g = 720;
%! assert (isequal (f, g))
%! f = symprod (2*n, [1 6]);
%! g = sym(2)^6*720;
%! assert (isequal (f, g))

%!test
%! % three inputs, last is range
%! syms n
%! f = symprod (2*n, n, [1 4]);
%! g = sym(384);
%! assert (isequal (f, g))
%! f = symprod (2*n, n, [sym(1) 4]);
%! g = sym(384);
%! assert (isequal (f, g))
%! f = symprod (2, n, [sym(1) 4]);
%! g = sym(16);
%! assert (isequal (f, g))

%!test
%! % three inputs, no range
%! syms n
%! f = symprod (2*n, 1, 4);
%! g = sym(384);
%! assert (isequal (f, g))
%! f = symprod (5, sym(1), 3);
%! g = sym(125);
%! assert (isequal (f, g))

%!test
%! % infinite product
%! syms a n oo
%! zoo = sym('zoo');
%! assert (isequal (symprod(a, n, 1, oo), a^oo))
%! assert (isequal (symprod(a, n, 1, inf), a^oo))

%%!test
%%! % FIXME: commented out test...
%%! % SymPy 0.7.6: nan
%%! % SymPy git: interesting that 1**oo is nan but this is still 1
%%! assert (isequal (symprod(1, n, 1, oo), sym(1)))


function z = sandwich3x3(x, y)

% SANDWICH3X3 compute x*y*x' provided y is Hermitian and dimensionality is 3x3xN

% Copyright (C) 2017, Donders Centre for Cognitive Neuroimaging, Nijmegen, NL
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip 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.
%
%    FieldTrip 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 FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

% FIXME build in check for hermitianity
z     = complex(zeros(size(x)));
xconj = conj(x);
xabs2 = abs(x).^2;

z(1,1,:,:) = xabs2(1,1,:,:).*y(1,1,:,:)  + ...
             xabs2(1,2,:,:).*y(2,2,:,:)  + ...
             xabs2(1,3,:,:).*y(3,3,:,:)  + ...
             2.*real( x(1,2,:,:).*y(2,1,:,:).*xconj(1,1,:,:) ) + ...
             2.*real( x(1,3,:,:).*y(3,1,:,:).*xconj(1,1,:,:) ) + ...
             2.*real( x(1,3,:,:).*y(3,2,:,:).*xconj(1,2,:,:) );

             %(x(1,2,:,:).*y(2,1,:,:) + x(1,3,:,:).*y(3,1,:,:)).*xconj(1,1,:,:) + ...
             %(x(1,1,:,:).*y(1,2,:,:) + x(1,3,:,:).*y(3,2,:,:)).*xconj(1,2,:,:) + ...
             %(x(1,1,:,:).*y(1,3,:,:) + x(1,2,:,:).*y(2,3,:,:)).*xconj(1,3,:,:);

z(2,1,:,:) = (x(2,1,:,:).*y(1,1,:,:) + x(2,2,:,:).*y(2,1,:,:) + x(2,3,:,:).*y(3,1,:,:)).*xconj(1,1,:,:) + ...
             (x(2,1,:,:).*y(1,2,:,:) + x(2,2,:,:).*y(2,2,:,:) + x(2,3,:,:).*y(3,2,:,:)).*xconj(1,2,:,:) + ...
             (x(2,1,:,:).*y(1,3,:,:) + x(2,2,:,:).*y(2,3,:,:) + x(2,3,:,:).*y(3,3,:,:)).*xconj(1,3,:,:);

z(3,1,:,:) = (x(3,1,:,:).*y(1,1,:,:) + x(3,2,:,:).*y(2,1,:,:) + x(3,3,:,:).*y(3,1,:,:)).*xconj(1,1,:,:) + ...
             (x(3,1,:,:).*y(1,2,:,:) + x(3,2,:,:).*y(2,2,:,:) + x(3,3,:,:).*y(3,2,:,:)).*xconj(1,2,:,:) + ...
             (x(3,1,:,:).*y(1,3,:,:) + x(3,2,:,:).*y(2,3,:,:) + x(3,3,:,:).*y(3,3,:,:)).*xconj(1,3,:,:);

z(1,2,:,:) = conj(z(2,1,:,:));

z(2,2,:,:) = xabs2(2,1,:,:).*y(1,1,:,:)  + ...
             xabs2(2,2,:,:).*y(2,2,:,:)  + ...
             xabs2(2,3,:,:).*y(3,3,:,:)  + ...
             2.*real( x(2,2,:,:).*y(2,1,:,:).*xconj(2,1,:,:) ) + ...
             2.*real( x(2,3,:,:).*y(3,1,:,:).*xconj(2,1,:,:) ) + ...
             2.*real( x(2,3,:,:).*y(3,2,:,:).*xconj(2,2,:,:) );

             %(x(2,2,:,:).*y(2,1,:,:) + x(2,3,:,:).*y(3,1,:,:)).*xconj(2,1,:,:) + ...
             %(x(2,1,:,:).*y(1,2,:,:) + x(2,3,:,:).*y(3,2,:,:)).*xconj(2,2,:,:) + ...
             %(x(2,1,:,:).*y(1,3,:,:) + x(2,2,:,:).*y(2,3,:,:)).*xconj(2,3,:,:);

z(3,2,:,:) = (x(3,1,:,:).*y(1,1,:,:) + x(3,2,:,:).*y(2,1,:,:) + x(3,3,:,:).*y(3,1,:,:)).*xconj(2,1,:,:) + ...
             (x(3,1,:,:).*y(1,2,:,:) + x(3,2,:,:).*y(2,2,:,:) + x(3,3,:,:).*y(3,2,:,:)).*xconj(2,2,:,:) + ...
             (x(3,1,:,:).*y(1,3,:,:) + x(3,2,:,:).*y(2,3,:,:) + x(3,3,:,:).*y(3,3,:,:)).*xconj(2,3,:,:);

z(1,3,:,:) = conj(z(3,1,:,:));

z(2,3,:,:) = conj(z(3,2,:,:));

z(3,3,:,:) = xabs2(3,1,:,:).*y(1,1,:,:)  + ...
             xabs2(3,2,:,:).*y(2,2,:,:)  + ...
             xabs2(3,3,:,:).*y(3,3,:,:)  + ...
             2.*real( x(3,2,:,:).*y(2,1,:,:).*xconj(3,1,:,:) ) + ...
             2.*real( x(3,3,:,:).*y(3,1,:,:).*xconj(3,1,:,:) ) + ...
             2.*real( x(3,3,:,:).*y(3,2,:,:).*xconj(3,2,:,:) );

             %(x(3,2,:,:).*y(2,1,:,:) + x(3,3,:,:).*y(3,1,:,:)).*xconj(3,1,:,:) + ...
             %(x(3,1,:,:).*y(1,2,:,:) + x(3,3,:,:).*y(3,2,:,:)).*xconj(3,2,:,:) + ...
             %(x(3,1,:,:).*y(1,3,:,:) + x(3,2,:,:).*y(2,3,:,:)).*xconj(3,3,:,:);
%
%b1 b2 b7    a1 a2' a4'   b1' b3' b5'
%b3 b4 b8    a2 a3  a5'   b2' b4' b6'
%b5 b6 b9    a4 a5  a6    b7' b8' b9'
%
%b1*a1+b2*a2+b7*a4  b1*a2'+b2*a3+b7*a5  b1*a4'+b2*a5'+b7*a6   b1' b3' b5'
%b3*a1+b4*a2+b8*a4  b3*a2'+b4*a3+b8*a5  b3*a4'+b4*a5'+b8*a6   b2' b4' b6'
%b5*a1+b6*a2+b9*a4  b5*a2'+b6*a3+b9*a5  b5*a4'+b6*a5'+b9*a6   b7' b8' b9'
%
%

%b1*a1*b1'+b2*a2*b1'+b1*a2'*b2'+b2*a3*b2' b1*a1*b3'+b2*a2*b3'+b1*a2'*b4'+b2*a3*b4'
%b3*a1*b1'+b4*a2*b1'+b3*a2'*b2'+b4*a3*b2' b3*a1*b3'+b4*a2*b3'+b3*a2'*b4'+b4*a3*b4'
%
%a1*abs(b1)^2 + a2*(b1'*b2) + a2'*(b1*b2') + a3*abs(b2)^2    a1*b1*b3'    + a2*b2*b3'   + a2'*b1*b4'   + a3*b2*b4'
%a1*b1'*b3    + a2*b1'*b4   + a2'*b2'*b3   + a3*b2'*b4       a1*abs(b3)^2 + a2*(b3'*b4) + a2'*(b3*b4') + a3*abs(b4)^2


% STD_ERSP - Compute ERSP and/or ITC transforms for ICA components
%              or data channels of a dataset. Save results into Matlab
%              float files.
%
% Function description:
%              The function computes the mean ERSP or ITC for the selected
%              dataset ICA components or data channels in the requested
%              frequency range and time window (the two are dependent).
%              Frequencies are equally log spaced. Options specify component
%              numbers, desired frequency range,  time window length,
%              frequency resolution, significance level, and wavelet
%              cycles. See >> help newtimef and >> timef details
%
%              Two Matlab files are saved (for ERSP and ITC). These contain
%              the ERSP|ITC image, plus the transform parameters
%              used to compute them. Saves the computed dataset mean images
%              in dataset-name files with extensions '.icaersp' and '.icaitc'
%              for ICA components or '.datersp', '.datitc' for data channels.
% Usage:
%              >> [X times logfreqs ] = std_ersp(EEG, 'key', 'val', ...);
% Inputs:
%   EEG          - a loaded epoched EEG dataset structure. May be an array
%                  of such structure containing several datasets.
%
% Other inputs:
%   'trialindices' - [cell array] indices of trials for each dataset.
%                  Default is EMPTY (no trials). NEEDS TO BE SET.
%   'components' - [numeric vector] components of the EEG structure for which
%                  activation spectrum will be computed. Note that because
%                  computation of ERP is so fast, all components spectrum are
%                  computed and saved. Only selected component
%                  are returned by the function to Matlab
%                  {default|[] -> all}
%   'channels'   - [cell array] channels of the EEG structure for which
%                  activation spectrum will be computed. Note that because
%                  computation of ERP is so fast, all channels spectrum are
%                  computed and saved. Only selected channels
%                  are returned by the function to Matlab
%                  {default|[] -> none}
%   'recompute'  - ['on'|'off'] force recomputing data file even if it is
%                  already on disk.
%   'rmcomps'    - [integer array] remove artifactual components (this entry
%                  is ignored when plotting components). This entry contains
%                  the indices of the components to be removed. Default is none.
%   'interp'     - [struct] channel location structure containing electrode
%                  to interpolate ((this entry is ignored when plotting
%                  components). Default is no interpolation.
%   'fileout'    - [string] name of the file to save on disk. The default
%                  is the same name (with a different extension) as the
%                  dataset given as input.
%  'savetrials'  - ['on'|'off'] save single-trials ERSP. Requires a lot of disk
%                  space (dataset space on disk times 10) but allow for refined
%                  single-trial statistics. This option is obsolete as
%                  trials are now always saved.
%  'savefile'    - ['on'|'off'] save file or simply return measures.
%                  Default is to save files ('on').
%  'getparams'   - ['on'|'off'] return optional parameters for the newtimef
%                  function (and do not compute anything). This argument is
%                  obsolete (default is 'off').
%
% ERSP optional inputs:
%   'type'       - ['ersp'|'itc'|'ersp&itc'] save ERSP, ITC, or both data
%                  types to disk {default: 'ersp'}
%   'freqs'      - [minHz maxHz] the ERSP/ITC frequency range to compute
%                  and return. {default: 3 to EEG sampling rate divided by 3}
%   'timelimits' - [minms maxms] time window (in ms) to compute.
%                  {default: whole input epoch}.
%   'cycles'     - [wavecycles (factor)]. If 0 -> DFT (constant window length
%                  across frequencies).
%                  If >0 -> the number of cycles in each analysis wavelet.
%                  If [wavecycles factor], wavelet cycles increase with
%                  frequency, beginning at wavecyles. (0 < factor < 1)
%                  factor = 0 -> fixed epoch length (DFT, as in FFT).
%                  factor = 1 -> no increase (standard wavelets)
%                  {default: [0]}
%   'padratio'   - (power of 2). Multiply the number of output frequencies
%                  by dividing their frequency spacing through 0-padding.
%                  Output frequency spacing is (low_freq/padratio).
%   'alpha'      - If in (0, 1), compute two-tailed permutation-based
%                  probability thresholds and use these to mask the output
%                  ERSP/ITC images {default: NaN}
%   'powbase'    - Deprecated. Note that baseline can be readjusted after
%                  computation as single trial spectral decompositions are stored.
%
% Other optional inputs:
%   This function will take any of the NEWTIMEF optional inputs (for instance
%   to compute log-space frequencies)...
%
% Outputs:
%   X         - the masked log ERSP/ITC of the requested ICA components/channels
%               in the selected frequency and time range. Note that for
%               optimization reasons, this parameter is now empty or 0. X
%               thus must be read from the datafile saved on disk.
%   times     - vector of time points for which the ERSPs/ITCs were computed.
%   logfreqs  - vector of (equally log spaced) frequencies (in Hz) at which the
%               log ERSP/ITC was evaluated.
%   parameters - parameters given as input to the newtimef function.
%
% Files written or modified:
%              [dataset_filename].icaersp   <-- saved component ERSPs
%              [dataset_filename].icaitc    <-- saved component ITCs
%              [dataset_filename].icatimef  <-- saved component single
%                                               trial decompositions.
%  OR for channels
%              [dataset_filename].datersp   <-- saved channel ERSPs
%              [dataset_filename].datitc    <-- saved channel ITCs
%              [dataset_filename].dattimef  <-- saved channel single
%                                               trial decompositions.
% Example:
%            % Create mean ERSP and ITC images on disk for all comps from
%            % dataset EEG use three-cycle wavelets (at 3 Hz) to more than
%            % three-cycle wavelets at 50 Hz. See >> help newtimef
%            % Return the (equally log-freq spaced, probability-masked) ERSP.
%            >> [Xersp, times, logfreqs] = std_ersp(EEG, ...
%                       'type', 'ersp', 'freqs', [3 50], 'cycles', [3 0.5]);
%
% See also: TIMEF, STD_ITC, STD_ERP, STD_SPEC, STD_TOPO, STD_PRECLUST
%
% Authors: Arnaud Delorme, Hilit Serby, SCCN, INC, UCSD, January, 2005-

% Copyright (C) Arnaud Delorme, SCCN, INC, UCSD, October 11, 2004, arno@sccn.ucsd.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function [X, times, logfreqs, parameters] = std_ersp(EEG, varargin)

if nargin < 1
    help std_ersp;
    return;
end

X = [];
options = {};
if length(varargin) > 1
    if ~ischar(varargin{1})
        if length(varargin) > 0, options = { options{:} 'components' varargin{1} }; end
        if length(varargin) > 1, options = { options{:} 'freqs'      varargin{2} }; end
        if length(varargin) > 2, options = { options{:} 'timewindow' varargin{3} }; end
        if length(varargin) > 3, options = { options{:} 'cycles'     varargin{4} }; end
        if length(varargin) > 4, options = { options{:} 'padratio'   varargin{5} }; end
        if length(varargin) > 5, options = { options{:} 'alpha'      varargin{6} }; end
        if length(varargin) > 6, options = { options{:} 'type'       varargin{7} }; end
        if length(varargin) > 7, options = { options{:} 'powbase'    varargin{8} }; end
    else
        options = varargin;
    end
end

[g, timefargs] = finputcheck(options, { ...
                        'components'    'integer'               []          [];
                        'channels'      { 'cell','integer' }    { [] [] }   {};
                        'powbase'       'real'                  []          [];
                        'trialindices' { 'integer','cell' }     []          [];
                        'savetrials'    'string'      { 'on','off' }        'off';
                        'plot'          'string'      { 'on','off' }        'off'; % not documented for debugging purpose
                        'recompute'     'string'      { 'on','off' }        'off';
                        'getparams'     'string'      { 'on','off' }        'off';
                        'savefile'      'string'      { 'on','off' }        'on';
                        'parallel'      'string'      { 'on','off' }        'off';
                        'timewindow'    'real'                  []          [];    % ignored, deprecated
                        'fileout'       'string'                []          '';
                        'timelimits'    'real'                  []          [EEG(1).xmin EEG(1).xmax]*1000;
                        'cycles'        'real'                  []          [3 .5];
                        'padratio'      'real'                  []          1;
                        'trialinfo'     'struct'                []          struct([]);
                        'freqs'         'real'                  []          [0 EEG(1).srate/2];
                        'rmcomps'       'cell'                  []          cell(1,length(EEG));
                        'interp'        'struct'                { }         struct([]);
                        'freqscale'     'string'                []         'log';
                        'alpha'         'real'                  []          NaN;
                        'baseline'      'real'                  []          0;
                        'type'          'string'      { 'ersp','itc','both','ersp&itc' }  'both'}, 'std_ersp', 'ignore');
if ischar(g), error(g); end
if isempty(g.trialindices), g.trialindices = cell(length(EEG)); end
if ~iscell(g.trialindices), g.trialindices = { g.trialindices }; end
if ~isempty(g.powbase), disp('''powbase'' parameter is no longer supported at computation time'); end

% checking input parameters
% -------------------------
if isempty(g.components) && isempty(g.channels)
    if isempty(EEG(1).icaweights)
        error('EEG.icaweights not found');
    end
    g.components = 1:size(EEG(1).icaweights,1);
    disp('Computing ERSP with default values for all components of the dataset');
end

% select ICA components or data channels
% --------------------------------------
if isempty(g.fileout), g.fileout = fullfile(EEG(1).filepath, EEG(1).filename(1:end-4)); end
if ~isempty(g.components)
    g.indices = g.components;
    prefix = 'comp';
    filenameersp   = [ g.fileout '.icaersp'  ];
    filenameitc    = [ g.fileout '.icaitc'   ];
    filenametrials = [ g.fileout '.icatimef' ];
    if ~isempty(g.channels)
        error('Cannot compute ERSP/ITC for components and channels at the same time');
    end
elseif ~isempty(g.channels)
    if iscell(g.channels)
        if ~isempty(g.interp)
            g.indices = eeg_chaninds(g.interp, g.channels, 0);
        else
            g.indices = eeg_chaninds(EEG(1), g.channels, 0);
            for ind = 2:length(EEG)
                if ~isequal(eeg_chaninds(EEG(ind), g.channels, 0), g.indices)
                    error([ 'Channel information must be consistent when ' 10 'several datasets are merged for a specific design' ]);
                end
            end
        end
    else
        g.indices = g.channels;
    end
    prefix = 'chan';
    filenameersp   = [ g.fileout '.datersp'  ];
    filenameitc    = [ g.fileout '.datitc'   ];
    filenametrials = [ g.fileout '.dattimef' ];
end

% Check if ERSP/ITC information found in datasets and if fits requested parameters
% ----------------------------------------------------------------------------
if exist( filenametrials ) && strcmpi(g.recompute, 'off')
    fprintf('Use existing file for ERSP: %s; check the ''recompute checkbox'' to force recomputing.\n', filenameersp);
    return;
end

% Compute ERSP parameters
% -----------------------
parameters = { 'cycles', g.cycles, 'padratio', g.padratio, ...
               'alpha', g.alpha, 'freqscale', g.freqscale, timefargs{:} };
defaultlowfreq = 3;
[time_range] = compute_ersp_times(g.cycles,  EEG(1).srate, ...
                                 [EEG(1).xmin EEG(1).xmax]*1000 , defaultlowfreq, g.padratio);
if time_range(1) < time_range(2) && g.freqs(1) == 0
     g.freqs(1) = defaultlowfreq; % for backward compatibility
end
parameters = { parameters{:} 'freqs' g.freqs };
if strcmpi(g.plot, 'off')
    parameters = { parameters{:} 'plotersp', 'off', 'plotitc', 'off', 'plotphase', 'off' };
end
parameters{end+1} = 'baseline';
parameters{end+1} = g.baseline;

% return parameters
% -----------------
if strcmpi(g.getparams, 'on')
    X = []; times = []; logfreqs = [];
    if strcmpi(g.savetrials, 'on')
        parameters = { parameters{:} 'savetrials', g.savetrials };
    end
    return;
end

options = {};
if ~isempty(g.rmcomps), options = { options{:} 'rmcomps' g.rmcomps }; end
if ~isempty(g.interp),  options = { options{:} 'interp' g.interp }; end
if isempty(g.channels)
     X = eeg_getdatact(EEG, 'component', g.indices, 'trialindices', g.trialindices );
else X = eeg_getdatact(EEG, 'channel'  , g.indices, 'trialindices', g.trialindices, 'rmcomps', g.rmcomps, 'interp', g.interp);
end
if size(X, 3) == 1
    error('The data is continuous for one of the dataset. ERSP can only be computed when data trials are present');
end

% frame range
% -----------
pointrange1 = round(max((g.timelimits(1)/1000-EEG(1).xmin)*EEG(1).srate, 1));
pointrange2 = round(min(((g.timelimits(2)+1000/EEG(1).srate)/1000-EEG(1).xmin)*EEG(1).srate, EEG(1).pnts));
pointrange = [pointrange1:pointrange2];

% Compute ERSP && ITC
% ------------------
allTrialsTmp   = cell(1,length(g.indices));
allTrialsTime  = cell(1,length(g.indices));
allTrialsFreqs = cell(1,length(g.indices));
eeglab_options;
usesingle = option_single;

disp('Computing time/frequency decomposition...');
parfor k = 1:length(g.indices)
    tmpparams = parameters;
    if length(g.indices) > 1
        tmpparams{end+1} = 'verbose';
        tmpparams{end+1} = 'off';
    end

    % Run timef() to get ERSP
    % ------------------------
    timefdata  = reshape(X(k,pointrange,:), 1, length(pointrange)*size(X,3));
    mytimes = [];
    mylogfreqs = [];
    alltfX   = [];
    if ~isempty(timefdata)
        [logersp,logitc,logbase,mytimes,mylogfreqs,logeboot,logiboot,alltfX] ...
              = newtimef( timefdata, length(pointrange), g.timelimits, EEG(1).srate, tmpparams{2:end});
        %figure; newtimef( TMP.data(32,:), EEG.pnts, [EEG.xmin EEG.xmax]*1000, EEG.srate, cycles, 'freqs', freqs);
        %figure; newtimef( timefdata, length(pointrange), g.timelimits, EEG.srate, cycles, 'freqs', freqs);
    end
    %if strcmpi(g.plot, 'on'), return; end
    if usesingle
        alltfX = single(alltfX);
    end

    allTrialsTmp{k}   = single( alltfX );
    allTrialsTime{k}  = mytimes;
    allTrialsFreqs{k} = mylogfreqs;
end
all_trials = [];
for k = 1:length(g.indices)  % for each (specified) component/channel
    all_trials = setfield( all_trials, [ prefix int2str(g.indices(k)) ], allTrialsTmp{k});
end
X = allTrialsTmp{1};

% Save ERSP into file
% -------------------
logfreqs             = allTrialsFreqs{1};
times                = allTrialsTime{1};
all_trials.freqs     = allTrialsFreqs{1};
all_trials.times     = allTrialsTime{1};
all_trials.parameters = { options{:} parameters{:} };
all_trials.datatype   = 'TIMEF';
all_trials.datafiles  = computeFullFileName( { EEG.filepath }, { EEG.filename });
all_trials.datatrials = g.trialindices;

all_trials.parameters = parameters;
if ~isempty(g.channels)
    if ~isempty(g.interp)
        all_trials.labels = { g.interp(g.indices).labels };
    elseif ~isempty(EEG(1).chanlocs)
        tmpchanlocs = EEG(1).chanlocs;
        all_trials.labels = { tmpchanlocs(g.indices).labels };
    end
end
all_trials.trialinfo = g.trialinfo;

if strcmpi(g.savefile, 'on')
    std_savedat( filenametrials , all_trials );
end

% compute full file names
% -----------------------
function res = computeFullFileName(filePaths, fileNames);
for index = 1:length(fileNames)
    res{index} = fullfile(filePaths{index}, fileNames{index});
end


function [ y2, m2, d2, f2 ] = yjf_to_ymdf_english ( y1, j1, f1 )

%*****************************************************************************80
%
%% YJF_TO_YMDF_ENGLISH converts an English date from YJF to YMDF format.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    06 March 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer Y1, J1, real F1, the YJF date.
%
%    Output, integer Y2, M2, D2, real F2,
%    the YMDF date.
%

%
%  Copy the input.
%
  y2 = y1;
  j2 = j1;
  f2 = f1;
%
%  Check the input.
%
  [ y2, j2, ierror ] = yj_check_english ( y2, j2 );

  if ( ierror ~= 0 )
    y2 = 0;
    m2 = 0;
    d2 = 0;
    f2 = 0.0;
    return
  end
%
%  Convert the input.
%
  m2 = 1;
  d2 = j2;

  [ y2, m2, d2 ] = day_borrow_english ( y2, m2, d2 );

  [ y2, m2, d2 ] = day_carry_english ( y2, m2, d2 );

  return
end


function [bcx,bcy] = specific_flow(xbd,ybd)
%poiseuille_flow   Reference problem 5.1 inflow condition
%   [bcx,bcy] = specific_flow(xbd,ybd);
%   input
%          xbd          x coordinate vector
%          ybd          y coordinate vector
%
%   specifies Poiseuille flow boundary condition
%   IFISS function: DJS; 6 March 2005.
% Copyright (c) 2005 D.J. Silvester, H.C. Elman, A. Ramage
bcx=1-ybd.*ybd; bcy=0*xbd;
return


function Mn=dataNorm(M,normOpt)

switch normOpt
    case 1 %Using max and min
        Mn=double(M);
        Mn=Mn-min(Mn(:));
        Mn=Mn./max(Mn(:));
    case 2 %Using max only and letting M(M<0)= 0
        Mn=double(M);
        Mn(Mn<0)=0;
        Mn=Mn./max(Mn(:));
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 dataCorners2 = atlasMergeAdjacentCorners(dataCorners,dataCorners2);
%
%   dataCorners2 = atlasMergeAdjacentCorners(dataCorners,dataCorners2);
%
% Author:  Wandell
% Purpose:
%     When adding an atlas segment, sometimes we want the corners from
%     adjacent segments to be the same.  This routine finds the two closest
%     corners and makes the corner positions in the second segment equal to
%     the closest ones in the first segment
%
%Examples
%

% First, we check the distance from each corner in corners2 to each corner
% in corners.  This is a 4x4 distance matrix.
%
for ii=1:4
    for jj=1:4
        d(ii,jj) = norm(dataCorners(ii,:) - dataCorners2(jj,:));
    end
end

% Find the two points with the closest values
[v,idx] = sort(d(:));

% Find the row and column coordinates of these two points
[r1,c1] = ind2sub(size(d),idx(1));

% Set the dataCorners2(c,:) equal to the positions of dataCorners(r,:)
dataCorners2(c1,:) = dataCorners(r1,:);

% Choose the second point that is closest with the constraint that this
% second point in dataCorners2 cannot be attached to the point we have
% already chosen.  Another way to do this is to remove the row containing
% point at r1, recalculale the distance matrix, and then find the minimum.
for ii=2:length(idx)
    [r2,c2] = ind2sub(size(d),idx(ii));
    if r1 ~= r2
        dataCorners2(c2,:) = dataCorners(r2,:);
        break;
    end
end

return;


function E = feval(disc, location, direction)
%FEVAL   Evaluation functional for CHEBCOLLOC.
%   FEVAL(DISC, LOC, DIRN) returns a functional that evaluates the Chebyshev
%   polynomial represented by a COLLOC discretization at the given point LOC as
%   approached from the direction DIRN (either +1 or -1).

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

n = disc.dimension;

% Find the collocation points and create an empty functional.
[x, ignored, v] = functionPoints(disc);
offset = cumsum([0 ; n(:)]);
N = offset(end);
E = zeros(1, N);

% Only one subinterval creates nonzero entries in E.
intnum = disc.whichInterval(location, direction);
active = offset(intnum) + (1:n(intnum));
E(1, active) = barymat(location, x(active), v(active));

end


% clear all;
% close all;
% %%%pavia University
% input_files.data_file='./data/PaviaU.mat';
% input_files.gt_file='./data/PaviaU_gt.mat';
% output_file_name='./results/Pavia_U_pca.mat';
% pca_dim=10;
% prepare_data_gt(input_files, output_file_name, pca_dim);

addpath('./pca_ica/');

clear all;
close all;
%%%pavia University
input_files.data_file='./data/Indian_pines_corrected.mat';
input_files.gt_file='./data/indian_pines_gt.mat';
output_file_name='./results/Indian_pines_pca.mat';
pca_dim=30;
prepare_data_gt(input_files, output_file_name, pca_dim);

% clear all;
% close all;
%
% input_files.data_file='./data/Salinas_corrected.mat';
% input_files.gt_file='./data/Salinas_gt.mat';
% output_file_name='./results/Salinas_pca.mat';
% pca_dim=10;
% prepare_data_gt(input_files, output_file_name, pca_dim);


function [xPred, SPred, xPropCenPoints]=sqrtDiscCubKalPred(xPrev,SPrev,f,SQ,xi,w,stateDiffTrans,stateAvgFun,stateTrans)
%%SQRTDISCCUBKALPRED Perform the discrete-time prediction step that comes
%                    with the square root implementation of the cubature
%                    Kalman filter with additive process noise.
%
%INPUTS: xPrev The xDim X 1 state estimate at the previous time-step.
%        SPrev The xDim X xDim lower-triangular square root of the state
%              covariance matrix at the previous time-step.
%            f A function handle for the state transition function that
%              takes the state as its parameter.
%           SQ The xDimXxDim lower-triangular square root of the process
%              noise covariance matrix.
%           xi An xDimXnumCubPoints matrix of cubature points. If this and
%              the next parameter are omitted or empty matrices are passed,
%              then fifthOrderCubPoints(xDim+cDim) is used. It is suggested
%              that xi and w be provided to avoid needless recomputation of
%              the cubature points.
%            w A numCubPointsX1 vector of the weights associated with the
%              cubature points. These must be all positive.
% stateDiffTrans An optional function handle that takes an xDimXN matrix of
%              N differences between states estimates and transforms them
%              however might be necessary. For example, a state continaing
%              angular components will generally need differences between
%              angular components wrapped to the range +/-pi.
%  stateAvgFun An optional function that given an xDimXN matrix of N state
%              estimates and an NX1 vector of weights, provides the
%              weighted average of the state estimates. This is necessary
%              if, for example, states with angular components are
%              averaged.
%   stateTrans An optional function that takes a state estimate and
%              transforms it. This is useful if one wishes the elements of
%              the state to be bound to a certain domain. For example, if
%              an element of the state is an angle, one should generally
%              want to bind it to the region +/-pi. This is not applied to
%              the output of f.
%
%OUTPUTS: xPred The xDim X 1 predicted state estimate.
%         SPred The xDim X xDim lower-triangular square root of the
%               predicted state covariance estimate.
% xPropCenPoints The centered propagated cubature state points. This matrix
%               is needed if the backwards smoothing step is being applied.
%
%The mathematics behind the function sqrtDiscCubKalPred are described in
%more detail in Section IX of [1] and in [2]. The use of stateDiffTrans,
%stateAvgFun, and stateTrans arises when dealing with state space models
%involving, for example, angles. This is analogous to similar issues that
%arise when dealing with angular measurements as described in [3].
%
%REFERENCES:
%[1] David F. Crouse , "Basic tracking using nonlinear 3D monostatic and
%    bistatic measurements," IEEE Aerospace and Electronic Systems Magazine,
%    vol. 29, no. 8, Part II, pp. 4-53, Aug. 2014.
%[2] I. Arasaratnam and S. Haykin, "Cubature Kalman filters," IEEE
%    Transactions on Automatic Control, vol. 54, no. 6, pp. 1254-1269,
%    Jun. 2009.
%[3] D. F. Crouse, "Cubature/ unscented/ sigma point Kalman filtering with
%    angular measurement models," in Proceedings of the 18th International
%    Conference on Information Fusion, Washington, D.C., 6-9 Jul. 2015.
%
%October 2013 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

    xDim=length(xPrev);

    if(nargin<5||isempty(xi))
        [xi,w]=fifthOrderCubPoints(xDim);
    end

    if(nargin<7||isempty(stateDiffTrans))
        stateDiffTrans=@(x)x;
    end

    if(nargin<8||isempty(stateAvgFun))
        stateAvgFun=@(x,w)calcMixtureMoments(x,w);
    end

    if(nargin<9||isempty(stateTrans))
        stateTrans=@(x)x;
    end

    xDim=length(xPrev);
    numCubPoints=length(w);

    xPropPoints=zeros(xDim,numCubPoints);%Allocate space

    %Calculate the cubature state points
    xPoints=stateTrans(transformCubPoints(xi,xPrev,SPrev));

    %Propagate the cubature state points
    for curP=1:numCubPoints
        xPropPoints(:,curP)=f(xPoints(:,curP));
    end

    %Calculate the predicted state
    xPred=stateAvgFun(xPropPoints,w);

    %Centered, propagated cubature state points
    xDiff=stateDiffTrans(bsxfun(@minus,xPropPoints,xPred));
    xPropCenPoints=bsxfun(@times,xDiff,sqrt(w'));

    %The root prediction covariance.
    SPred=tria([xPropCenPoints, SQ]);
end

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


%IBLOBS	Blob features
%
% F = IBLOBS(IM, OPTIONS) is a vector of RegionFeature objects that
% describe each connected region in the image IM.
%
% Options::
%  'aspect',A        set pixel aspect ratio, default 1.0
%  'connect',C	     set connectivity, 4 (default) or 8
%  'greyscale'	     compute greyscale moments 0 (default) or 1
%  'boundary'        compute boundary (default off)
%  'area',[A1,A2]    accept only blobs with area in the interval A1 to A2
%  'shape',[S1,S2]   accept only blobs with shape in the interval S1 to S2
%  'touch',T         accept only blobs that touch (1) or do not touch (0)
%                    the edge (default accept all)
%  'class',C         accept only blobs of pixel value C (default all)
%
% The RegionFeature object has many properties including:
%
%  uc            centroid, horizontal coordinate
%  vc            centroid, vertical coordinate
%  p             centroid (uc, vc)
%  umin          bounding box, minimum horizontal coordinate
%  umax          bounding box, maximum horizontal coordinate
%  vmin          bounding box, minimum vertical coordinate
%  vmax          bounding box, maximum vertical coordinate
%  area          the number of pixels
%  class         the value of the pixels forming this region
%  label         the label assigned to this region
%  children      a list of indices of features that are children of this feature
%  edgepoint     coordinate of a point on the perimeter
%  edge          a list of edge points 2xN matrix
%  perimeter     edge length (pixels)
%  touch         true if region touches edge of the image
%  a             major axis length of equivalent ellipse
%  b             minor axis length of equivalent ellipse
%  theta         angle of major ellipse axis to horizontal axis
%  shape         aspect ratio b/a (always <= 1.0)
%  circularity   1 for a circle, less for other shapes
%  moments       a structure containing moments of order 0 to 2
%
% References::
%  - Robotics, Vision & Control, Section 13.1,
%    P. Corke, Springer 2011.
% - METHODS TO ESTIMATE AREAS AND PERIMETERS OF BLOB-LIKE OBJECTS: A COMPARISON
%   Luren Yang, Fritz Albregtsen, Tor Lgnnestad and Per Grgttum
%   IAPR Workshop on Machine Vision Applications Dec. 13-15, 1994, Kawasaki
% - Area and perimeter measurement of blobs in discrete binary pictures.
%   Z.Kulpa.
%   Comput. Graph. Image Process., 6:434-451, 1977.
%
% Notes::
% - The RegionFeature objects are ordered by the raster order of the top most
%   point (smallest v coordinate) in each blob.
% - Circularity is computed using the raw perimeter length scaled down by Kulpa's
%   correction factor.
%
% See also RegionFeature, ILABEL, IDISPLABEL, IMOMENTS.

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

function [features,labimg] = iblobs(im, varargin)

	[nr,nc] = size(im);

    opt.area = [0 Inf];
    opt.shape = [0 Inf];
    opt.class = NaN;
    opt.touch = NaN;
    opt.aspect = 1;
    opt.connect = 4;
    opt.greyscale = false;
    opt.moments = false;
    opt.boundary = false;

    opt = tb_optparse(opt, varargin);

    % HACK ilabel should take int image
	%[li,nl,parent,color,edge] = ilabel(im, opt.connect);

    [b,li,nb,a] = bwboundaries(im);
    nl = max(li(:));

	blob = 0;
	for i=0:nl
		binimage = (li == i);

		% determine the blob extent
		[y,x] = find(binimage);
		umin = min(x); umax = max(x);
		vmin = min(y); vmax = max(y);

        % it touches the edge if its parent is 0
		%t = (parent(i) == 0);
        try
        t = (umin == 1) || (vmin == 1) || (umax == nc) || (vmax == nr);
        catch
            t = false;
            if i==0
                continue
            end
        end

        % compute the moments
		if opt.greyscale
			F = imoments(binimage .* im, 'aspect', opt.aspect);
		else
			F = imoments(binimage, 'aspect', opt.aspect);
		end

        % compute shape property, accounting for degenerate case
		if F.a == 0,
			shape = NaN;
		else
			shape = F.b / F.a;
        end

        color = (i <= nb) && (i > 0);

		% apply various filters
		if 	((t == opt.touch) || isnan(opt.touch)) && ...
            ((color == opt.class) || isnan(opt.class)) && ...
			(F.area_ >= opt.area(1)) && ...
			(F.area_ <= opt.area(2)) && ...
			(					...
				isnan(shape) ||			...
				(               ...
					(shape >= opt.shape(1)) &&	...
					(shape <= opt.shape(2))	...
				)				...
			)

            % this blob matches the filter

            % record a perimeter point
            %[y,x] = ind2sub(size(im), edge(i));
            if i==0
                % special work for the background blob, it's edge is not traced by
                % bwboundaries

                % first find a point on the edge that belongs to background
                k = find( (x==1) |(y==1) | (x==nc) | (y==nr) );
                if length(k) >0
                    % blob 0 does touch the edge
                    k = k(1);
                    ep = edgelist(binimage, [x(k) y(k)]); % trace the perim
                else
                    ep = [];
                end
            else
                ep = b{i};
            end

            if ~isempty(ep)
                F.edgepoint = [ep(1,2) ep(1,1)];    % a point on the perimeter
                e = [ep(:,2) ep(:,1)];
                F.edge = e;

                e = diff([e; e(1,:)])';

                % compute length:
                %   - 1 for horizontal/vertical segment
                %   - sqrt(2) for diagnonal
                %
                % Apply Kulpa's correction factor when computing
                % circularity
                kulpa = pi/8*(1+sqrt(2));
                F.perimeter_ = sum( colnorm(e) );

                F.circularity_ = 4*pi*F.area_/ (F.perimeter_*kulpa)^2;
            end
            % set object properties
			F.umin = umin;
			F.umax = umax;
			F.vmin = vmin;
			F.vmax = vmax;
			F.touch_ = t;
            if i > 0
                F.parent = find(a(i,:))+1;
                if isempty(F.parent)
                    F.parent = 1;
                end
                F.children = find(a(:,i))'+1;
            else
                F.parent = 1;
                F.children = [];
            end
			F.shape_ = shape;
            F.label_ = i+1;
            F.class_ = color;

            % save it in the feature vector
			blob = blob+1;
			features(blob) = F;
		end
	end

    if blob == 0
        features = [];
    end

%     % add children property
%     % the numbers in the children property refer to elements in the feature vector
%     for i=1:length(features)
%         parent = features(i).parent;
%         for F=features
%             if F.label == parent
%                 F.children = [F.children i];
%             end
%         end
%     end

	%fprintf('%d blobs in image, %d after filtering\n', nl, blob);
    if nargout > 1
        labimg = li+1;
    end


function disp(F)
%DISP   Display a CHEBFUN2 to the command line.
%
% See also DISPLAY.

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

loose = strcmp( get(0, 'FormatSpacing'), 'loose' );

% Get display style and remove trivial empty CHEBFUN2 case.
if ( isempty(F) )
    fprintf('    empty chebfun2\n')
    if ( loose )
        fprintf('\n');
    end
    return
end

% Get information that we want to display:
dom = F.domain;                           % Domain
len = length(F);                          % Numerical rank
[xx, yy] = meshgrid(dom(1:2), dom(3:4));
vals = feval(F, xx, yy ).';               % Corner values
vals = vals(:);
vscl = vscale(F);                         % vertical scale

% Check underlying tech is a TRIGTECH:
techCol = get(F.cols.funs{1}, 'tech');
techRow = get(F.rows.funs{1}, 'tech');

% Display the information:
if ( isa(techCol(), 'trigtech') && isa(techRow(), 'trigtech') )
    disp('   chebfun2 object  (trig)')
elseif ( isa(techRow(), 'trigtech') )
    disp('   chebfun2 object  (trig in x)')
elseif ( isa(techCol(), 'trigtech') )
    disp('   chebfun2 object  (trig in y)')
else
    disp('   chebfun2 object')
end
fprintf('       domain                 rank       corner values\n');
if ( isreal(vals) )
    fprintf('[%4.2g,%4.2g] x [%4.2g,%4.2g]   %6i     [%4.2g %4.2g %4.2g %4.2g]\n', ...
        dom(1), dom(2), dom(3), dom(4), len, vals);
else
    fprintf('[%4.2g,%4.2g] x [%4.2g,%4.2g]   %6i     [  complex values  ]\n', ...
        dom(1), dom(2), dom(3) , dom(4), len);
end
fprintf('vertical scale = %3.2g \n', vscl)

if ( loose )
    fprintf('\n');
end

end


function test_suite = test_randomize_targets()
% tests for cosmo_randomize_targets
%
% #   For CoSMoMVPA's copyright information and license terms,   #
% #   see the COPYING file distributed with CoSMoMVPA.           #
    try % assignment of 'localfunctions' is necessary in Matlab >= 2016
        test_functions=localfunctions();
    catch % no problem; early Matlab versions can use initTestSuite fine
    end
    initTestSuite;

function test_randomize_targets_basics()
    ds=cosmo_synthetic_dataset('ntargets',4,'nchunks',10);
    [x1,perm1]=cosmo_randomize_targets(ds);
    assertEqual(size(ds.sa.targets),[40 1])
    assertEqual(x1,ds.sa.targets(perm1))
    assertEqual(sort(perm1),(1:size(ds.samples,1))');

    x2=cosmo_randomize_targets(ds);
    assert(any(x1~=x2)); % probablity of failing less than 1e-13
    assert(any(x1~=ds.sa.targets));

    ds_small=cosmo_slice(ds,1:8);
    x3=cosmo_randomize_targets(ds_small,'seed',1);
    assertEqual(x3,[ 3 4 1 2 2 1 3 4]');

    x4=cosmo_randomize_targets(ds_small,'seed',314);
    assertEqual(x4,[ 3 2 4 1 4 3 2 1]');

    ds_single_target=cosmo_slice(ds,1:4:20);
    x5=cosmo_randomize_targets(ds_single_target,'seed',314);
    assertEqual(x5,ones(5,1));

    ds_between=cosmo_slice(ds,1:5:40);
    x6=cosmo_randomize_targets(ds_between,'seed',1);
    assertEqual(x6,[3 2 1 3 4 4 1 2]');
    x7=cosmo_randomize_targets(ds_between);
    assertEqual(histc(x7,1:4),[2 2 2 2]');

    % test exceptions
    aet=@(varargin)assertExceptionThrown(@()cosmo_randomize_targets(...
    varargin{:}),'');

    ds_missing=cosmo_slice(ds,1:3:20);
    aet(ds_missing);

    ds.sa=rmfield(ds.sa,'targets');
    aet(ds);

    ds=rmfield(ds,'sa');
    aet(ds);


#!/usr/bin/env octave
%% Machine Learning Online Class
%  Exercise 7 | Principle Component Analysis and K-Means Clustering
%
%  Instructions
%  ------------
%
%  This file contains code that helps you get started on the
%  exercise. You will need to complete the following functions:
%
%     pca.m
%     projectData.m
%     recoverData.m
%     computeCentroids.m
%     findClosestCentroids.m
%     kMeansInitCentroids.m
%
%  For this exercise, you will not need to change any code in this file,
%  or any other files other than those mentioned above.
%

%% Initialization
clear ; close all; clc

%% ================= Part 1: Find Closest Centroids ====================
%  To help you implement K-Means, we have divided the learning algorithm
%  into two functions -- findClosestCentroids and computeCentroids. In this
%  part, you shoudl complete the code in the findClosestCentroids function.
%
fprintf('Finding closest centroids.\n\n');

% Load an example dataset that we will be using
load('ex7data2.mat');

% Select an initial set of centroids
K = 3; % 3 Centroids
initial_centroids = [3 3; 6 2; 8 5];

% Find the closest centroids for the examples using the
% initial_centroids
idx = findClosestCentroids(X, initial_centroids);

fprintf('Closest centroids for the first 3 examples: \n')
fprintf(' %d', idx(1:3));
fprintf('\n(the closest centroids should be 1, 3, 2 respectively)\n');

fprintf('Program paused. Press enter to continue.\n');
pause;

%% ===================== Part 2: Compute Means =========================
%  After implementing the closest centroids function, you should now
%  complete the computeCentroids function.
%
fprintf('\nComputing centroids means.\n\n');

%  Compute means based on the closest centroids found in the previous part.
centroids = computeCentroids(X, idx, K);

fprintf('Centroids computed after initial finding of closest centroids: \n')
fprintf(' %f %f \n' , centroids');
fprintf('\n(the centroids should be\n');
fprintf('   [ 2.428301 3.157924 ]\n');
fprintf('   [ 5.813503 2.633656 ]\n');
fprintf('   [ 7.119387 3.616684 ]\n\n');

fprintf('Program paused. Press enter to continue.\n');
pause;

%% =================== Part 3: K-Means Clustering ======================
%  After you have completed the two functions computeCentroids and
%  findClosestCentroids, you have all the necessary pieces to run the
%  kMeans algorithm. In this part, you will run the K-Means algorithm on
%  the example dataset we have provided.
%
fprintf('\nRunning K-Means clustering on example dataset.\n\n');

% Load an example dataset
load('ex7data2.mat');

% Settings for running K-Means
K = 3;
max_iters = 10;

% For consistency, here we set centroids to specific values
% but in practice you want to generate them automatically, such as by
% settings them to be random examples (as can be seen in
% kMeansInitCentroids).
initial_centroids = [3 3; 6 2; 8 5];

% Run K-Means algorithm. The 'true' at the end tells our function to plot
% the progress of K-Means
[centroids, idx] = runkMeans(X, initial_centroids, max_iters, true);
fprintf('\nK-Means Done.\n\n');

fprintf('Program paused. Press enter to continue.\n');
pause;

%% ============= Part 4: K-Means Clustering on Pixels ===============
%  In this exercise, you will use K-Means to compress an image. To do this,
%  you will first run K-Means on the colors of the pixels in the image and
%  then you will map each pixel on to it's closest centroid.
%
%  You should now complete the code in kMeansInitCentroids.m
%

fprintf('\nRunning K-Means clustering on pixels from an image.\n\n');

%  Load an image of a bird
A = double(imread('bird_small.png'));

% If imread does not work for you, you can try instead
%   load ('bird_small.mat');

A = A / 255; % Divide by 255 so that all values are in the range 0 - 1

% Size of the image
img_size = size(A);

% Reshape the image into an Nx3 matrix where N = number of pixels.
% Each row will contain the Red, Green and Blue pixel values
% This gives us our dataset matrix X that we will use K-Means on.
X = reshape(A, img_size(1) * img_size(2), 3);

% Run your K-Means algorithm on this data
% You should try different values of K and max_iters here
K = 16;
max_iters = 10;

% When using K-Means, it is important the initialize the centroids
% randomly.
% You should complete the code in kMeansInitCentroids.m before proceeding
initial_centroids = kMeansInitCentroids(X, K);

% Run K-Means
[centroids, idx] = runkMeans(X, initial_centroids, max_iters);

fprintf('Program paused. Press enter to continue.\n');
pause;

%% ================= Part 5: Image Compression ======================
%  In this part of the exercise, you will use the clusters of K-Means to
%  compress an image. To do this, we first find the closest clusters for
%  each example. After that, we

fprintf('\nApplying K-Means to compress an image.\n\n');

% Find closest cluster members
idx = findClosestCentroids(X, centroids);

% Essentially, now we have represented the image X as in terms of the
% indices in idx.

% We can now recover the image from the indices (idx) by mapping each pixel
% (specified by it's index in idx) to the centroid value
X_recovered = centroids(idx,:);

% Reshape the recovered image into proper dimensions
X_recovered = reshape(X_recovered, img_size(1), img_size(2), 3);

% Display the original image
subplot(1, 2, 1);
imagesc(A);
title('Original');

% Display compressed image side by side
subplot(1, 2, 2);
imagesc(X_recovered)
title(sprintf('Compressed, with %d colors.', K));

fprintf('Program paused. Press enter to continue.\n');
pause;


% If a different type of PDM is to be trained, prepare training data here

clear
load('menpo_68_pts_flip.mat');
addpath('../PDM_helpers');

xs = all_pts(1:end/2,:);
ys = all_pts(end/2+1:end,:);
num_imgs = size(xs, 1);

pdmLoc = ['../../models/pdm/pdm_68_aligned_wild.mat'];
% pdmLoc = ['pdm_68_aligned_menpo_v1.mat'];

load(pdmLoc);

pdm = struct;
pdm.M = double(M);
pdm.E = double(E);
pdm.V = double(V);
errs_poss = [];

all_shapes = -200 * ones(num_imgs, 68 * 2);
min_x = 0;
max_x = 0;
min_y = 0;
max_y = 0;

for i=1:num_imgs

    shape2D = cat(2, all_pts(i,:)', all_pts(i+num_imgs,:)');

    M_n = M;
    ind_rem = find(shape2D(:,1) == -1);
    to_keep = setdiff(1:68, ind_rem);

    if(sum(shape2D(:)==-1) > 0)

        hidden = true;
        % which indices to remove
        inds_to_rem = shape2D(:,1) == -1 | shape2D(:,2) == -1;

        shape2D = shape2D(~inds_to_rem,:);

        inds_to_rem = repmat(inds_to_rem, 3, 1);

        M_n = M(~inds_to_rem);

    end

    % To deal with really extreme cases of roll
    M2D = cat(2, M_n(1:end/3), M_n(end/3+1:2*end/3));
    [ A, t, error, alignedShape, s ] = AlignShapesWithScale(M2D, shape2D);
    R = A/s;

    % Transform the shape
    shape2D(:,1) = shape2D(:,1) - t(1);
    shape2D(:,2) = shape2D(:,2) - t(2);

    shape2D = (R' * shape2D')/s;
    shape2D = shape2D';

%     all_pts(i,all_pts(i,:)~=-1) = shape2D(:,1);
%     all_pts(i+num_pts,all_pts(i+num_pts,:)~=-1) = shape2D(:,2);
%
    all_shapes(i,[to_keep,to_keep+68]) = shape2D(:);

    if(min(shape2D(:,1)) < min_x)
        min_x = min(shape2D(:,1));
    end
    if(min(shape2D(:,2)) < min_y)
        min_y = min(shape2D(:,2));
    end
    if(max(shape2D(:,1)) > max_x)
        max_x = max(shape2D(:,1));
    end
    if(max(shape2D(:,2)) > max_y)
        max_y = max(shape2D(:,2));
    end
end

% Scaling and shifting the model so that all points are from -1 to 1
MD = all_shapes == -200;

xs = 2 * (all_shapes(:,1:68) - min_x)/(max_x-min_x) - 1;
ys = 2 * (all_shapes(:,69:end) - min_y)/(max_y - min_y) - 1;

all_shapes = cat(2, xs, ys);
all_shapes(MD) = -2;

xs = all_shapes(:,1:68);
ys = all_shapes(:,69:end);

save('menpo_train.mat', 'all_shapes');

%%
load('menpo_68_pts_valid.mat');

xs = all_pts(1:end/2,:);
ys = all_pts(end/2+1:end,:);
num_imgs = size(xs, 1);

all_shapes = -200 * ones(num_imgs, 68 * 2);

for i=1:num_imgs

    shape2D = cat(2, all_pts(i,:)', all_pts(i+num_imgs,:)');

    M_n = M;
    ind_rem = find(shape2D(:,1) == -1);
    to_keep = setdiff(1:68, ind_rem);

    if(sum(shape2D(:)==-1) > 0)

        hidden = true;
        % which indices to remove
        inds_to_rem = shape2D(:,1) == -1 | shape2D(:,2) == -1;

        shape2D = shape2D(~inds_to_rem,:);

        inds_to_rem = repmat(inds_to_rem, 3, 1);

        M_n = M(~inds_to_rem);

    end

    % To deal with really extreme cases of roll
    M2D = cat(2, M_n(1:end/3), M_n(end/3+1:2*end/3));
    [ A, t, error, alignedShape, s ] = AlignShapesWithScale(M2D, shape2D);
    R = A/s;

    % Transform the shape
    shape2D(:,1) = shape2D(:,1) - t(1);
    shape2D(:,2) = shape2D(:,2) - t(2);

    shape2D = (R' * shape2D')/s;
    shape2D = shape2D';

%     all_pts(i,all_pts(i,:)~=-1) = shape2D(:,1);
%     all_pts(i+num_pts,all_pts(i+num_pts,:)~=-1) = shape2D(:,2);
%
    all_shapes(i,[to_keep,to_keep+68]) = shape2D(:);

end

% Scaling and shifting the model so that all points are from -1 to 1
MD = all_shapes == -200;

xs = 2 * (all_shapes(:,1:68) - min_x)/(max_x-min_x) - 1;
ys = 2 * (all_shapes(:,69:end) - min_y)/(max_y - min_y) - 1;

all_shapes = cat(2, xs, ys);
all_shapes(MD) = -2;

xs = all_shapes(:,1:68);
ys = all_shapes(:,69:end);

save('menpo_valid.mat', 'all_shapes');


function tcell_flow_movie ( )

%*****************************************************************************80
%
%% TCELL_FLOW_MOVIE animates the TCELL data.
%
%  Discussion:
%
%    This MATLAB script file reads the T-Cell flow data:
%
%      geometry (XY values at nodes, assumed to be in 'xy.txt')
%      flow (UV values at nodes, in a sequence of files starting with 'up001.txt')
%
%    and plots the velocity vectors (U,V)(X,Y), saving each plot and
%    making an animation.
%
%    The file plots either the velocity vector field, or the velocity
%    direction field, depending on the value of the internal logical
%    parameter "normalized".
%
%    The MATLAB routine quiver internally scales the vectors, but this can
%    be adjusted by using a value of SCALE that is not 1.
%
%    For the unnormalized case, the velocity field is computed to a fixed
%    scale determined by finding the largest velocity vector over time.
%
%    This routine requires some auxiliary routines in order to "increment"
%    the name of the current velocity data file to get the name of the next
%    one, with the main such routine being called FILE_NAME_INC.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    05 July 2003
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TCELL_FLOW_MOVIE:\n' );
  fprintf ( 1, '  Create a movie of flow in the TCELL.\n' );

  FALSE = 0;
  TRUE = 1;
  scale = 1.0;
  normalized = TRUE;

  nframes = 500;
%
%  Get the XY coordinates of the nodes.
%
  load xy.txt;

  x = xy(:,1);
  y = xy(:,2);
%
%  Compute the thinning index.
%
  thin_factor = 4;
  thin_dex = thin_index ( x, y, thin_factor );
  thin_num = length ( thin_dex );
  x = x(thin_dex);
  y = y(thin_dex);
%
%  For unnormalized plots, you need to make sure that a fixed scale is preserved from
%  step to step.  The only way I can see to do this requires that I determine the
%  maximum velocity over all time, and then append one extra node and velocity
%  to the data structure.
%
  if ( normalized == FALSE )

    upfile = 'up000.txt';
    vnorm_max = 0.0;

    for i = 1 : nframes
      i
      upfile = file_name_inc ( upfile );
      uv = load ( upfile );
      u = uv(thin_dex,1);
      v = uv(thin_dex,2);
      norm = sqrt ( u.^2 + v.^2 );
      vnorm_max = max ( vnorm_max, max ( norm ) );
    end

    fprintf ( 1, '\n' );
    fprintf ( 1, '  Maximum visible velocity magnitude is %f\n', vnorm_max );

  end
%
%  Set the coordinates of the boundary lines, and an extra set of
%  lines that will be invisible, but which make some space for the
%  file name to be displayed within the plot area.
%
  bx1 = [ 0.00, 1.00, 1.00, 0.00, 0.00, 0.00 ];
  by1 = [ 1.00, 1.00, 0.99, 0.99, 0.99, 1.00 ];

  bx2 = [ 0.00, 0.25, 0.25, 0.75, 0.75, 1.00, 1.00, 0.74, 0.74, ...
          0.26, 0.26, 0.00, 0.00];
  by2 = [ 0.50, 0.50, 0.00, 0.00, 0.50, 0.50, 0.51, 0.51, 0.01, ...
          0.01, 0.51, 0.51, 0.50];

  bx3 = [ -0.10,  1.10, 1.10, -0.10, -0.10 ];
  by3 = [ -0.10, -0.10, 1.10,  1.10, -0.10 ];
%
%  Set the name of the 0th (nonexistent) velocity file.
%  All the velocity files will have this format, with the
%  numeric part of the name incremented to get the next one.
%  In particular, the first velocity file is called UP001.TXT.
%
  upfile = 'up000.txt';

  for i = 1 : nframes

    i
    upfile = file_name_inc ( upfile );
    uv = load ( upfile );
    u = uv(thin_dex,1);
    v = uv(thin_dex,2);

    if ( normalized == TRUE )
      norm = sqrt ( u.^2 + v.^2 );
      nonzero = find ( norm ~= 0.0 );
      u(nonzero) = u(nonzero) ./ norm(nonzero);
      v(nonzero) = v(nonzero) ./ norm(nonzero);
      vnorm_max = 1.0;
    end

    x(thin_num+1) = 0.00;
    y(thin_num+1) = 1.05;
    u(thin_num+1) = vnorm_max;
    v(thin_num+1) = 0.0;

    quiver ( x, y, u, v, scale )
%
%  Draw the boundary lines, and the invisible bounding line.
%
    line ( bx1, by1, 'color', 'r' )
    line ( bx2, by2, 'color', 'r' )
    line ( bx3, by3, 'color', 'w' )
    axis equal
    if ( normalized == TRUE )
      title ( 'T-Cell Direction Field' )
    else
      title ( 'T-Cell Flow Field' )
    end
    text ( 0.420, 1.03, upfile )

    my_frames(:,i) = getframe;

  end
%
%  Display the movie a given number of times.
%
  movie ( my_frames, 1 )

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TCELL_FLOW_MOVIE:\n' );
  fprintf ( 1, '  Normal end of execution.\n' );

  return
end
function file_name = file_name_inc ( file_name )

%*****************************************************************************80
%
%% FILE_NAME_INC generates the next filename in a series.
%
%  Discussion:
%
%    It is assumed that the digits in the name, whether scattered or
%    connected, represent a number that is to be increased by 1 on
%    each call.  If this number is all 9's on input, the output number
%    is all 0's.  Non-numeric letters of the name are unaffected..
%
%    If the name is empty, then the routine stops.
%
%    If the name contains no digits, the empty string is returned.
%
%  Example:
%
%      Input            Output
%      -----            ------
%      'a7to11.txt'     'a7to12.txt'  (typical case.  Last digit incremented)
%      'a7to99.txt'     'a8to00.txt'  (last digit incremented, with carry.)
%      'a9to99.txt'     'a0to00.txt'  (wrap around)
%      'cat.txt'        ' '           (no digits in input name.)
%      ' '              STOP!         (error.)
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 September 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string FILE_NAME, the string to be incremented.
%
%    Output, string FILE_NAME, the incremented string.
%
  lens = length ( file_name );

  if ( lens <= 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'FILE_NAME_INC - Fatal error!\n' );
    fprintf ( 1, '  The input filename is empty.\n' );
    error ( 'FILE_NAME_INC - Fatal error!' );
  end

  change = 0;

  for i = lens : -1 : 1

    c = file_name(i);

    if ( '0' <= c & c <= '8' )

      change = change + 1;

      c = c + 1;

      file_name(i) = c;

      return

    elseif ( c == '9' )

      change = change + 1;

      c = '0';

      file_name(i) = c;

    end

  end

  if ( change == 0 )
    file_name = ' ';
  end

  return
end
function thin_dex = thin_index ( x, y, thin_factor )

%*****************************************************************************80
%
%%  THIN_INDEX determines thinning indices for a X, Y data.
%
%  Discussion:
%
%    A set of X, Y data is given, that is presumably, not too far off
%    from being on a rectangular grid.
%
%    The input value of THIN_FACTOR indicates by how much the data should
%    be thinned.
%
%    The X and Y ranges are computed, and only those data points are
%    retained for which both X and Y lie in an appropriate subrange.
%
%    For instance, a THIN_FACTOR of 2 would essentially save data
%    that lay in the black squares of a checkerboard.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    17 June 2003
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real X(NODE_NUM), Y(NODE_NUM), the X and Y coordinates
%    of the nodes.
%
%    Input, integer THIN_FACTOR, the thinning factor.
%
%    Output, integer THIN_DEX(NODE_NUM), contains in (1:THIN_NUM) the
%    indices into X and Y of the vectors to be retained after thinning.
%
  TRUE = 1;
  FALSE = 0;

  node_num = length ( x );

  x_unique_num = 0;

  for i = 1 : node_num

    unique = TRUE;

    for j = 1 : x_unique_num
      if ( x(i) == x_unique(j) )
        unique = FALSE;
        break;
      end
    end

    if ( unique )
      x_unique_num = x_unique_num + 1;
      x_unique(x_unique_num) = x(i);
    end

  end

  sort ( x_unique );

  y_unique_num = 0;

  for i = 1 : node_num

    unique = TRUE;

    for j = 1 : y_unique_num
      if ( y(i) == y_unique(j) )
        unique = FALSE;
        break;
      end
    end

    if ( unique )
      y_unique_num = y_unique_num + 1;
      y_unique(y_unique_num) = y(i);
    end

  end

  sort ( y_unique );

  thin_num = 0;

  for i = 1 : node_num

    for j = 1 : x_unique_num-1
      if ( x_unique(j) <= x(i) & x(i) <= x_unique(j+1) )
        x_bin = j;
        break;
      end
    end

    for j = 1 : y_unique_num-1
      if ( y_unique(j) <= y(i) & y(i) <= y_unique(j+1) )
        y_bin = j;
        break;
      end
    end

    if ( mod ( y_bin, thin_factor ) == thin_factor / 2 & ...
         mod ( x_bin, thin_factor ) == thin_factor / 2 )

      thin_num = thin_num + 1;
      thin_dex(thin_num) = i;

    end

  end
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TCELL_FLOW_MOVIE\n' );
  fprintf ( 1, '  Normal end of execution.\n' );

  return
end


function out = scimat_resample(inp,out,kind)
% SCIMAT_RESAMPLE resamples a scimat file given an input and output scimat.
%
% Intended for mapping 2D slices in 3D volume or extract 2D
% slices from 3D volume. Also works nicely between 1D and 2D to extract
% profiles, for example.
%
% OUT = SCIMAT_RESAMPLE(INP, OUT, KIND)
%
%   INP is the input scimat file
%
%   OUT is the target scimat file
%
%   KIND is a string, deciding on the kind of interpolation/averaging
%
% See also: scimat_resize3, scimat_downsample.

% Author: Nicolas Basty <nicolas.basty@eng.ox.ac.uk>
% Copyright © 2016 University of Oxford
% Version: 0.1.2
%
% University of Oxford means the Chancellor, Masters and Scholars of
% the University of Oxford, having an administrative office at
% Wellington Square, Oxford OX1 2JD, UK.
%
% This file is part of Gerardus.
%
% 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. The offer of this
% program under the terms of the License is subject to the License
% being interpreted in accordance with English Law and subject to any
% action against the University of Oxford being under the jurisdiction
% of the English Courts.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.
% _________________________________________________________________

[x,y,z] = inp.axis.spacing; %get in and output resolutions
[x_o,y_o,z_o] = out.axis.spacing;

if x_o>x %taking lower resolution
    x = x_o;
    y = y_o;
    z = z_o;
end

sigmaa = [x,y,inf]/2;
ws =  sigmaa*3; %window size
ws(3) = z/2;
rrrr=r;
if strcmp(kind,'gaussian') % get the weighting function
    W = @(xl,yl,zl) exp(-(xl.^2)/(2*sigmaa(1)^2)...
        -(yl.^2)/(2*sigmaa(2)^2)...
        -(zl.^2)/(2*sigmaa(3)^2));
elseif strcmp(kind,'sinc')
    W = @(xl,yl,zl) (sin(sigmaa(1)*xl)./(sigmaa(1)*xl))...
        .* (sin(sigmaa(2)*yl)./(sigmaa(2)*yl))...
        .* (sin(sigmaa(3)*zl)./(sigmaa(3)*zl));
elseif strcmp(kind,'nearest')
    %does something later, l84
else
    fprintf('Weighting method expected to be gaussian, sinc or nearest\n')
    return
end

To = scimat2transform(inp); %gets transform from input image mapping IDX to RW
Ti = scimat2transform(out);  %gets transform from target image mapping IDX to RW
T = pinv(To) * Ti; %combining gives IDXin to IDXout

% create grid of output�s indices
if numel(out.data)>2
    [X, Y, Z] = ndgrid(1:size(out.data,1), 1:size(out.data,2), 1:size(out.data,3));
elseif  numel(out.data)<3
    [X, Y, Z] = ndgrid(1:size(out.data,1), 1:size(out.data,2), 1);
end
% for each of the output index, find its corresponding input index
XYZin = T * [X(:), Y(:), Z(:), ones(size(X(:)))]';

% round them to do nearest neightbour assignment
Xin = round(XYZin(1,:));
Yin = round(XYZin(2,:));
Zin = round(XYZin(3,:));

% find which ones are valid (input space)
valid_indices = (Xin > 0) & (Xin <= size(inp.data,1)) & (Yin > 0) & (Yin <= size(inp.data,2)) & (Zin > 0) & (Zin <= size(inp.data,3));

%%
inpt = double(inp.data); %get data out of the structures
outp = double(out.data);

allind = 1:numel(valid_indices);
allind = allind(valid_indices);

[xi,yi,zi] = scimat_ndgrid(inp); % grid of input rw
[xo,yo,zo] = scimat_ndgrid(out); % grid of output rw

vox_out = [xo(:),yo(:),zo(:)];

[Xi, Yi, Zi] = ndgrid(1:size(inp.data,1), 1:size(inp.data,2), 1:size(inp.data,3));
xyzin = round(pinv(T)*[Xi(:) Yi(:) Zi(:) ones(size(Xi(:)))]');
xin = xyzin(1,:);
yin = xyzin(2,:);
zin = xyzin(3,:);
%using indices to get valid voxels, but the other part works better in
%rw... window size gets messed up when converting to index
valid_indices_out = (xin > 0) & (xin <= size(out.data,1)) & (yin > 0) & (yin <= size(out.data,2)) & (zin > 0) & (zin <= size(out.data,3));

inpt_val = inpt(valid_indices_out);
%keep voxels relevant to the averaging
xi = xi(valid_indices_out);
yi = yi(valid_indices_out);
zi = zi(valid_indices_out);

if strcmp(kind,'nearest')
    source_indices = sub2ind(size(inp.data), Xin(valid_indices), Yin(valid_indices), Zin(valid_indices));
    valid_intensities_input = inp.data(source_indices);
    out.data(valid_indices) = valid_intensities_input;
    return
end
outpdummy = zeros(numel(allind),1);
% xyz = [xi(:) yi(:) zi(:)];
% par parfor is actually slower for the data I am using so I commented it
% out
for r = 1:numel(allind)
    p =  vox_out(allind(r),:)';
    % get a neighbourhood of vox_out around this point (rw)
    mask = (abs(xi-p(1)) <= ws(1)) & (abs(yi - p(2)) <= ws(2)) & (abs(zi - p(3)) <= ws(3));
    %     mask = bsxfun(@le, (abs(bsxfun(@minus, xyz, p'))), ws);
    %     mask = sum(mask,2)==3;
    % get a shortlist of voxels in the window & distances for weighting
    xlist = xi(mask) - p(1);
    ylist = yi(mask) - p(2);
    zlist = zi(mask) - p(3);
    Ilist = inpt_val(mask);

    % get a weighted average
    outpdummy(r) = sum(W(xlist,ylist,zlist).*Ilist) / (sum(W(xlist,ylist,zlist)+eps));
end
outp(allind) = outpdummy;
outp(isnan(outp)) = 0;
out.data = outp;
end


function [out,x] =  symmetric_bc( x, nx)

    if(x < 0)
   border = nx - 1;
       xx = -x;
        n  = mod((xx/border) , 2);

        if ( n ) x = border - (mod( xx ,border) );
        else x = mod(xx , border);
        out = 1;
        end
        elseif ( x >= nx )
         border = nx - 1;
         n = mod((x/border) , 2);
        end
        if ( n ) x = border - ( mod(x , border) );
        else x = mod(x , border);
        out = 1;

        end
end


function [slice_number]=dicomrt_findsliceVECT(vectref,slice,vect,PatientPosition,edges)
% dicomrt_findsliceVECT(vectref,slice,vect,PatientPosition,edges)
%
% Find the location of a point among different vectors.
%
% vectref is the vector of reference
% slice is the slice number (defined in voilookup)
% vect is the vector where to search for slice
% PatientPoisition is the code which defines the patient orientation
% edges is an OPTIONAL parameter
%     if edges==1 vectors define boundaries of pixels
%     if edges==0 (default) vectors define centers of pixels
%
% Example:
%
% [num]=dicomrt_findsliceVECT(dose_xmesh,30,ct_xmesh);
%
% returns in num the slice number in ct_xmesh which correspond to slice "30" in dose_xmesh.
%
% See also dicomrt_findslice, dicomrt_getPatientPosition, hist, histc
%
% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org)

% Check number of argument and set-up some parameters and variables
error(nargchk(4,5,nargin))

if exist('edges')==0
    edges=1;
end

if edges==1
    if slice<=length(vectref)
        if PatientPosition==1
            locate_slice=histc(vectref(slice),vect);
            slice_number=find(locate_slice);
        elseif PatientPosition==2
            locate_slice=histc(vectref(slice),vect);
            slice_number=find(locate_slice);
        elseif PatientPosition==3
            if issorted(vectref)~=1 & issorted(vect)~=1 % if sorted this is a Z slice which is always sorted
                [vectref,index_vectref]=sort(vectref);
                [vect,index_vect]=sort(vect);
                locate_slice=histc(vectref(length(vectref)-slice+1),vect);
                slice_number=index_vect(find(locate_slice));
            else
                locate_slice=histc(vectref(slice),vect);
                slice_number=find(locate_slice);
            end
        else
            if issorted(vectref)~=1 & issorted(vect)~=1 % if sorted this is a Z slice which is always sorted
                [vectref,index_vectref]=sort(vectref);
                [vect,index_vect]=sort(vect);
                locate_slice=histc(vectref(length(vectref)-slice+1),vect);
                slice_number=index_vect(find(locate_slice));
            else
                locate_slice=histc(vectref(slice),vect);
                slice_number=find(locate_slice);
            end
        end
    else
        slice_number=[];
    end
else
    if slice<=length(vectref)
        if PatientPosition==1
            locate_slice=hist(vectref(slice),vect);
            slice_number=find(locate_slice);
        elseif PatientPosition==2
            locate_slice=hist(vectref(slice),vect);
            slice_number=find(locate_slice);
        elseif PatientPosition==3
            if issorted(vectref)~=1 & issorted(vect)~=1 % if sorted this is a Z slice which is always sorted
                [vectref,index_vectref]=sort(vectref);
                [vect,index_vect]=sort(vect);
                locate_slice=hist(vectref(length(vectref)-slice+1),vect);
                slice_number=index_vect(find(locate_slice));
            else
                locate_slice=hist(vectref(slice),vect);
                slice_number=find(locate_slice);
            end
        else
            if issorted(vectref)~=1 & issorted(vect)~=1 % if sorted this is a Z slice which is always sorted
                [vectref,index_vectref]=sort(vectref);
                [vect,index_vect]=sort(vect);
                locate_slice=hist(vectref(length(vectref)-slice+1),vect);
                slice_number=index_vect(find(locate_slice));
            else
                locate_slice=hist(vectref(slice),vect);
                slice_number=find(locate_slice);
            end
        end
    else
        slice_number=[];
    end
end


% Make an HMM with autoregressive Gaussian observations (switching AR model)
%   X1 -> X2
%   |     |
%   v     v
%   Y1 -> Y2

seed = 0;
rand('state', seed);
randn('state', seed);

intra = zeros(2);
intra(1,2) = 1;
inter = zeros(2);
inter(1,1) = 1;
inter(2,2) = 1;
n = 2;

Q = 2; % num hidden states
O = 2; % size of observed vector

ns = [Q O];
dnodes = 1;
onodes = [2];
bnet = mk_dbn(intra, inter, ns, 'discrete', dnodes, 'observed', onodes);

bnet.CPD{1} = tabular_CPD(bnet, 1);
bnet.CPD{2} = gaussian_CPD(bnet, 2);
bnet.CPD{3} = tabular_CPD(bnet, 3);
bnet.CPD{4} = gaussian_CPD(bnet, 4);

T = 10; % fixed length sequences

engine = {};
%engine{end+1} = hmm_inf_engine(bnet);
engine{end+1} = jtree_unrolled_dbn_inf_engine(bnet, T);
%engine{end+1} = smoother_engine(hmm_2TBN_inf_engine(bnet));
%engine{end+1} = smoother_engine(jtree_2TBN_inf_engine(bnet));

inf_time = cmp_inference_dbn(bnet, engine, T, 'check_ll',1);
learning_time = cmp_learning_dbn(bnet, engine, T, 'check_ll', 1);


function y = truerand(varargin)
% TRUERAND Returns truly random integers using random.org's Random Integer
%   Generator. According to random.org, the numbers are generated based on
%   atmospheric noise and skew-corrected to generate uniform numbers. The
%   generated numbers have been shown to pass the NIST tests for RNGs.
%
%   The range of numbers is -1e9 to 1e9 and the maximum number of values
%   that can be generated is 10,000
%
% USAGE:
%  truerand(rows,cols,min,max) returns a matrix of size rows-by-cols with
%  random integers between min and max.
%  truerand(n,min,max) returns an n by 1 vector
%  truerand(n, m) uses the default values min = 1, max = 100
%  truerand(n) and truerand
%
% EXAMPLES:
%  y = truerand
%  y = truerand(9)
%  y = truerand(6,6)
%  y = truerand(5,1,20)
%  y = truerand(3, 4, 15, 30)
%
% For more information visit random.org

m = 1;
n = 1;
min = 1;
max = 100;
seed = 'new'; % New implies new random numbers - they will not be the same with each run

if nargin > 0
    m = varargin{1};
end
if nargin == 2 || nargin == 4
    n = varargin{2};
end

if m*n>=10000
    error('The maximum number of values requested must be no greater than 10000')
end

if min < -1e9 || max > 1e9
    error('The range of values must lie in [-1e9, 1e9]')
end

if nargin == 3 || nargin == 4
    [min,max] = varargin{end-1:end};
end

url = sprintf('http://www.random.org/integers/?num=%d&min=%d&max=%d&col=1&base=10&format=plain&rnd=%s',...
              m*n, min, max, seed);
data = urlread(url);
y = reshape(str2num(data),m,n); %#ok<ST2NM>


im = iread('tomato_124.jpg', 'gamma', 'sRGB', 'double');
figure(1); idisp(im)
randinit
[cls, cxy] = colorkmeans(im, 4);
figure(2); idisp(cls)
cxy

cls2 = (cls == 2);
figure(1); idisp(cls2);
binary_im = iclose(cls2, kcircle(15));
figure(2); idisp(binary_im)

f = iblobs(binary_im, 'boundary', 'class', 1)

idisp(im)
f.plot_boundary('r.')
f.plot_box('g')


function Y = tapas_uniqc_create_shepp_logan_4d()
% Creates 4D Shepp-Logan Phantom for tapas_uniqc_slider4d demo
%
%   output = tapas_uniqc_create_shepp_logan_4d(input)
%
% IN
%
% OUT
%
% EXAMPLE
%   tapas_uniqc_create_shepp_logan_4d
%
%   See also

% Author:   Saskia Bollmann & Lars Kasper
% Created:  2015-11-20
% Copyright (C) 2015 Institute for Biomedical Engineering
%                    University of Zurich and ETH Zurich
%
% This file is part of the TAPAS UniQC Toolbox, which is released
% under the terms of the GNU General Public License (GPL), version 3.
% You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version).
% For further details, see the file COPYING or
%  <http://www.gnu.org/licenses/>.

% parameter specs, create shepp logan phantom
nX = 64;
nY = nX;
nSli = 32;
nDyn = 20;

P = phantom('Modified Shepp-Logan',nX);

% create different slices via shift
Y = zeros(nX,nY,nSli,1);
for iSli = 1:nSli
    Y(:,:,iSli,1) = circshift(P, iSli*floor(nX/nSli));
end

% replicate over number of dynamics and add some noise to make them
% different
Y = repmat(Y, [1 1 1 nDyn]) + 0.05*max(Y(:))*randn(nX,nY,nSli,nDyn);