function [pt_errs_phys, pts_moved_phys, TRE_phys, TREstd_phys] = move_points_tre_general(pts_mov_phys, ...
                        pts_fix_phys, Tr_phys, spc, lu_orig)
    if ~exist('lu_orig') || isempty(lu_orig)
        lu_orig = [0, 0, 0];
    end

    pts_moved_phys = 0 * pts_mov_phys;
    tsz = size(Tr_phys);
    tsz = tsz(1:3);
    for i = 1 : size(pts_mov_phys, 1)
        pos = round( (fl(pts_fix_phys(i, :))- lu_orig(:))./spc(:) );
        pos = min(pos, tsz(:));
        pos = max(pos, 1);
%                 pos
%         size(Tr_phys)
        pts_moved_phys(i, :) = (pts_fix_phys(i, :)' + fl(Tr_phys(pos(1), pos(2), pos(3), :)))';
    end

%     max(Tr_phys(:))
%     pts_moved_phys = bsxfun(@times, round(bsxfun(@rdivide, pts_moved_phys, spc)), spc);
%     pts_mov_phys = bsxfun(@times, round(bsxfun(@rdivide, pts_mov_phys, spc)), spc);

    pt_errs_phys = sqrt( sum((pts_moved_phys - pts_mov_phys).^2, 2) );

    TRE_phys = mean(pt_errs_phys);
    TREstd_phys = std(pt_errs_phys);
end


function y = geo_mean( x, dim, w )
error( nargchk( 1, 3, nargin ) );

%GEO_MEAN   Internal cvx version.

%
% Basic argument check
%

sx = size( x );
if nargin < 2 || isempty( dim ),
    dim = cvx_default_dimension( sx );
elseif ~cvx_check_dimension( dim ),
    error( 'Second argument must be a positive integer.' );
end

%
% Determine sizes, quick exit for empty arrays
%

sx = [ sx, ones( 1, dim - length( sx ) ) ];
nx = sx( dim );
sy = sx;
sy( dim ) = 1;
if any( sx == 0 ),
    y = ones( sy );
    return
end

%
% Third and fourth argument check
%

if nargin < 3 || isempty( w ),
    w = [];
elseif numel( w ) ~= length( w ) || ~isnumeric( w ) || ~isreal( w ) || any( w < 0 ) || any( w ~= floor( w ) ),
    error( 'Third argument must be a vector of nonnegative integers.' );
elseif length( w ) ~= nx,
    error( 'Third argument must be a vector of length %d', nx );
elseif ~any( w ),
    y = ones( sy );
    return
end

%
% Type check
%

persistent remap_1 remap_2 remap_3 remap_4
if isempty( remap_4 ),
    % Constant (postive or negative)
    remap_1 = cvx_remap( 'real' );
    remap_2 = cvx_remap( 'concave' );
    remap_3 = cvx_remap( 'log-convex' );
    remap_4 = cvx_remap( 'log-concave' );
end
vx = cvx_reshape( cvx_classify( x ), sx );
t1 = all( reshape( remap_1( vx ), sx ), dim );
t2 = all( reshape( remap_2( vx ), sx ), dim );
t3 = all( reshape( remap_3( vx ), sx ), dim ) | ...
     all( reshape( remap_4( vx ), sx ), dim );
% Valid combinations with zero or negative entries can be treated as constants
t1 = t1 | ( ( t2 | t3 ) & any( vx == 1 | vx == 9, dim ) );
ta = t1 + ( 2 * t2 + 3 * t3 ) .* ~t1;
nu = sort( ta(:) );
nu = nu([true;diff(nu)~=0]);
nk = length( nu );

%
% Permute and reshape, if needed
%

perm = [];
if nk > 1 || ( any( nu > 1 ) && nx > 1 ),
    if dim > 1 && any( sx( 1 : dim - 1 ) > 1 ),
        perm = [ dim, 1 : dim - 1, dim + 1 : length( sx ) ];
        x    = permute( x,  perm );
        sx   = sx( perm ); %#ok
        sy   = sy( perm );
        ta   = permute( ta, perm );
        dim  = 1;
    else
        perm = [];
    end
    nv = prod( sy );
    x  = reshape( x, nx, nv );
    ta = reshape( ta, 1, nv );
end

%
% Perform the computations
%

if nk > 1,
    y = cvx( [ 1, nv ], [] );
end
for k = 1 : nk,

    if nk == 1,
        xt = x;
        sz = sy; %#ok
    else
        tt = ta == nu( k );
        xt = cvx_subsref( x, ':', tt );
        nv = nnz( tt );
        sz = [ 1, nv ]; %#ok
    end

    switch nu( k ),
        case 0,
            error( 'Disciplined convex programming error:\n   Invalid computation: geo_mean( {%s} )', cvx_class( xt, true, true ) );
        case 1,
            yt = cvx( geo_mean( cvx_constant( xt ), dim, w ) );
        case 2,
            cvx_begin
                hypograph variable yt(sz);
                { cvx_accept_concave(xt), yt } == geo_mean_cone( size(xt), dim,  w, 'func' );
            cvx_end
        case 3,
            if nx == 1,
                yt = xt;
            elseif isempty( w ),
                yt = exp( sum( log( xt ), 1 ) * ( 1 / nx ) );
            else
                yt = exp( ( w / sum( w ) ) * log( xt ) );
            end
        otherwise,
            error( 'Shouldn''t be here.' );
    end

    if nk == 1,
        y = yt;
    else
        y = cvx_subsasgn( y, tt, yt );
    end

end

%
% Reverse the reshaping and permutation steps
%

y = reshape( y, sy );
if ~isempty( perm ),
    y = ipermute( y, perm );
end

% Copyright 2010 Michael C. Grant and Stephen P. Boyd.
% See the file COPYING.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


classdef PlottingVademecumSuperEllipseVsStress < handle

    properties (Access = private)
        phiV
        qOpt
        qMin
        qMax
        qMean
        xi
        rho
        compressedFileName
        vademecum
    end

    properties (Access = private)

    end

    methods (Access = public)

        function obj = PlottingVademecumSuperEllipseVsStress()
            obj.init();
            obj.loadCompressedVademecum();
            obj.compute();
        end

    end

    methods (Access = private)

        function init(obj)
            obj.compressedFileName = 'OptimalSuperEllipses';
        end

        function loadCompressedVademecum(obj)
            d = load(obj.compressedFileName);
            obj.vademecum = d;
        end

        function compute(obj)
            nMx  = size(obj.vademecum.q,1);
            nMy  = size(obj.vademecum.q,2);
            for iMx = 1:nMx
                for iMy = 1:nMy
                    obj.computeDataForPlotter(iMx,iMy)
                    obj.plot(iMx,iMy);
                end
            end
        end

        function computeDataForPlotter(obj,iMx,iMy)
            obj.computeXi(iMx,iMy);
            obj.computeRho(iMx,iMy);
            obj.computePhi(iMx,iMy);
            obj.computeQopt(iMx,iMy);
            obj.computeQminQmax();
            obj.computeQmean();
        end

        function computeXi(obj,iMx,iMy)
            v = obj.vademecum;
            obj.xi = v.xi(iMx,iMy,1);
        end

        function computeRho(obj,iMx,iMy)
            v = obj.vademecum;
            obj.rho = v.rho(iMx,iMy,1);
        end

        function computePhi(obj,iMx,iMy)
            v = obj.vademecum;
            obj.phiV = squeeze(v.phi(iMx,iMy,:));
        end

        function computeQopt(obj,iMx,iMy)
            v = obj.vademecum;
            obj.qOpt = squeeze(v.q(iMx,iMy,:));
        end

        function computeQminQmax(obj)
            s.mxMax = 0.99;
            s.myMax = 0.99;
            s.mxMin = 0.01;
            s.myMin = 0.01;
            s.xi =  obj.xi;
            s.rho = obj.rho;
            sC = SuperellipseExponentBoundsComputer(s);
            obj.qMin = sC.qMin;
            obj.qMax = sC.qMax;
        end

        function computeQmean(obj)
            s.phiV = obj.phiV;
            qMeanC    = SuperEllipseMeanExponentComputer(s);
            obj.qMean = qMeanC.compute(obj.qOpt,obj.xi);
        end

        function plot(obj,iMx,iMy)
            nMx  = size(obj.vademecum.q,1);
            iter = (iMx-1)*nMx + iMy;
            s.phiV   = obj.phiV;
            s.qOpt   = obj.qOpt;
            s.qMin   = obj.qMin;
            s.qMax   = obj.qMax;
            s.qMean  = obj.qMean;
            s.rho    = obj.rho;
            s.xi     = obj.xi;
            p = OptimalSuperEllipseExponentVsGaussianPlotter(s);
            p.plot(iter);
        end

%
%         function isConsistent = checkConsistency(obj,qV,rhoV,xiV,mxV,myV,iMx,iMy,iphi)
%             xi  = xiV(iMx,iMy,iphi);
%             rho = rhoV(iMx,iMy,iphi);
%             q = qV(iMx,iMy,iphi);
%             mx = mxV(iMx);
%             my = myV(iMy);
%             errorMx = norm(mx - SuperEllipseParamsRelator.mx(xi,rho,q))/norm(mx)
%             errorMy = norm(my - SuperEllipseParamsRelator.my(xi,rho,q))/norm(my)
%             isMxEqual = errorMx < 1e-14;
%             isMyEqual = errorMy < 1e-14;
%             isConsistent = isMxEqual && isMyEqual;
%         end

    end

end


function varargout=rem(varargin)
%REM (overloaded)

switch class(varargin{1})

    case 'sdpvar' % Overloaded operator for SDPVAR objects. Pass on args and save them.

        if ~isa(varargin{2},'double')
            error('REM is currently only supported for DOUBLE second argument');
        end

        x = varargin{1};
        y = varargin{2};
        % Some boring code for scalarization
        if prod(size(x))==1 & prod(size(y))>1
            x = x*ones(size(y));
        elseif prod(size(y))==1 & prod(size(x))>1
            y = y*ones(size(x));
        end
        if ~all(size(x) == size(y))
            error('Matrix dimensions must agree.');
        end
        dim = size(x);
        x = reshape(x,prod(dim),1);
        y = reshape(y,prod(dim),1);
        z = [];
        % Create one variable for each element
        for i = 1:length(x)
            xi = extsubsref(x,i);
            yi = extsubsref(y,i);
            inarg = {xi,yi};
            z = [z;yalmip('define',mfilename,inarg{:})];
        end
        z = reshape(z,dim);
        varargout{1} = z;

    case 'char' % YALMIP send 'graph' when it wants the epigraph or hypograph

        % Description using epigraphs
        t = varargin{2};
        x = varargin{3};
        y = varargin{4};

        % t = rem(x,y), i.e. t = x - n*y, n = fix(x/y)
        d1 = binvar(1,1);
        d2 = binvar(1,1);
        [M,m] = derivebounds(x);
        n = intvar(1,1);
        F = [t == x - y*n, d1+d2 == 1];
        F = [F,x>=m*(1-d1), x<=M*(1-d2),(x/y)-d1 <= n <= (x/y)+d2];
        if ~isinf(m) && isa(y,'double')
            F = [F, fix(m/y) <= n];
        end
        if ~isinf(M) && isa(y,'double')
            F = [F, n <= fix(M/y)];
        end

        varargout{1} = F;
        varargout{2} = struct('convexity','none','monotonicity','none','definiteness','none','model','integer');
        varargout{3} = [x(:);y(:)];

    otherwise
        error(['SDPVAR/' upper(mfilename) ' called with weird argument']);
end


%MDL_STANFORD Create model of Stanford arm
%
%      mdl_stanford
%
% Script creates the workspace variable stanf which describes the
% kinematic and dynamic characteristics of the Stanford (Scheinman) arm.
%
% Also defines the vectors:
%   qz   zero joint angle configuration.
%
% Note::
% - SI units are used.
% - Gear ratios not currently known, though reflected armature inertia
%   is known, so gear ratios are set to 1.
%
% References::
% - Kinematic data from "Modelling, Trajectory calculation and Servoing of
%   a computer controlled arm".  Stanford AIM-177.  Figure 2.3
% - Dynamic data from "Robot manipulators: mathematics, programming and control"
%   Paul 1981, Tables 6.5, 6.6
% - Dobrotin & Scheinman, "Design of a computer controlled manipulator for
%   robot research", IJCAI, 1973.
%
% See also SerialLink, mdl_puma560, mdl_puma560akb.

% MODEL: Stanford, Stanford Arm, prismatic, 6DOF, standard_DH

% Copyright (C) 1993-2015, by Peter I. Corke
%
% This file is part of The Robotics Toolbox for MATLAB (RTB).
%
% RTB 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.
%
% RTB 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 RTB.  If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com

clear L
%             th    d       a    alpha
L(1) = Link([ 0     0.412   0   -pi/2     0]);
L(2) = Link([ 0     0.154   0    pi/2     0]);
L(3) = Link([ -pi/2 0       0    0        1]);  % PRISMATIC link
L(4) = Link([ 0     0       0   -pi/2     0]);
L(5) = Link([ 0     0       0    pi/2     0]);
L(6) = Link([ 0     0.263   0    0        0]);

% guestimates of some parameters
%
% According to the IJCAI paper the rack is 38in and the maximum reach is 52in
% From the image http://infolab.stanford.edu/pub/voy/museum/pictures/display/robots/IMG_2408ArmCenter.JPG
% and scaled by the rack length (38in) it looks like the minimum stroke is 12in.
%
L(3).qlim = [12 12+38] * 0.0254;

% According to the IJCAI paper
L(1).qlim = [-170 170]*pi/180;
L(2).qlim = [-170 170]*pi/180;
L(4).qlim = [-170 170]*pi/180;
L(5).qlim = [-90 90]*pi/180;
L(6).qlim = [-170 170]*pi/180;

L(1).m = 9.29;
L(2).m = 5.01;
L(3).m = 4.25;
L(4).m = 1.08;
L(5).m = 0.630;
L(6).m = 0.51;

L(1).Jm = 0.953;
L(2).Jm = 2.193;
L(3).Jm = 0.782;
L(4).Jm = 0.106;
L(5).Jm = 0.097;
L(6).Jm = 0.020;

L(1).G = 1;
L(2).G = 1;
L(3).G = 1;
L(4).G = 1;
L(5).G = 1;
L(6).G = 1;

L(1).I = [0.276   0.255   0.071   0   0   0];
L(2).I = [0.108   0.018   0.100   0   0   0];
L(3).I = [2.51    2.51    0.006   0   0   0 ];
L(4).I = [0.002   0.001   0.001   0   0   0 ];
L(5).I = [0.003   0.0004  0       0   0   0];
L(6).I = [0.013   0.013   0.0003  0   0   0];

L(1).r = [0    0.0175 -0.1105];
L(2).r = [0   -1.054  0];
L(3).r = [0    0      -6.447];
L(4).r = [0    0.092  -0.054];
L(5).r = [0    0.566   0.003];
L(6).r = [0    0       1.554];

qz = [0 0 0 0 0 0];

stanf = SerialLink(L, 'name', 'Stanford arm');
stanf.plotopt = {'workspace', [-2 2 -2 2 -2 2]};
stanf.model3d = 'example/stanford';


% Rmem_test.m

% check match between Reg1 and Rmem
if 1 | ~isvar('Rm'), printm 'Rm'
	if 0
		ig = image_geom('nx', 512, 'ny', 496, 'nz', 16, 'fov', 500, ...
			'down', 4);
	else % 2d
		ig = image_geom('nx', 100, 'ny', 80, 'dx', 4.2);
	end
	ig.mask = ig.circ(200) > 0;
	kappa = 2 + 1 * cos(2*pi*ig.x/ig.fov) * sin(2*pi*ig.y/ig.fov)';
	kappa = single(kappa) .* ig.mask;
%	kappa = repmat(kappa, [1 1 ig.nz]) .* ig.mask;
%	kappa = ig.mask;

	f.l2b = 3;
%	f.l2b = 0;
	f.pot = 'hyper3'; f.delta = 30; f.pot_arg = {f.pot, f.delta};
%	f.pot = 'quad'; f.delta = inf; f.pot_arg = {f.pot};
	f.offsets = '3d:26';
	f.offsets = [ig.nx+1];
	f.offsets = '';
	Rg = Reg1(kappa, 'pot_arg', f.pot_arg, 'beta', 2^f.l2b, ...
		'offsets', f.offsets, 'type_penal', 'mat');
%		'offsets', f.offsets, 'type_penal', 'mex');
%		'edge_type', 'tight', ...
	Rm = Rmem(kappa, 'pot_arg', f.pot_arg, 'beta', 2^f.l2b, ...
		'distance_power', Rg.distance_power, ...
		'offsets', f.offsets);
%		'edge_type', 'tight', ...

	x = ig.unitv;

	if 1 % check C1
		jf_equal(Rm.C1 * x, Rg.C1 * x)
		jf_equal(Rm.C1 * x(ig.mask), Rg.C1 * x(ig.mask))
	end

	if 1 % check penalty value
		jf_equal(Rg.penal(Rg, x), Rg.penal(Rg, x(ig.mask)))
		jf_equal(Rm.penal(Rm, x), Rm.penal(Rm, x(ig.mask)))
		equivs(Rg.penal(Rg, x), Rm.penal(Rm, x))
	end

	if 1 % check cgrad
		g1 = Rm.cgrad(Rm, x);
		g2 = ig.embed(Rm.cgrad(Rm, x(ig.mask)));
		jf_equal(g1, g2)
		g2 = Rg.cgrad(Rg, x);
im pl 2 2, im(1, g1), im(2, g2), im(3, g1-g2), im(4, ig.mask)
		equivs(g1, g2)
		g3 = ig.embed(Rg.cgrad(Rg, x(ig.mask)));
		jf_equal(g2, g3)
		clear g1 g2 g3
	end

	if 0 % check denom
	return
	end

	%d = Rm.diag(R);
prompt
end

% Robject designed to match Rmem'
if 1 | ~isvar('Ro'), printm 'Ro'
	tmp = repmat(kappa.^2, [1 1 1 length(Rm.offsets)]);
	Ro = Robject(ig.mask, 'edge_type', 'leak', 'beta', 2^f.l2b, ...
		'offsets', Rm.offsets, ...
		'potential', f.pot, 'delta', f.delta, ...
		'type_denom', 'matlab', ...
		'distance_power', Rg.distance_power, 'user_wt', tmp);
	clear tmp
end

if 1
	cpu etic
	g1 = Rm.cgrad(Rm, x);
	cpu etoc 'Rm cgrad time'
	cpu etic
	g2 = Ro.cgrad(Ro, x(ig.mask));
	g2 = embed(g2, ig.mask);
	cpu etoc 'Ro cgrad time'
	equivs(g1, g2)
end

if 0 % these tests superceded by Reg1_test.m
	tmp = sprintf('cgrad%d,offset', Rm.order);
	beta = 2^f.l2b ...
		./ penalty_distance(Rm.offsets(:), Rm.dim) .^ Rm.distance_power;
	g31 = penalty_mex(tmp, single(x), single(kappa), ...
		int32(Rm.offsets), single(beta), ...
		Rm.pot_arg{1}{1}, single(Rm.pot_arg{1}{2}), int32(1));
	g34 = penalty_mex(tmp, single(x), single(kappa), ...
		int32(Rm.offsets), single(beta), ...
		Rm.pot_arg{1}{1}, single(Rm.pot_arg{1}{2}), int32(4));
	jf_equal(g31, g34)
	max_percent_diff(g1, g31)
	max_percent_diff(g2, g31)
end

if 1
	% compare them
	%x = ig.unitv;
	pr Rm.penal(Rm, x)
	pr Ro.penal(Ro, x(ig.mask))
	max_percent_diff 'Rm.penal(Rm,x)' 'Ro.penal(Ro,x(ig.mask))'
end

return %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

x = mask;
rng(0)
x = rand(size(mask));
x = x(mask);
max_percent_diff(R0.penal(R0, x), R1.penal(R1, x))
max_percent_diff(R0.diag(R0), R1.diag(R1))
max_percent_diff(R0.cgrad(R0, x), R1.cgrad(R1, x))
max_percent_diff(R0.denom(R0, x), R1.denom(R1, x))
if 0
	d0 = R0.denom(R0, x);
	d1 = R1.denom(R1, x);
	d0 = embed(d0, mask);
	d1 = embed(d1, mask);
	im clf
	im(221, d0)
	im(222, d1)
	im(223, d1-d0)
end


function Archive = UpdateArchive(Archive,Population,popsize)
% Update the archive in MSOPS-II

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

    %% Combine the archive with the population
    Archive = [Archive,Population];
    ArchObj = Archive.objs;
    N       = length(Archive);

    %% Update the archive by weighted min-max metric
    % Calculate the weighted min-max metric between each two solutions
    WMM = CalMetric(ArchObj,ArchObj);
    WMM_diagonal = WMM(logical(eye(N)))';
    % Delete the solutions which do not have the lowest metric value than
    % others according to its own weight vector
    Remain = true(1,N);
    for i = 1 : N
        if Remain(i)
            if WMM(i,i) > min(WMM(Remain,i))
                Remain(i) = false;
            else
                Remain(WMM(i,:)<WMM_diagonal) = false;
            end
        end
    end
    Archive = Archive(Remain);
    % If the archive contains too many solutions, randomly delete some. The
    % original algorithm does not limit the size of archive, so that the
    % size of archive will increase unrestrainedly
    if length(Archive) > 10*popsize
        Archive = Archive(randperm(length(Archive),5*popsize));
    end
end


Network torchvision.models.googlenet {
Layer Conv2d-1 {
Type: CONV
Stride { X: 2, Y: 2 }
Dimensions { K: 64, C: 3, R: 7, S: 7, Y: 224, X: 224 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-2 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 64, C: 64, R: 1, S: 1, Y: 56, X: 56 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-3 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 192, C: 64, R: 3, S: 3, Y: 56, X: 56 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-4 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 64, C: 192, R: 1, S: 1, Y: 28, X: 28 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-5 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 96, C: 192, R: 1, S: 1, Y: 28, X: 28 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-6 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 128, C: 96, R: 3, S: 3, Y: 28, X: 28 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-7 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 16, C: 192, R: 1, S: 1, Y: 28, X: 28 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-8 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 32, C: 16, R: 3, S: 3, Y: 28, X: 28 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-9 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 32, C: 192, R: 1, S: 1, Y: 28, X: 28 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-10 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 128, C: 256, R: 1, S: 1, Y: 28, X: 28 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-11 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 128, C: 256, R: 1, S: 1, Y: 28, X: 28 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-12 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 192, C: 128, R: 3, S: 3, Y: 28, X: 28 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-13 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 32, C: 256, R: 1, S: 1, Y: 28, X: 28 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-14 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 96, C: 32, R: 3, S: 3, Y: 28, X: 28 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-15 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 64, C: 256, R: 1, S: 1, Y: 28, X: 28 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-16 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 192, C: 480, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-17 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 96, C: 480, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-18 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 208, C: 96, R: 3, S: 3, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-19 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 16, C: 480, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-20 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 48, C: 16, R: 3, S: 3, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-21 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 64, C: 480, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-22 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 128, C: 512, R: 1, S: 1, Y: 4, X: 4 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Linear-23 {
Type: CONV
Dimensions { K: 1024, C: 2048, R: 1, S: 1, Y: 1, X: 1 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Linear-24 {
Type: CONV
Dimensions { K: 1000, C: 1024, R: 1, S: 1, Y: 1, X: 1 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-25 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 160, C: 512, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-26 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 112, C: 512, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-27 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 224, C: 112, R: 3, S: 3, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-28 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 24, C: 512, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-29 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 64, C: 24, R: 3, S: 3, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-30 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 64, C: 512, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-31 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 128, C: 512, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-32 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 128, C: 512, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-33 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 256, C: 128, R: 3, S: 3, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-34 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 24, C: 512, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-35 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 64, C: 24, R: 3, S: 3, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-36 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 64, C: 512, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-37 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 112, C: 512, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-38 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 144, C: 512, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-39 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 288, C: 144, R: 3, S: 3, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-40 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 32, C: 512, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-41 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 64, C: 32, R: 3, S: 3, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-42 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 64, C: 512, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-43 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 128, C: 528, R: 1, S: 1, Y: 4, X: 4 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Linear-44 {
Type: CONV
Dimensions { K: 1024, C: 2048, R: 1, S: 1, Y: 1, X: 1 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Linear-45 {
Type: CONV
Dimensions { K: 1000, C: 1024, R: 1, S: 1, Y: 1, X: 1 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-46 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 256, C: 528, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-47 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 160, C: 528, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-48 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 320, C: 160, R: 3, S: 3, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-49 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 32, C: 528, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-50 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 128, C: 32, R: 3, S: 3, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-51 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 128, C: 528, R: 1, S: 1, Y: 14, X: 14 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-52 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 256, C: 832, R: 1, S: 1, Y: 7, X: 7 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-53 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 160, C: 832, R: 1, S: 1, Y: 7, X: 7 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-54 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 320, C: 160, R: 3, S: 3, Y: 7, X: 7 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-55 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 32, C: 832, R: 1, S: 1, Y: 7, X: 7 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-56 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 128, C: 32, R: 3, S: 3, Y: 7, X: 7 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-57 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 128, C: 832, R: 1, S: 1, Y: 7, X: 7 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-58 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 384, C: 832, R: 1, S: 1, Y: 7, X: 7 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-59 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 192, C: 832, R: 1, S: 1, Y: 7, X: 7 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-60 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 384, C: 192, R: 3, S: 3, Y: 7, X: 7 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-61 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 48, C: 832, R: 1, S: 1, Y: 7, X: 7 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-62 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 128, C: 48, R: 3, S: 3, Y: 7, X: 7 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Conv2d-63 {
Type: CONV
Stride { X: 1, Y: 1 }
Dimensions { K: 128, C: 832, R: 1, S: 1, Y: 7, X: 7 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
Layer Linear-64 {
Type: CONV
Dimensions { K: 1000, C: 1024, R: 1, S: 1, Y: 1, X: 1 }
Dataflow {
        SpatialMap(1,1) K;
        TemporalMap(64,64) C;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        Cluster(64, P);
        SpatialMap(1,1) C;
        TemporalMap(Sz(R),1) Y;
        TemporalMap(Sz(S),1) X;
        TemporalMap(Sz(R),Sz(R)) R;
        TemporalMap(Sz(S),Sz(S)) S;
}
}
}


function [g,dgdx,dgdP] = g_ttest(x,P,u,in)

% transformations
%%% normal priors on phi_1
sP = P;
dsPdP = ones(numel(P),1);
%%% sparse laplace priors on phi_2
[sP(2),dsPdP(2)] = VBA_sparsifyPrior (P(2));

% prediction
g = [sP(1) ;
     sP(1) + sP(2) ];

% derivatives
dgdP = diag(dsPdP);
dgdP(1,2) = 1*dsPdP(1);
dgdx = [];

% % prediction
% g = [sP(1) - sP(2)/2;
%      sP(1) + sP(2)/2 ];
%
% % derivatives
% dgdP = zeros(2);
% dgdP(1,1) = dsPdP(1);
% dgdP(2,1) = -(1/2)*dsPdP(2);
% dgdP(1,2) = dsPdP(1);
% dgdP(2,2) = +(1/2)*dsPdP(2);
% dgdx = [];

end


classdef prtClusterSphericalKmeans < prtCluster
    % prtClusterSphericalKmeans Spherical K-Means Clustering with Cosine
    %     Metric
    %
    % sk = prtClusterSphericalKmeans generates a spherical K-means
    %   clustering object based on the algorithm description in [1] below.
    %   Spherical K-means operates under the assumption that the input data
    %   rows have zero-mean and unit standard deviation.  Otherwise the
    %   resulting clusters may not work very well.
    %
    % sk = prtClusterSphericalKmeans(varargin) enables the inclusion of
    %   various parameter/value pairs.
    %
    %
    %  A prtClusterSphericalKmeans object has the following properites:
    %
    %   nClusters - 3 - The number of clusters to learn
    %   nIters - 10 - the number of clustering iterations to use
    %
    %  A prtClusterSphericalKmeans object also inherits all properties
    %   and functions from the prtCluster class
    %
    % [1] Learning Feature Representations with K-means, Adam Coates and
    % Andrew Y. Ng
    %
    % Example usage:
    %    See the entry in ]blogs\torrione_2013.03.15_CoatesNg_Kmeans for
    %    example usage

    properties (SetAccess=private)
        name = 'Spherical K-Means'
        nameAbbreviation = 'SKM'
    end

    properties
        nClusters = 3;
        nIters = 10;
    end

    properties (SetAccess = protected)
        clusterCenters = [];   % The cluster centers
    end

    methods

        function self = set.nClusters(self,value)
            if ~prtUtilIsPositiveScalarInteger(value)
                error('prt:prtClusterKmeans:nClusters','value (%s) must be a positive scalar integer',mat2str(value));
            end
            self.nClusters = value;
        end

        function self = prtClusterSphericalKmeans(varargin)
            % Allow for string, value pairs
            self = prtUtilAssignStringValuePairs(self,varargin{:});
        end
    end

    methods (Access=protected, Hidden = true)

        function self = trainAction(self,dataSet)

            X = dataSet.X;
            d1 = dataSet.bootstrap(self.nClusters); %random inits
            clusters = d1.X';

            clusters = bsxfun(@rdivide,clusters,sqrt(sum(clusters.^2,1)));
            clusters(isnan(clusters)) = 0;

            inner = X*clusters;
            [val,indJ] = max(inner,[],2);

            matInd = sub2ind(size(inner),(1:length(indJ))',indJ);
            boolMat = false(size(inner));
            boolMat(matInd) = true;
            inner(~boolMat) = 0;

            for i = 1:self.nIters
                clusters = clusters + X'*inner;

                clusters = bsxfun(@rdivide,clusters,sqrt(sum(clusters.^2,1)));
                clusters(isnan(clusters)) = 0;

                inner = X*clusters;
                [val,indJ] = max(inner,[],2);
                matInd = sub2ind(size(inner),(1:length(indJ))',indJ);
                boolMat = false(size(inner));
                boolMat(matInd) = true;
                inner(~boolMat) = 0;
            end
            self.clusterCenters = clusters;
        end

        function dataSet = runAction(self,dataSet)

            X = dataSet.X;
            inner = X*self.clusterCenters;
            dataSet.X = inner;
            %             [val,indJ] = max(inner,[],2);
            %             matInd = sub2ind(size(inner),(1:length(indJ))',indJ);
            %             boolMat = false(size(inner));
            %             boolMat(matInd) = true;
            %
            %             dataSet.X = double(boolMat);

        end
    end
end


function MOV = PQavgMOVB (MOVC, Nchan, Nwup)
% Time average MOV precursors

% P. Kabal $Revision: 1.1 $  $Date: 2003/12/07 13:34:46 $

Fs = 48000;
NF = 2048;
Nadv = NF / 2;
Fss = Fs / Nadv;
tdel = 0.5;
tex = 0.050;

% BandwidthRefB, BandwidthTestB
[MOV(0+1), MOV(1+1)] = PQ_avgBW (MOVC.BW);

% Total NMRB, RelDistFramesB
[MOV(2+1), MOV(10+1)] = PQ_avgNMRB (MOVC.NMR);

% WinModDiff1B, AvgModDiff1B, AvgModDiff2B
N500ms = ceil (tdel * Fss);
Ndel = max (0, N500ms - Nwup);
[MOV(3+1), MOV(6+1), MOV(7+1)] = PQ_avgModDiffB (Ndel, MOVC.MDiff);

% RmsNoiseLoudB
N50ms = ceil (tex * Fss);
Nloud = PQloudTest (MOVC.Loud);
Ndel = max (Nloud + N50ms, Ndel);
MOV(8+1) = PQ_avgNLoudB (Ndel, MOVC.NLoud);

% ADBB, MFPDB
[MOV(4+1), MOV(9+1)] = PQ_avgPD (MOVC.PD);

% EHSB
MOV(5+1) = PQ_avgEHS (MOVC.EHS);

%-----------------------------------------
function EHSB = PQ_avgEHS (EHS)

[Nchan, Np] = size (EHS.EHS);

s = 0;
for (j = 0:Nchan-1)
    s = s + PQ_LinPosAvg (EHS.EHS(j+1,:));
end
EHSB = 1000 * s / Nchan;

%-----------------------------------------
function [ADBB, MFPDB] = PQ_avgPD (PD)

global PQopt

c0 = 0.9;
if (isempty (PQopt))
    c1 = 1;
else
    c1 = PQopt.PDfactor;
end

N = length (PD.Pc);
Phc = 0;
Pcmax = 0;
Qsum = 0;
nd = 0;
for (i = 0:N-1)
    Phc = c0 * Phc + (1 - c0) * PD.Pc(i+1);
    Pcmax = max (Pcmax * c1, Phc);

    if (PD.Pc(i+1) > 0.5)
        nd = nd + 1;
        Qsum = Qsum + PD.Qc(i+1);
    end
end

if (nd == 0)
    ADBB = 0;
elseif (Qsum > 0)
    ADBB = log10 (Qsum / nd);
else
    ADBB = -0.5;
end

MFPDB = Pcmax;

%-----------------------------------------
function [TotalNMRB, RelDistFramesB] = PQ_avgNMRB (NMR)

[Nchan, Np] = size (NMR.NMRavg);
Thr = 10^(1.5 / 10);

s = 0;
for (j = 0:Nchan-1)
    s = s + 10 * log10 (PQ_LinAvg (NMR.NMRavg(j+1,:)));
end
TotalNMRB = s / Nchan;

s = 0;
for (j = 0:Nchan-1)
    s = s + PQ_FractThr (Thr, NMR.NMRmax(j+1,:));
end
RelDistFramesB = s / Nchan;

%-----------------------------------------
function [BandwidthRefB, BandwidthTestB] = PQ_avgBW (BW)

[Nchan, Np] = size (BW.BWRef);

sR = 0;
sT = 0;
for (j = 0:Nchan-1)
    sR = sR + PQ_LinPosAvg (BW.BWRef(j+1,:));
    sT = sT + PQ_LinPosAvg (BW.BWTest(j+1,:));
end
BandwidthRefB  = sR / Nchan;
BandwidthTestB = sT / Nchan;

%-----------------------------------------
function [WinModDiff1B, AvgModDiff1B, AvgModDiff2B] = PQ_avgModDiffB (Ndel, MDiff)

NF = 2048;
Nadv = NF / 2;
Fs = 48000;

Fss = Fs / Nadv;
tavg = 0.1;

[Nchan, Np] = size (MDiff.Mt1B);

% Sliding window average - delayed average
L = floor (tavg * Fss);     % 100 ms sliding window length
s = 0;
for (j = 0:Nchan-1)
    s = s + PQ_WinAvg (L, MDiff.Mt1B(j+1,Ndel+1:Np-1+1));
end
WinModDiff1B = s / Nchan;

% Weighted linear average - delayed average
s = 0;
for (j = 0:Nchan-1)
    s = s + PQ_WtAvg (MDiff.Mt1B(j+1,Ndel+1:Np-1+1), MDiff.Wt(j+1,Ndel+1:Np-1+1));
end
AvgModDiff1B = s / Nchan;

% Weighted linear average - delayed average
s = 0;
for (j = 0:Nchan-1)
    s = s + PQ_WtAvg (MDiff.Mt2B(j+1,Ndel+1:Np-1+1), MDiff.Wt(j+1,Ndel+1:Np-1+1));
end
AvgModDiff2B = s / Nchan;

%-----------------------------------------
function RmsNoiseLoudB = PQ_avgNLoudB (Ndel, NLoud)

[Nchan, Np] = size (NLoud.NL);

% RMS average - delayed average and loudness threshold
s = 0;
for (j = 0:Nchan-1)
    s = s + PQ_RMSAvg (NLoud.NL(j+1,Ndel+1:Np-1+1));
end
RmsNoiseLoudB = s / Nchan;

%-----------------------------------
% Average values values, omitting values which are negative
function s = PQ_LinPosAvg (x)

N = length(x);

Nv = 0;
s = 0;
for (i = 0:N-1)
    if (x(i+1) >= 0)
        s = s + x(i+1);
        Nv = Nv + 1;
    end
end

if (Nv > 0)
    s = s / Nv;
end

%----------
% Fraction of values above a threshold
function Fd = PQ_FractThr (Thr, x)

N = length (x);

Nv = 0;
for (i = 0:N-1)
    if (x(i+1) > Thr)
        Nv = Nv + 1;
    end
end

if (N > 0)
    Fd = Nv / N;
else
    Fd = 0;
end

%-----------
% Sliding window (L samples) average
function s = PQ_WinAvg (L, x)

N = length (x);

s = 0;
for (i = L-1:N-1)
    t = 0;
    for (m = 0:L-1)
        t = t + sqrt (x(i-m+1));
    end
    s = s + (t / L)^4;
end

if (N >= L)
    s = sqrt (s / (N - L + 1));
end

%----------
% Weighted average
function s = PQ_WtAvg (x, W)

N = length (x);

s = 0;
sW = 0;
for (i = 0:N-1)
    s = s + W(i+1) * x(i+1);
    sW = sW + W(i+1);
end

if (N > 0)
    s = s / sW;
end

%----------
% Linear average
function LinAvg = PQ_LinAvg (x)

N = length (x);
s = 0;
for (i = 0:N-1)
    s = s + x(i+1);
end

LinAvg = s / N;

%----------
% Square root of average of squared values
function RMSAvg = PQ_RMSAvg (x)

N = length (x);
s = 0;
for (i = 0:N-1)
    s = s + x(i+1)^2;
end

if (N > 0)
    RMSAvg = sqrt(s / N);
else
    RMSAvg = 0;
end


clear;
t0=0.01;
tf=0.05;
b0=[1.2 2.2 1.8];
[t,b]=ode45('dfun2',[t0, tf],b0);
plot(b(:,1),b(:,2));
hold on

xlabel('x1');
ylabel('x2');


function state = ...
    psoboundssoft(state,Aineq,bineq,Aeq,beq,LB,UB,nonlcon,options)

x = state.Population ;
% v = state.Velocities ;

for i = 1:size(state.Population,1)
    lowindex = [] ; highindex = [] ;
    if ~isempty(LB), lowindex = x(i,:) < LB ; end
    if ~isempty(UB), highindex = x(i,:) > UB ; end

    outofbounds = any([lowindex,highindex]) ;
    if ~outofbounds && ~isempty(Aineq) % Check linear inequalities
        outofbounds = any(Aineq*x(i,:)' - bineq > options.TolCon) ;
    end % if ~isempty
    if ~outofbounds && ~isempty(Aeq) % Check linear equalities
        outofbounds = any(abs(Aeq*x(i,:)' - beq) > options.TolCon) ;
    end % if ~isempty
    if ~outofbounds && ~isempty(nonlcon) % Nonlinear constraint check
        [c,ceq] = nonlcon(x(i,:)) ;
        outofbounds = any(c > options.TolCon) ;
        outofbounds = outofbounds || any(abs(ceq) > options.TolCon) ;
    end

    if outofbounds
        state.Score(i) = inf ;
    end % if outofbounds

    state.OutOfBounds(i) = outofbounds ;
end % for i

state.Population = x ;
% state.Velocities = v ;


function [score,outputs] = evaluate(CPD, fam, data, ns, cnodes)
% Evaluate evaluate the performance of the classification/regression tree on given complete data
% score = evaluate(CPD, fam, data, ns, cnodes)
%
% fam(i) is the node id of the i-th node in the family of nodes, self node is the last one
% data(i,m) is the value of node i in case m (can be cell array).
% ns(i) is the node size for the i-th node in the whold bnet
% cnodes(i) is the node id for the i-th continuous node in the whole bnet
%
% Output
% score is the classification accuracy (for classification)
%          or mean square deviation (for regression)
%            here for every case we use the mean value at the tree leaf node as its predicted value
% outputs(i) is the predicted output value for case i
%
% Author: yimin.zhang@intel.com
% Last updated: Jan. 19, 2002

if iscell(data)
  local_data = cell2num(data(fam,:));
else
  local_data = data(fam, :);
end

%get local node sizes and node types
node_sizes = ns(fam);
node_types = zeros(1,size(ns,2)); %all nodes are disrete
node_types(cnodes)=1;
node_types=node_types(fam);

fam_size=size(fam,2);
output_type = node_types(fam_size);

num_cases=size(local_data,2);
total_error=0;

outputs=zeros(1,num_cases);
for i=1:num_cases
  %class one case using the tree
  cur_node=CPD.tree.root;  % at the root node of the tree
  while (1)
    if (CPD.tree.nodes(cur_node).is_leaf==1)
      if (output_type==0) %output is discrete
        %use the class with max probability as the output
        [maxvalue,class_id]=max(CPD.tree.nodes(cur_node).probs);
        outputs(i)=class_id;
        if (class_id~=local_data(fam_size,i))
          total_error=total_error+1;
        end
      else   %output is continuous
        %use the mean as the value
        outputs(i)=CPD.tree.nodes(cur_node).mean;
        cur_deviation = CPD.tree.nodes(cur_node).mean-local_data(fam_size,i);
        total_error=total_error+cur_deviation*cur_deviation;
      end
      break;
    end
    cur_attr = CPD.tree.nodes(cur_node).split_id;
    attr_val = local_data(cur_attr,i);
    if (node_types(cur_attr)==0)  %discrete attribute
        % goto the attr_val -th child
        cur_node = CPD.tree.nodes(cur_node).children(attr_val);
    else
        if (attr_val <= CPD.tree.nodes(cur_node).split_threshhold)
          cur_node = CPD.tree.nodes(cur_node).children(1);
        else
          cur_node = CPD.tree.nodes(cur_node).children(2);
        end
    end
    if (cur_node > CPD.tree.num_node)
      fprintf('Fatal error: Tree structure corrupted.\n');
      return;
    end
  end
  %update the classification error number
end
if (output_type==0)
  score=1-total_error/num_cases;
else
  score=total_error/num_cases;
end


function [V,F] = cookie_cutter(P,E)
  % COOKIE_CUTTER Generate a cookie cutter model from a curve
  %
  % [V,F,W,G] = cookie_cutter(P,E)
  %
  % Inputs:
  %   P  #P by 2 list of positions (bbd should be ~40)
  %   E  #E by 3 list of edge indices into P
  % Outputs:
  %   V  #V by 3 list of positions of cutter part
  %   F  #F by 3 list of triangle indices on cutter part
  %
  % Example:
  %
  %     clf;
  %     axis([-40 40 -40 40]);axis equal;
  %     P = get_pencil_curve();
  %     E = [1:size(P,1);2:size(P,1) 1]';
  %     [V,F] = cookie_cutter(P,E);
  %     tsurf(F,V);axis equal;
  %
  function [V,O] = robust_overlap(S,E)
    sqr_len = mean(sum((S(E(:,1),:)-S(E(:,2),:)).^2,2));
    max_area = sqr_len/9;
    [V,F] = cdt(S,E,'TriangleFlags',sprintf('-qYY -a%g',max_area),'Quiet',true);
    w = winding_number(S,E,barycenter(V,F));
    F = F(w>0.5,:);
    [V,I] = remove_unreferenced(V,F);
    F = I(F);
    O = outline(F);
    [V,I] = remove_unreferenced(V,O);
    O = I(O);
    [V,~,I] = remove_duplicate_vertices(V,1e-3);
    O = I(O);
    % remove degnerate edges
    O = O(O(:,1) ~= O(:,2),:);
    % remove duplice edges
    [~,I] = unique(sort(O,2),'rows');
    O = O(I,:);
    assert(size(unique(sort(O,2),'rows'),1) == size(O,1));
    [V,F] = triangle(V,O,[],'Flags','-YY','Quiet');
    w = abs(winding_number(V,O,barycenter(V,F)));
    F = F(w>0.5,:);
    O = outline(F);
    [V,I] = remove_unreferenced(V,O);
    O = I(O);
    assert(size(unique(sort(O,2),'rows'),1) == size(O,1));

  end

  % thin wall
  offset = 0.5;
  [SI,SO,EI,EO] = offset_curve(P,offset);
  S = [SI;SO];
  E = [EI;size(SI,1)+EO];
  [S,E] = robust_overlap(S,E);

  % thick wall
  k_offset = 2;
  [KI,KO,KEI,KEO] = offset_curve(P,k_offset);
  K = [KI;KO];
  KE = [KEI;size(KI,1)+KEO];
  [K,KE] = robust_overlap(K,KE);

  % height of cutting wall
  h = 15;
  % height of lip
  th = 3;
  % height of stamper
  sth = 5;
  [CV,CF] = wedding_cake({K,S},{KE,E},[th,h]);

  tol = 0.8;
  [sP,~,sE,~] = offset_curve(P,offset+tol);
  sE = fliplr(sE);
  [sP,sE] = robust_overlap(sP,sE);
  % center
  c = mean(sP);
  % center should be inside
  assert(abs(winding_number(sP,sE,c))>0.5,'Uhoh, center for post fell outside curve. Too non-convex');
  % radius determined by closest point on curve
  r = min(pdist2(K,c));
  r = 0.9*r;
  r = min(r,4);
  theta = linspace(0,2*pi,100)';
  theta = theta(1:end-1);
  hP = bsxfun(@plus,c,r*[cos(theta) sin(theta)]);
  hE = [1:size(hP,1);2:size(hP,1) 1]';
  [SV,SF] = wedding_cake({sP,hP},{sE,hE},[sth,2*h]);

  % concatenate
  F = [CF;size(CV,1)+SF];
  %V = [CV;bsxfun(@plus,[max(CV(:,1))*2 0 0],SV)];
  % Cutter needs to be flipped!
  V = [bsxfun(@times,[-1 1 1],CV);bsxfun(@plus,[abs(max(CV(:,1))-min(CV(:,1)))*1.1 0 0],SV)];
end


function [predict_label, predict_prob] = CNN_SVM_prediction(imdb,OP,retrain_net,nfeatures,data_mean)
%
% predict_label:
%   if OP.class = 1 then: predict_label = 1:Wake, 2:REM sleep, 3:NREM light sleep, 4:NREM deep sleep
%   if OP.class = 2 then: predict_label = 1:NREM sleep (light + deep), 2:REM sleep, 3: wake
%   if OP.class = 3 then: predict_label = 1:NREM deep sleep, 2:NREM light sleep, 3:Wake + REM sleep
%   if OP.class = 4 then: predict_label = 1:NREM sleep (light + deep), 2: Wake + REM sleep

if nargin<5
    data_mean=[];
end

if nargin<4 || isempty(nfeatures)
    nfeatures=13;
end

imdb.meta.features(isinf(imdb.meta.features))=NaN;
sqi=nanmean(imdb.meta.sqi,1);
sqi(find(isnan(sqi)))=nanmean(sqi);

% load model
load(OP.model);

if nargin<3 || isempty(retrain_net)
    net=stat.net;
else
    net=retrain_net;
end

net.layers{1,end}.type='softmax';
mean_features=stat.mean_features;
std_features=stat.std_features;

mean_sqi=stat.mean_sqi;
std_sqi=stat.std_sqi;

model=stat.model;

% standardization
for i=8:nfeatures
    for j=1:size(imdb.meta.features,1)
        imdb.meta.features(j,i)=log(imdb.meta.features(j,i));
    end
end
imdb.meta.features(find(isinf(imdb.meta.features)))=NaN;

% subtract data_mean
if ~isempty(data_mean)
    stat.data_mean=data_mean;
end

for k=1:size(imdb.images.data,4)
    imdb.images.data(:,:,1,k)=imdb.images.data(:,:,1,k)-stat.data_mean;
end

for i=1:nfeatures
    imdb.meta.features(find(isnan(imdb.meta.features(:,i))),i)=mean_features(i);
    imdb.meta.features(:,i)=bsxfun(@minus, imdb.meta.features(:,i),mean_features(i));
    imdb.meta.features(:,i)=bsxfun(@rdivide, imdb.meta.features(:,i),std_features(i));
end
sqi=bsxfun(@minus,sqi,mean_sqi);
sqi=bsxfun(@rdivide,sqi,std_sqi);

% CNN prediction
if size(imdb.images.data,4)>1000
    split=round(size(imdb.images.data,4)/1000);
else
    split=1;
end

retall=[];
for kk=1:split
    each=ceil(size(imdb.images.data,4)/split);
    res=vl_simplenn(net,imdb.images.data(:,:,:,(kk-1)*each+1:min(kk*each,size(imdb.images.data,4))));

    ret=[];
    for i=1:OP.nclass
        for j=1:size(res(end).x,4)
            ret(i,j)=res(end).x(1,1,i,j);
        end
    end
    retall=[retall,ret];
end
% probability of CNN output
ret=retall;

xtest=[];
for i=1:size(ret,1)
    xtest(:,end+1)=ret(i,:);
end
for i=1:nfeatures
    if i~=6 % remove DFA feature
        xtest(:,end+1)=imdb.meta.features(:,i);
    end
end
xtest(:,end+1)=sqi;

% SVM prediction
[predict_label, accuracy_test, predict_prob] = svmpredict(ones(size(xtest,1),1), xtest, model,'-b 1');

[~,si]=sort(model.Label);
predict_prob=predict_prob(:,si);
end


function nuDot = forwardDynamics(tau, JL, JR, M, h, f, LEFT_RIGHT_FOOT_IN_CONTACT)

    % get the robot accelerations using the joint torques, the
    % dynamics model, the robot state and the contact constraints.
    ndof  = size(M,1)-6;
    B     = [zeros(6,ndof); eye(ndof)];

    nuDot = M\(B*tau+LEFT_RIGHT_FOOT_IN_CONTACT(1)*JL'*f(1:6)+LEFT_RIGHT_FOOT_IN_CONTACT(2)*JR'*f(7:end)-h);

end


function [ixZ_vec, endleaves_vec, minBranche] = recursivesubtreePlus(Z, ixZ, ixZ_vec, endleaves_vec, minBranche)
% [ixZ_vec, endleaves_vec] = recursivesubtree(Z, ixZ, ixZ_vec, endleaves_vec)
% recursively finds all subnodes and leaves from the node with index ixZ in
% matrix Z
% initialized as:
% [ixZ_vec, endleaves_vec] = recursivesubtree(Z, ixZ,[],[])
% Z output from 'linkage' function
% ixZ -  index of the node in matrix Z (eg ixZ=(find(Z(:,3)==distance_value)))
% Z = linkage(ccds,'complete');
% [H,T,perm] = dendrogram(Z,0, 'colorthreshold',0.3);
% then subtree of node with ixZ = 50 in dendrogram
% [H,T,perm] = dendrogram(Z,0);
% can be enhanced by eg
% set(H(recursivesubtree(Z,50,[],[])),'LineWidth',2)
ixZ_vec(end+1) = ixZ;
value = Z(ixZ, 1:2) - (length(Z)+1);
if and(value(1)>0, value(1)>0)
    if isempty(minBranche)
        minBranche = ixZ; %to initialize
    end
    if Z(ixZ,3)<Z(minBranche,3)
        minBranche = ixZ;
    end
end
if value(1) > 0
    ixZ = value(1);
    ixZ_vec(end+1) = ixZ;
    [ixZ_vec, endleaves_vec, minBranche ] = recursivesubtreePlus(Z, ixZ, ixZ_vec, endleaves_vec, minBranche );
else
    endleaves_vec(end+1) = Z(ixZ, 1);
end
if value(2) > 0
    ixZ = value(2);
    ixZ_vec(end+1) = ixZ;
    [ixZ_vec, endleaves_vec, minBranche ] = recursivesubtreePlus(Z, ixZ, ixZ_vec, endleaves_vec, minBranche );
else
    endleaves_vec(end+1) = Z(ixZ, 2);
end


function b = PVsubsasgn_2idx(a,L,RHS)
% function B =  PVsubsasgn_2idx(A,L,RHS)
%
% DESCRIPTION
%   (INTERNAL FUNCTION)
%   (:)-subsassign for polynomial objects.
%
% INPUTS
%   A: polynomial
%   L: a 1x1 structure with the fields:
%    type -- string containing '()'
%    subs -- 1x2 cell array containing indices
%   RHS: Value to be assigned.
%
% OUTPUTS
%   B: object after subsassignment
%
% SYNTAX
%   B =  subsasgn(A,L,RHS)

% 6/9/2002: PJS  Initial Coding
% 11/11/2008: PJS Mods to reduce computation
% 1/13/2011: PJS  Fixed bug in sub2ind conversion

% Check Indices
ridx = L(1).subs{1};
lr = length(ridx);
cidx = L(1).subs{2};
lc = length(cidx);
if min(ridx)<1 || min(cidx)<1
    error('Index into matrix is negative or zero.');
end

% Get info about polynomials
b = a;
[nrb,ncb]=size(b);
ntb = size(b.degmat,1);

temp = RHS;
[nrt,nct]=size(temp);
ntt = size(temp.degmat,1);

% Fan out scalar RHS to correct dimension
if all([nrt nct]==[1 1])
    temp.coefficient = repmat(temp.coefficient,1,lr*lc);
    nrt = lr;
    nct = lc;
    temp.matdim = [nrt nct];
end

% Check dimensions
if lr*lc~=nrt*nct
    error(['In an assignment  A(I) = B, the number of' ...
        ' elements in B and I must be the same.']);
end

% Determine proper dimensions for poly after the assignment
nr = max([nrb; ridx(:)]);
nc = max([ncb; cidx(:)]);

% Convert from row/col indices to single index
if isempty(ridx) || isempty(cidx)
    % No substitution
    b = a;
    return;
end
% XXX PJS If ridx and cidx are N-by-1 then the commented code produces
% subsidx of size N-by-1. However, it should be N^2-by-1 (all combos)
% elseif length(cidx)==1
%     cidx = repmat(cidx,length(ridx),1);
% elseif length(ridx)==1
%     ridx = repmat(ridx,length(cidx),1);
% end
% subsidx = sub2ind([nr nc],ridx(:),cidx(:));
tmp = reshape(1:nr*nc,[nr,nc]);
subsidx = tmp(ridx,cidx);
subsidx = subsidx(:);

% Perform the subsassignment
if isempty(b)
    tempcoef = sparse(ntt,nr*nc);
    tempcoef(:,subsidx) = temp.coefficient;
    temp.coefficient = tempcoef;
    temp.matdim = [nr nc];

    b = temp;
else
    % Place coefs of b in proper location, zero out terms of b to be
    % assigned, stack in new terms, and then combine
    coef = sparse(ntb,nr*nc);
    [ii,jj]=ind2sub([nrb ncb],1:(nrb*ncb));
    bidx = sub2ind([nr nc],ii,jj);
    coef(:,bidx) = b.coefficient;

    coef(:,subsidx) = 0;
    coef(end+1:end+ntt,subsidx) = temp.coefficient;

    degmat = blkdiag(b.degmat,temp.degmat);
    varname = [b.varname; temp.varname];
    matdim = [nr nc];
    chkval = 0; % skip validity check
    b = polynomial(coef,degmat,varname,matdim,chkval);
    b = combine(b);
end


function [ywarp,dwarp_dt,dwarp_dtheta,d2warp_dthetadt] = outwarp_negscaledpow(hyp,y,invflag)
%GPLITE_NOISEFUN Noise function for lite Gaussian Process regression.
%   SN2 = GPLITE_NOISEFUN(HYP,X,NOISEFUN) computes the GP noise function
%   NOISEFUN, that is the variance of observation noise evaluated at test
%   points X. HYP is a single column vector of noise function
%   hyperparameters. NOISEFUN is a numeric array whose elements specify
%   features of the noise function, as follows:
%
%   See also GPLITE_COVFUN, GPLITE_MEANFUN.

if nargin < 2; y = []; end
if nargin < 3 || isempty(invflag); invflag = false; else; invflag = true; end

if invflag && nargout > 1
    error('outwarp_fun:InverseOnly', ...
        ['When calling for the inverse output warping function, only one function output is expected.']);
end

%--------------------------------------------------------------------------
% CUSTOM: Number of hyperparameters
Noutwarp = 3;       % # hyperparameters of the output warping function
%--------------------------------------------------------------------------

N = size(y,1);      % Number of training points

% Return number of output warping function hyperparameters and additional info
if ischar(hyp)
    ywarp = Noutwarp;
    if nargout > 1

        % Initialize bounds for all hyperparameters
        outwarp_info.LB = -Inf(1,Noutwarp);
        outwarp_info.UB = Inf(1,Noutwarp);
        outwarp_info.PLB = -Inf(1,Noutwarp);
        outwarp_info.PUB = Inf(1,Noutwarp);
        outwarp_info.x0 = NaN(1,Noutwarp);

        %------------------------------------------------------------------
        % CUSTOM: Initialize hyperparameter bounds and other details

        % Threshold parameter
        outwarp_info.LB(1) = min(y);
        outwarp_info.UB(1) = max(y);
        outwarp_info.PLB(1) = min(y);
        outwarp_info.PUB(1) = max(y);
        outwarp_info.x0(1) = NaN;

        % Scaling parameter a (log space)
        outwarp_info.LB(2) = -Inf;
        outwarp_info.UB(2) = Inf;
        outwarp_info.PLB(2) = -2;
        outwarp_info.PUB(2) = 2;
        outwarp_info.x0(2) = 0;

        % Power exponent k (log space)
        outwarp_info.LB(3) = -Inf;
        outwarp_info.UB(3) = Inf;
        outwarp_info.PLB(3) = -3;
        outwarp_info.PUB(3) = 3;
        outwarp_info.x0(3) = 0;

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

        % Assign handle of current output warping function
        outwarp_info.outwarpfun = str2func(mfilename);

        % Plausible starting point
        idx_nan = isnan(outwarp_info.x0);
        outwarp_info.x0(idx_nan) = 0.5*(outwarp_info.PLB(idx_nan) + outwarp_info.PUB(idx_nan));

        dwarp_dt = outwarp_info;

    end

    return;
end

[Nhyp,Ns] = size(hyp);      % Hyperparameters and samples

if Nhyp ~= Noutwarp
    error('outwarp_fun:WrongLikHyp', ...
        ['Expected ' num2str(Noutwarp) ' output warping function hyperparameters, ' num2str(Nhyp) ' passed instead.']);
end
if Ns > 1
    error('outwarp_fun:nosampling', ...
        'Output warping function output is available only for one-sample hyperparameter inputs.');
end

%--------------------------------------------------------------------------
% CUSTOM: Compute output warping function and gradients

% Read hyperparameters
y0 = hyp(1);
a = exp(hyp(2));
k = exp(hyp(3));

% Compute output warping or inverse warping
ywarp = y;
idx = y < y0;
if invflag      % Inverse output warping
    ywarp(idx) = y0 - ((y0 - y(idx)).^(1/k))/a;
else            % Direct output warping
    adelta = a*(y0 - y(idx));
    adeltak = adelta.^k;
    ywarp(idx) = y0 - adeltak;
end

if nargout > 1
    % First-order derivative of output warping function in output space
    dwarp_dt = ones(size(y));
    adeltakm1 = adelta.^(k-1);

    dwarp_dt(idx) = a*k*adeltakm1;

    if nargout > 2
        % Gradient of output warping function wrt hyperparameters
        dwarp_dtheta = zeros(N,Noutwarp);

        dwarp_dtheta(idx,1) = 1 - a*k*adeltakm1;            % y0
        dwarp_dtheta(idx,2) = -k*adeltak;                   % log(a)
        dwarp_dtheta(idx,3) = -k*adeltak.*log(adelta);      % log(k)

        if nargout > 3
            % Gradient of derivative of output warping function
            d2warp_dthetadt = zeros(N,Noutwarp);

            d2warp_dthetadt(idx,1) = a^2*k*(k-1)*adelta.^(k-2);                % y0
            d2warp_dthetadt(idx,2) = a*k^2*adeltakm1;                           % log(a)
            d2warp_dthetadt(idx,3) = a*k*adeltakm1 + a*k^2*adeltakm1.*log(adelta);  % log(k)

        end

    end
end

end


function [ref_signal, refsig_fs, ref_signal_ds] = ...
    read_signal(sample_name, num_devices)

    global GYRO_FS;
    [ref_signal, refsig_fs] = audioread(['samples/' sample_name '.wav']);
    ref_signal_ds = resample(ref_signal, GYRO_FS * num_devices, refsig_fs);
    ref_signal_ds = normalization(ref_signal_ds);
    display(['Samples in ' sample_name ' (resampled): ' ...
        num2str(length(ref_signal_ds))]);
    figure;
    subplot(121);
    fft_plot(ref_signal_ds, GYRO_FS * num_devices);
    title([sample_name ' FFT']);

end


% NMFLAB for Signal Processing written by A. Cichocki and R. Zdunek
% in cooperation with other members of Laboratory for Advanced Brain Signal
% Processing, BSI, RIKEN, Saitama, JAPAN

function [A,X,Distance_output]=nmf_newton(Y,r,Index_norm,A_true,S, mc_on, NoAlts,restart_mc_on,AL,Y_true,type_alg_A,type_alg_X,max_restart,no_iter,alphaS,alpha,CostFun,lambda,alpha0,tau,niter_selected)
%
% Non-negative Matrix Factorization (NMF) with the quasi-Newton method
%
%
% [A,X]=nmf_newton(Y,r,Index_norm,A_true,S,mc_on,NoAlts,restart_mc_on,AL,Y_true,type_alg_A,type_alg_X,max_restart,no_iter,alphaS,alpha,L_type,lambda,alpha0,tau)
%
%       produces mixing matrix A of dimension [m by r],
%       and source matrix X of dimension [r by T], for the linear mixing model: AX = Y,
%       where Y is an observation matrix [m by T].
% Note: > m: number of sensors,
%       > r: number of sources,
%       > T: number of samples,
%
% INPUTS:
%       > Index_norm:    vector of 13 binary entries indicating which number
%                        divergence measures are turned on in the View Options,
%       > A_true:        true mixing matrix (only for synthetic data),
%       > S:             true source matrix (only for synthetic data),
%       > mc_on:         1 - Monte Carlo analysis enabled, 0 - otherwise,
%       > NoAlts:        number of alternating steps (only for Monte Carlo
%                        analysis and the option "Fixed Alternatings" is selected)
%       > restart_mc_on: 1 - restarts in Monte Carlo analysis are enabled,
%                        0 - otherwise,
%       > AL:            mixing matrix estimaed from the preceeding layer,
%       > Y_true:        the first layer mixed signals (mixtures),
%       > type_alg_A:    indicates the selected algorithm for computation
%                        of the mixing matrix,
%       > type_alg_X:    indicates the selected algorithm for computation of the sources,
%       > no_iter:       number of inner iterations,
%       > alphaS:        parameter of non-linear projection in computation
%                        of the sources,
%       > alpha:         parameter "alpha" in the alpha-divergence,
%       > CostFun        cost function: (1) - Euclidean,
%                                       (2) - alpha-divergence
%       > lambda         Tikhonov regularization parameter in QP-NMF
%       > alpha0:        initial magnitude in the exponential model for regularization parameter,
%       > tau:           damping factor in the exponential model for regularization parameter,
%
% OUTPUTS:
%       > A:               estimated mixing matrix,
%       > X:               estimated source matrix,
%       > Distance_output: structures of different divergences measured between "Y" and estimated "AX" versus iterations,
%
% #########################################################################
A = [];
X = [];
if (nargin < 21) | isempty(niter_selected) | max(size(niter_selected) > 1)
   disp('Default number of alternating steps');
   niter_selected = 1000;
end
if (nargin < 20) | isempty(tau) | max(size(tau) > 1)
   disp('Incorrect the damping factor in the exponential model');
   return
end
if (nargin < 19) | isempty(alpha0) | max(size(alpha0) > 1)
   disp('Incorrect the initial magnitude in the exponential model');
   return
end
if (nargin < 18) | isempty(lambda) | max(size(lambda) > 1)
   disp('Incorrect regularization parameter');
   return
end
if (nargin < 17) | isempty(CostFun) | (CostFun < 1) | max(size(CostFun) > 1)
   disp('Incorrect cost function');
   return
end
if (nargin < 16) | isempty(alpha) | max(size(alpha) > 1)
   disp('Incorrect parameter alpha in alpha-divergence');
   return
end
if (nargin < 15) | isempty(alphaS) | max(size(alphaS) > 1)
   disp('Incorrect parameter alphaS');
   return
end
if (nargin < 14) | isempty(no_iter)  | (no_iter < 0) | max(size(no_iter) > 1)
   disp('Incorrect number of inner iterations');
   return
end
if (nargin < 13) | isempty(max_restart)  | (max_restart < 0) | max(size(max_restart) > 1)
   disp('Number of restarts must be given correctly');
   return
end
if (nargin < 12) | isempty(type_alg_X) | (type_alg_X < 1) | max(size(type_alg_X) > 1)
   disp('Incorrect algorithm for X');
   return
end
if (nargin < 11) | isempty(type_alg_A) | (type_alg_A < 1) | max(size(type_alg_A) > 1)
   disp('Incorrect algorithm for A');
   return
end
if (nargin < 10) | isempty(Y_true)
   disp('The first layer mixed signals are unknown');
   Y_true = zeros(size(Y_true));
end
if (nargin < 9) | isempty(AL)
   disp('Mixing matrix from the preceeding layer unknown');
   AL = eye(size(Y,1));
end
if (nargin < 8) | isempty(restart_mc_on) | max(size(restart_mc_on) > 1)
   disp('Index od restarts in MC analysis unknown');
   restart_mc_on = 0;
end
if (nargin < 7) | isempty(NoAlts) | max(size(NoAlts) > 1)
   disp('Adjustable number of alternatings');
   NoAlts = [];
end
if (nargin < 6) | isempty(mc_on) | max(size(mc_on) > 1)
   disp('No Monte Carlo Analysis');
   mc_on = 0;
end
if (nargin < 5) | isempty(S)
   disp('X_true not given');
end
if (nargin < 4) | isempty(A_true)
   disp('A_true not given');
   index_fixed_A = 1;
else
   index_fixed_A = 0;
end
if (nargin < 3) | isempty(Index_norm)
   '"Index_norm" must be specified'
   return
end
if (nargin < 2) | isempty(r)
   'Rank of factorization must be given'
   return
end
if isempty(Y) | isnan(Y)
   error('No data');
   return
end
% test for negative values in Y
if min(min(Y)) < 0
    disp('Some matrix entries are changed from negative to small positive');
    Y(Y< 0) = eps;
end
if min(sum(Y,2)) == 0
    disp('Not all entries in a row can be zero');
    return
end

Y = Y + eps;

[m,T]=size(Y);
%niter_selected = 1000;     % maximum number of iterations for the selected sample (can be adjusted)
niter_sample = 10; % maximum number of iterations for each random sample
epsil_normA = 1E-8; % tolerance for alternating

if (alpha == 0) & (type_alg_A == 6)
   type_alg_A = 5;
end

if (type_alg_A == 8) & (size(A_true,1) ~= size(Y,1))
   disp('Multilayer technique cannot be used with A fixed');
   Distance_output = [];
   return
end

% Monte Carlo and alternatings adjustment
if mc_on & ~restart_mc_on
    max_restart = 0;
end
if ~isempty(NoAlts)
    niter_selected = NoAlts;
end

% Parameters for QP-NMF
rho = 1E-3;
eta = 1E-4;
epsil_A = 1E-6;

% Declaration for A and X
A=zeros(m,r);
Ap = A;
X=zeros(r,T);
Ainit = A;
Xinit = X;
Z = zeros(m,T);
KL_outer_temp = 0;
Z_outer_temp = 0;
nr = 0; restart_on = 0; norm_A = 10; nr_best = -1;
m_sx = 1:m; r_sx = 1:r; T_sx = 1:T;
s_dist = 0;

% Newton
HX = spalloc(r*T,r*T,T*r^2);
HA = spalloc(m*r,m*r,m*r^2);
E = ones(m,T);
I = eye(r);
Zx = zeros(m,T);
alpha_h_init = 1E-13;

while (nr <= max_restart)

   % Initialize random A and X
       if ~nr & (~mc_on | restart_mc_on)
          Ainit(m_sx',r_sx) = abs(repmat(.1*sin(2*pi*.1*m_sx'),1,r) + repmat(.1*cos(2*pi*.1*r_sx),m,1) + repmat(cos(2*pi*.471*m_sx'),1,r) + repmat(sin(2*pi*.471*r_sx),m,1));
          Ainit = Ainit/max(max(Ainit));

          Xinit(r_sx',T_sx) = abs(repmat(.1*sin(2*pi*.1*r_sx'),1,T) + repmat(.1*cos(2*pi*.1*T_sx),r,1) + repmat(cos(2*pi*.471*r_sx'),1,T) + repmat(sin(2*pi*.471*T_sx),r,1));
          Xinit = Xinit/max(max(Xinit));
       else
          Ainit=rand(m,r);
          Xinit=rand(r,T);
       end

        % Normalization of initial guess
        Ainit = Ainit*diag(1./sum(Ainit,1));

        if (nr == max_restart)&(max_restart > 0)
           A = A_best;
           X = X_best;
        else
           A = Ainit;
           X = Xinit;
        end % initial guess assignment

    Yx = zeros(m,T);
    n = 0; k = 0;

while ((k <= niter_sample)&(nr < max_restart)) | ((k <= niter_selected)&(nr == max_restart)&(norm_A > epsil_normA)& isempty(NoAlts)) | ((k <= niter_selected)&(nr == max_restart)& (NoAlts > 0))

k = k + 1;

    switch type_alg_X

        case 1 % ALS

            X = max(1E6*eps,pinv(A'*A)*A'*Y);

        case 2 % HALS

                 for j = 1:r
                     Ys = Y - A*X + A(:,j)*X(j,:);
                     X(j,:) = max(1E6*eps,(A(:,j)'*Ys)/(A(:,j)'*A(:,j)));
                 end

        case 3 % Regularized ALS

            alpha_reg = alpha0*exp(-k/tau);
            if isnan(A)  disp('Matrix A is too much ill-conditioned. Try again.'); break; end
            if cond(A) > 1E6 alphaX = 1E-6; else alphaX = 0; end
            X = max(1E6*eps,pinv(A'*A + alpha_reg + alphaX*I)*A'*Y); %Updating of X

        case 4 % GPCG

            X = gpcg_nmf(Y,A,X,no_iter,CostFun,alpha);

        case 5 % Kullback-Leibler (EMML)

             for t = 1:no_iter
                 X = (X.*(A'*(Y./(A*X + eps)))).^(1 + alphaS);
             end
             X = X + 100*eps;

        case 6 % Frobenius (ISRA)

             for t = 1:no_iter
                 X = X.*((A'*Y)./(A'*A*X + eps));
             end
             X = X + 100*eps;

        case 7 % Newton applied to Frobenius

            hX = A'*A;
            GX = A'*Y - hX*X;
            HX = kron(speye(T),-hX); % Hessian
            hk = 0;
            alpha_h = alpha_h_init;
            while condest(HX) > 1E7
                  hk = hk + 1;
                  alpha_h = 10*alpha_h;
                  HX = HX + alpha_h*speye(r*T);
            end
            [QX,RX] = qr(HX,GX(:));
            X(:) = X(:) - .9*RX\QX;
            X(X <= 0) = 100*eps;

        case 8  % Newton applied to KL

            Zx = A*X+1E5*eps;
            GX = A'*(E - Y./Zx);
            Zxx = (Y+100*eps)./Zx.^2;
            for t = 1:T
                HX(((t-1)*r+1):t*r,((t-1)*r+1):t*r) = A'*diag(Zxx(:,t))*A;
            end
            hk = 0;
            alpha_h = alpha_h_init;
            while condest(HX) > 1E7
                  hk = hk + 1;
                  alpha_h = 10*alpha_h;
                  HX = HX + alpha_h*speye(r*T);
            end
            [QX,RX] = qr(HX,GX(:));
            X(:) = X(:) + .9*RX\QX;
            X(X <= 0) = 100*eps;

        case 9 % Newton applied to dual KL (KL2)

            Zx = A*X+10*eps;
            Zxx = 1./Zx + eps;
            GX = A'*log(Zx./(Y + 10*eps));
            for t = 1:T
                HX(((t-1)*r+1):t*r,((t-1)*r+1):t*r) = A'*diag(Zxx(:,t))*A;
            end
            hk = 0;
            alpha_h = alpha_h_init;
            while condest(HX) > 1E7
                  hk = hk + 1;
                  alpha_h = 10*alpha_h;
                  HX = HX + alpha_h*speye(r*T);
            end
            [QX,RX] = qr(HX,GX(:));
            X(:) = X(:) - .9*RX\QX;
            X(X <= 0) = 100*eps;

        case 10 % QP with barrier function

            X = iptrnr(Y',A',no_iter,lambda,rho,eta,epsil_A);
            X = X';

        case 11 % Fixed X

            X = S + eps;
            niter_selected = 1000;     % maximum number of iterations for the selected sample (can be adjusted)

    end % switch for X

    switch type_alg_A

        case 1 % QP with barrier function

            Ap = A;
            A = iptrnr(Y,X,no_iter,lambda,rho,eta,epsil_A);
            A = A*diag(1./(sum(A,1)+eps));

        case 2 % GPCG

            Ap = A;
            A = gpcg_nmf(Y',X',A',no_iter,CostFun,alpha);
            A = A';

        case 3 % Newton applied to Frobenius

            Ap = A;
            hA = X*X';
            hA = hA + (1E-12 + 1E8*exp(-k))*eye(r);  % Levenberg-Marquardt regularization
            GA = A*hA - Y*X';  % Gradient
            A = A - .9*GA*pinv(hA);
            A(A <= 0) = 1E2*eps;
            A = A*diag(1./sum(A,1));

        case 4 % Newton applied to KL

            Ap = A;
            Zx = A*X+100*eps;
            Zxx = (Y+eps)./Zx.^2;
            for i = 1:m
                HA(((i-1)*r+1):i*r,((i-1)*r+1):i*r) = (X.*repmat(Zxx(i,:),r,1))*X'; % Hessian
            end
            HA = HA + (1E-12 + 1E15*exp(-2*k))*speye(m*r);
            GA = X*(1 - (Y+eps)./Zx)'; % Gradient
        %    [QA,R] = qr(HA,GA(:)); % Q-less QR factorization
            cond_HA = condest(HA);
            if isinf(cond_HA)
               fprintf(1,'Hessian is singular in %d iteration(s). Restart is needed.\n',k)
               break;
            end
            A = A';
            A(:) = A(:) - .9*inv(HA)*GA(:);
          %  A(:) = A(:) - .9*R\QA;
            A(A < 0) = 100*eps;
            A = A';
            A = A*diag(1./sum(A,1));

        case 5 % Newton applied to dual KL (KL2)

            Zx = A*X+100*eps; Zxx = 1./Zx;
            GA = X*(log(Zx./(Y+eps)))'; % Gradient
            for i = 1:m
                HA(((i-1)*r+1):i*r,((i-1)*r+1):i*r)...
                = (X.*repmat(Zxx(i,:),r,1))*X';  % Hessian
            end
            HA = HA + (1E-12 + 1E15*exp(-2*k))*speye(m*r);
           %    [QA,R] = qr(HA,GA(:)); % Q-less QR factorization
            cond_HA = condest(HA);
            if isinf(cond_HA)
               fprintf(1,'Hessian is singular in %d iteration(s). Restart is needed.\n',k)
               break;
            end
            A = A';
            A(:) = A(:) - .9*inv(HA)*GA(:);
          %  A(:) = A(:) - .9*R\QA;
            A(A < 0) = 100*eps;
            A = A';
            A = A*diag(1./sum(A,1));

        case 6 % Newton applied to alpha-divergence

            Ap = A;
            Zx = A*X+100*eps;
            Zxx = ((Y+eps).^alpha)./(Zx.^(alpha + 1));
            for i = 1:m
                HA(((i-1)*r+1):i*r,((i-1)*r+1):i*r) =...
                    (X.*repmat(Zxx(i,:),r,1))*X'; % Hessian
            end
            GA = (1/alpha)*X*(1 - ((Y+eps)./Zx).^alpha)'; % Gradient
            HA = HA + (1E-12 + 1E15*exp(-2*k))*speye(m*r);
       %    [QA,R] = qr(HA,GA(:)); % Q-less QR factorization
            cond_HA = condest(HA);
            if isinf(cond_HA)
               fprintf(1,'Hessian is singular in %d iteration(s). Restart is needed.\n',k)
               break;
            end
            A = A';
            A(:) = A(:) - .9*inv(HA)*GA(:);
         %  A(:) = A(:) - .9*R\QA;
            A(A < 0) = 100*eps;
            A = A';
            A = A*diag(1./sum(A,1));

        case 7 % Regularized ALS

            Ap = A;
            alpha_reg = alpha0*exp(-k/tau);
            A = max(1E6*eps, Y*X'*pinv(X*X' + alpha_reg));
            A = A*diag(1./sum(A,1));

        case 8 % Fixed A

            niter_selected = 1000;     % maximum number of iterations for the selected sample (can be adjusted)
            A = A_true + eps;
            A = A*diag(1./(sum(A,1) + eps));

    end % switch for A

                if (nr == max_restart)&(mod(k,50)==0)& (~mc_on | restart_mc_on)
                    norm_A = norm(abs(A - Ap),'fro');
                    fprintf(1, 'Restart %d,  %d-th alternating step\n',nr_best+1,k);
                end

                if sum(Index_norm)
                   if (nr == max_restart) & (((k < 50) & (mod(k,5)==0)) | ((k>49) & ((mod(k,50)==0))))

                       s_dist = s_dist + 1;
                       k_select(s_dist) = k;
                       Z = A*X + eps;
                       Z = diag(1./sqrt(var(Z')))*Z;

                        dist_Fro(s_dist) = norm(Y - Z,'fro');
                        dist_KL(s_dist) = sum(sum(Y.*log(Y./Z + eps) - Y + Z));
                        dist_KL2(s_dist) = sum(sum(Z.*log(Z./Y + eps) + Y - Z));
                        dist_Pearson(s_dist) = sum(sum( ((Y - Z).^2)./Z ));
                        dist_Hellinger(s_dist) = sum(sum( (sqrt(Z) - sqrt(Y)).^2 ));
                        dist_JS_rel(s_dist) = sum(sum(2*Y.*log(2*Y./(Y + Z) + eps) + Z - Y));
                        dist_JS_rel2(s_dist) = sum(sum(2*Z.*log(2*Z./(Y + Z) + eps) - Z + Y));
                        Zy = Y + Z;
                        dist_JS(s_dist) = sum(sum(Y.*log(2*Y./Zy + eps) + Z.*log(2*Z./Zy + eps) ));
                        dist_AG_rel(s_dist) = sum(sum(Zy.*log(.5*Zy./Y + eps) + Y - Z));
                        dist_AG(s_dist) = sum(sum(.5*Zy.*log(.5*Zy./sqrt(Y.*Z) + eps)));
                        dist_J(s_dist) = sum(sum( .5*(Y - Z).*log(Y./Z + eps) ));
                        dist_Chi(s_dist) = sum(sum( ((Y + Z).*(Y - Z).^2)./(Y.*Z) ));
                        dist_Tria(s_dist) = sum(sum( ((Y - Z).^2)./(Y + Z) ));
                    end % if multiple
                end % if sum

end % while (k)

% Outer KL divergence
Z = AL*A*X;
Z_outer = norm(Z,'fro') + eps;
KL_outer = sum(sum(Y_true.*log((Y_true + eps)./(Z + eps)) - Y_true + Z))/Z_outer;

           if (nr == 0) | (KL_outer < KL_outer_temp)
              A_best = A; X_best = X; KL_outer_temp = KL_outer; nr_best = nr;
           end % multi-conditions

   nr = nr + 1;

   if nr <=max_restart
      fprintf(1, 'Restart %d, Kullback-Leibler divergence = %e\n',	nr, KL_outer);
   end

end % while (restarts)

% One-Variance scaling
X(X <= 0) = eps;

Distance_output = cell(length(s_dist),1);
Distance_output(1) = {[]};
Distance_output(2) = {[]};
Distance_output(3) = {[]};
Distance_output(4) = {[]};
Distance_output(5) = {[]};
Distance_output(6) = {[]};
Distance_output(7) = {[]};
Distance_output(8) = {[]};
Distance_output(9) = {[]};
Distance_output(10) = {[]};
Distance_output(11) = {[]};
Distance_output(12) = {[]};
Distance_output(13) = {[]};
Distance_output(14) = {[]};

if sum(Index_norm)
   Distance_output(1) = {k_select};
   Distance_output(2) = {dist_Fro};
   Distance_output(3) = {dist_KL};
   Distance_output(4) = {dist_KL2};
   Distance_output(5) = {dist_Pearson};
   Distance_output(6) = {dist_Hellinger};
   Distance_output(7) = {dist_JS_rel};
   Distance_output(8) = {dist_JS_rel2};
   Distance_output(9) = {dist_JS};
   Distance_output(10) = {dist_AG_rel};
   Distance_output(11) = {dist_AG};
   Distance_output(12) = {dist_J};
   Distance_output(13) = {dist_Chi};
   Distance_output(14) = {dist_Tria};
end


% this script is a brief tutorial for mapping the firing rates of neurons
% onto the behavioral positions occupied by an animal
%
% This script assumes that you are currently in the
% /buzcode/tutorials/exampleDataStructs/20170505_396um_0um_merge folder,
% it will not work otherwise!

path = strsplit(pwd,filesep);
if ~strcmp(path{end},'tutorials') & ~strcmp(path{end-1},'buzcode')
   error('this script assumes you are running it from the /buzcode/tutorials folder...')
end
cd(['exampleDataStructs' filesep '20170505_396um_0um_merge'])

%% loading data
sessionInfo = bz_getSessionInfo;
lfpChan = sessionInfo.ca1;
spikes = bz_GetSpikes('noprompts',true);
try
    lfp = bz_GetLFP(lfpChan);
catch
    error('couldnt load LFP, have you run the "download_DATA" script yet?')
end

behavior = bz_LoadBehavior(pwd,'track');
% what does the behavior look like?
subplot(3,2,1)
bz_plotTrials(behavior,'condition',1)

%% mapping spiking onto behavior
[firingMaps] = bz_firingMap1D(spikes,behavior,4,'savemat',false);
% let's look at some ratemaps...
subplot(3,2,2)
imagesc(squeeze(firingMaps.rateMaps{1}(96,:,:)))
ylabel('trial #')
xlabel('position')

[phaseMaps] = bz_phaseMap1D(spikes,behavior,lfp,4,'savemat',false);
% phase precession, eh?
subplot(3,2,4)
scatter(phaseMaps.phaseMaps{1}{96}(:,1),phaseMaps.phaseMaps{1}{96}(:,end),'.k')
hold on
scatter(phaseMaps.phaseMaps{1}{96}(:,1),phaseMaps.phaseMaps{1}{96}(:,end)+2*pi,'.k')
axis([0 200 -pi pi*3])
ylabel('theta phase')
xlabel('position')

subplot(3,2,3)
% pretty phasemap for rachel.... coming when someone has the motivation :)

%% detecting place fields
% should we find some place fields?
for condition = 1:length(firingMaps.rateMaps)
     fields{condition} = bz_getPlaceFields1D(firingMaps.rateMaps{condition},'minPeakRate',2,'percentThreshold',.15);
end

% typing 'fields{1}{96}{1}' will give you an idea of the type of data
% stored for each place field
fieldStart = fields{1}{96}{1}.start;
fieldStop = fields{1}{96}{1}.stop;
fieldCenterMass = fields{1}{96}{1}.COM;
% fieldStart = fields{1}{96}{1}.start;

subplot(3,2,3)
plot(squeeze(mean(firingMaps.rateMaps{1}(96,:,:),2)),'k')
line([fieldStart fieldStart],[0 25],'color','g')
line([fieldStop fieldStop],[0 25],'color','g')
line([fieldCenterMass fieldCenterMass],[0 25],'color','r')
title('G - start/stop, R - Center of mass')
ylabel('avg. firing rate')
xlabel('position')