function [V,X,Z,W] = spm_DEM_int(M,z,w,c)
% Integrates/evaluates a hierarchical model given innovations z{i} and w{i}
% FORMAT [V,X,Z,W] = spm_DEM_int(M,z,w,c);
%
% M{i}    - model structure
% z{i}    - innovations (causes)
% w{i}    - innovations (states)
% c{i}    - exogenous causes
%
% V{i}    - causal states (V{1} = y = response)
% X{i}    - hidden states
% Z{i}    - fluctuations (causes)
% W{i}    - fluctuations (states)
%
% The system is evaluated at the prior expectation of the parameters
%__________________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Karl Friston
% $Id: spm_DEM_int.m 6132 2014-08-06 19:59:46Z karl $

% set model indices and missing fields
%--------------------------------------------------------------------------
M      = spm_DEM_M_set(M);

% innovations
%--------------------------------------------------------------------------
z = spm_cat(z(:)) + spm_cat(c(:));
w = spm_cat(w(:));

% number of states and parameters
%--------------------------------------------------------------------------
nt   = size(z,2);                        % number of time steps
nl   = size(M,2);                        % number of levels
nv   = sum(spm_vec(M.l));                % number of v (casual states)
nx   = sum(spm_vec(M.n));                % number of x (hidden states)

% order parameters (n= 1 for static models)
%==========================================================================
dt   = M(1).E.dt;                        % time step
n    = M(1).E.n + 1;                     % order of embedding
nD   = M(1).E.nD;                        % number of iterations per sample
td   = dt/nD;                            % integration time for D-Step

% initialize cell arrays for derivatives z{i} = (d/dt)^i[z], ...
%--------------------------------------------------------------------------
u.v      = cell(n,1);
u.x      = cell(n,1);
u.z      = cell(n,1);
u.w      = cell(n,1);
[u.v{:}] = deal(sparse(nv,1));
[u.x{:}] = deal(sparse(nx,1));
[u.z{:}] = deal(sparse(nv,1));
[u.w{:}] = deal(sparse(nx,1));

% hyperparameters
%--------------------------------------------------------------------------
ph.h   = {M.hE};
ph.g   = {M.gE};

% initialize with starting conditions
%--------------------------------------------------------------------------
vi     = {M.v};
xi     = {M.x};
u.v{1} = spm_vec(vi);
u.x{1} = spm_vec(xi);

% derivatives for Jacobian of D-step
%--------------------------------------------------------------------------
Dx    = kron(spm_speye(n,n,1),spm_speye(nx,nx,0));
Dv    = kron(spm_speye(n,n,1),spm_speye(nv,nv,0));
D     = spm_cat(spm_diag({Dv,Dx,Dv,Dx}));
dfdw  = kron(eye(n,n),eye(nx,nx));

% initialize conditional estimators of states to be saved (V and X)
%--------------------------------------------------------------------------
mnx   = 0;
mnv   = 0;
for i = 1:nl

    V{i} = sparse(M(i).l,nt);
    X{i} = sparse(M(i).n,nt);
    Z{i} = sparse(M(i).l,nt);
    W{i} = sparse(M(i).n,nt);

    % check for state-dependent precision
    %----------------------------------------------------------------------
    mnx = mnx | length(M(i).pg);
    mnv = mnv | length(M(i).ph);

end

% defaults for state-dependent precision
%--------------------------------------------------------------------------
Sz = 1;
Sw = 1;

% iterate over sequence (t) and within for static models
%==========================================================================
for t  = 1:nt
    for iD = 1:nD

        % Get generalised motion of random fluctuations
        %==================================================================

        % sampling time
        %------------------------------------------------------------------
        ts   = (t + (iD - 1)/nD)*dt;

        % evaluate state-dependent precision
        %------------------------------------------------------------------
        if mnx || mnv

            vi{nl} = vi{nl} + c{nl}(:,t);
            pu.x   = {spm_vec(xi(1:end - 1))};
            pu.v   = {spm_vec(vi(1 + 1:end))};
            p      = spm_LAP_eval(M,pu,ph);

            if mnv, Sz = sparse(diag(exp(-p.h/2))); end
            if mnx, Sw = sparse(diag(exp(-p.g/2))); end

        end

        % derivatives of innovations (and exogenous input)
        %------------------------------------------------------------------
        u.z  = spm_DEM_embed(Sz*z,n,ts,dt);
        u.w  = spm_DEM_embed(Sw*w,n,ts,dt);

        % Evaluate and update states
        %==================================================================

        % evaluate functions
        %------------------------------------------------------------------
        [u,dg,df] = spm_DEM_diff(M,u);

        % tensor products for Jacobian
        %------------------------------------------------------------------
        dgdv = kron(spm_speye(n,n,1),dg.dv);
        dgdx = kron(spm_speye(n,n,1),dg.dx);
        dfdv = kron(spm_speye(n,n,0),df.dv);
        dfdx = kron(spm_speye(n,n,0),df.dx);

        % Save realization
        %==================================================================
        vi   = spm_unvec(u.v{1},{M.v});
        xi   = spm_unvec(u.x{1},{M.x});
        zi   = spm_unvec(u.z{1},{M.v});
        wi   = spm_unvec(u.w{1},{M.x});
        if iD == 1
            for i = 1:nl
                if M(i).l, V{i}(:,t) = spm_vec(vi{i}); end
                if M(i).n, X{i}(:,t) = spm_vec(xi{i}); end
                if M(i).l, Z{i}(:,t) = spm_vec(zi{i}); end
                if M(i).n, W{i}(:,t) = spm_vec(wi{i}); end
            end
        end

        % break for static models
        %------------------------------------------------------------------
        if nt == 1, break, end

        % Jacobian for update
        %------------------------------------------------------------------
        J      = spm_cat({dgdv dgdx Dv  []  ;
                          dfdv dfdx []  dfdw;
                          []   []   Dv  []  ;
                          []   []   []  Dx});

        % update states u = {x,v,z,w}
        %------------------------------------------------------------------
        du     = spm_dx(J,D*spm_vec(u),td);

        % and unpack
        %------------------------------------------------------------------
        u      = spm_unvec(spm_vec(u) + du,u);

    end % iterations over iD

end % iterations over t


function [y] = cellcolselect(x, cols)

% [Y] = CELLCOLSELECT(X, COLS) outputs cell-array Y with the same dimensionality as X
% Each cell in Y only contains the columns COLS from the original corresponding cell in X
%
% X (and Y) should be linear cell-array(s) of matrices for which the number of rows
% should be the same for all cells

nx = size(x);
if ~iscell(x) || length(nx)>2 || all(nx>1)
  error('incorrect input for cellrows');
end

if ~iscell(cols)
  y = cellfun(@colc, x, repmat(mat2cell(cols(:),length(cols),1),nx), 'UniformOutput', 0);
else
  y = cellfun(@colc, x, cols, 'UniformOutput', 0);
end

function [y] = colc(x, cols)

y = x(:,cols);


function g = matRad_objectiveGradient(optiProb,apertureInfoVec,dij,cst)
% matRad IPOPT callback: gradient function for direct aperture optimization
%
% call
%   g = matRad_objectiveGradient(optiProb,apertureInfoVec,dij,cst)
%
% input
%   optiProb:           option struct defining the type of optimization
%   apertureInfoVect:   aperture info in form of vector
%   dij:                matRad dij struct as generated by bixel-based dose calculation
%   cst:                matRad cst struct
%
% output
%   g: gradient
%
% References
%   [1] http://dx.doi.org/10.1118/1.4914863
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Copyright 2015 the matRad development team.
%
% This file is part of the matRad project. It is subject to the license
% terms in the LICENSE file found in the top-level directory of this
% distribution and at https://github.com/e0404/matRad/LICENSES.txt. No part
% of the matRad project, including this file, may be copied, modified,
% propagated, or distributed except according to the terms contained in the
% LICENSE file.
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% update apertureInfo, bixel weight vector an mapping of leafes to bixels
if ~isequal(apertureInfoVec,optiProb.apertureInfo.apertureVector)
    optiProb.apertureInfo = optiProb.matRad_daoVec2ApertureInfo(optiProb.apertureInfo,apertureInfoVec);
end
apertureInfo = optiProb.apertureInfo;

% bixel based gradient calculation
bixelG = matRad_objectiveGradient@matRad_OptimizationProblem(optiProb,apertureInfo.bixelWeights,dij,cst);

% allocate gradient vector for aperture weights and leaf positions
g = NaN * ones(size(apertureInfoVec,1),1);

% 1. calculate aperatureGrad
% loop over all beams
offset = 0;
for i = 1:numel(apertureInfo.beam)

    % get used bixels in beam
    ix = ~isnan(apertureInfo.beam(i).bixelIndMap);

    % loop over all shapes and add up the gradients x openingFrac for this shape
    for j = 1:apertureInfo.beam(i).numOfShapes
        g(j+offset) = apertureInfo.beam(i).shape(j).shapeMap(ix)' ...
                        * bixelG(apertureInfo.beam(i).bixelIndMap(ix));
    end

    % increment offset
    offset = offset + apertureInfo.beam(i).numOfShapes;

end

% 2. find corresponding bixel to the leaf Positions and aperture
% weights to calculate the gradient
g(apertureInfo.totalNumOfShapes+1:end) = ...
        apertureInfoVec(apertureInfo.mappingMx(apertureInfo.totalNumOfShapes+1:end,2)) ...
     .* bixelG(apertureInfo.bixelIndices(apertureInfo.totalNumOfShapes+1:end)) / apertureInfo.bixelWidth;

% correct the sign for the left leaf positions
g(apertureInfo.totalNumOfShapes+1:apertureInfo.totalNumOfShapes+apertureInfo.totalNumOfLeafPairs) = ...
    -g(apertureInfo.totalNumOfShapes+1:apertureInfo.totalNumOfShapes+apertureInfo.totalNumOfLeafPairs);


function DCM = VBA_spm_dcm_test(DCM)
% tests whether DCM parameters are zero using Savage-Dickey ratios
% function DCM = spm_dcm_test(DCM)
% IN:
%   - DCM: the DCM structure
% OUT:
%   - DCM: the DCM structure, augmented with field .sdr, which contains the
%   Savage-Dickey ratios in the same format as DCM.Ep

n = size(DCM.Ep.A,1);
nu = size(DCM.Ep.C,2);

E = VBA_spm_vec(DCM.Ep);
V = DCM.Cp;
E0 = VBA_spm_vec(DCM.M.pE);
V0 = DCM.M.pC;

sdr.A = zeros(n,n);
for i=1:n
    for j=1:n
        % 0- identify param index in DCM.Cp
        tmp = DCM.Vp;
        tmp.A(i,j) = 0;
        ind = find(full(VBA_spm_vec(tmp))~=full(VBA_spm_vec(DCM.Vp)));
        % 1- define reduced model
        E0r = E0;
        E0r(ind) = 0;
        V0r = V0;
        V0r(ind,:) = 0;
        V0r(:,ind) = 0;
        % 2- call Savage-Dickey ratios
        if isempty(ind) % this param was fixed
            if isequal(E0,E0r)
                dF = Inf;
            else
                dF = -Inf;
            end
        else
            dF = VBA_spm_log_evidence(E,V,E0,V0,E0r,V0r);
        end
        % 3- store Bayes factor
        sdr.A(i,j) = 1./(1+exp(dF));
    end
end

sdr.B = zeros(n,n,nu);
for i=1:n
    for j=1:n
        for k=1:nu
            tmp = DCM.Vp;
            tmp.B(i,j,k) = 0;
            ind = find(full(VBA_spm_vec(tmp))~=full(VBA_spm_vec(DCM.Vp)));
            E0r = E0;
            E0r(ind) = 0;
            V0r = V0;
            V0r(ind,:) = 0;
            V0r(:,ind) = 0;
            if isempty(ind) % this param was fixed
                if isequal(E0,E0r)
                    dF = Inf;
                else
                    dF = -Inf;
                end
            else
                dF = VBA_spm_log_evidence(E,V,E0,V0,E0r,V0r);
            end
            sdr.B(i,j,k) = 1./(1+exp(dF));
        end
    end
end

sdr.C = zeros(n,nu);
for i=1:n
    for j=1:nu
        tmp = DCM.Vp;
        tmp.C(i,j) = 0;
        ind = find(full(VBA_spm_vec(tmp))~=full(VBA_spm_vec(DCM.Vp)));
        E0r = E0;
        E0r(ind) = 0;
        V0r = V0;
        V0r(ind,:) = 0;
        V0r(:,ind) = 0;
        if isempty(ind) % this param was fixed
            if isequal(E0,E0r)
                dF = Inf;
            else
                dF = -Inf;
            end
        else
            dF = VBA_spm_log_evidence(E,V,E0,V0,E0r,V0r);
        end
        sdr.C(i,j) = 1./(1+exp(dF));
    end
end

nD = size(DCM.Ep.D,3);
if nD > 0
    for i=1:n
        for j=1:n
            for k=1:n
                tmp = DCM.Vp;
                tmp.D(i,j,k) = 0;
                ind = find(full(VBA_spm_vec(tmp))~=full(VBA_spm_vec(DCM.Vp)));
                E0r = E0;
                E0r(ind) = 0;
                V0r = V0;
                V0r(ind,:) = 0;
                V0r(:,ind) = 0;
                if isempty(ind) % this param was fixed
                    if isequal(E0,E0r)
                        dF = Inf;
                    else
                        dF = -Inf;
                    end
                else
                    dF = VBA_spm_log_evidence(E,V,E0,V0,E0r,V0r);
                end
                sdr.D(i,j,k) = 1./(1+exp(dF));
            end
        end
    end
end

DCM.sdr = sdr;


function [g1, g2] = ggwhiteXggwhiteKernGradient(ggwhiteKern1, ggwhiteKern2, ...
    x, x2, covGrad)

% GGWHITEXGGWHITEKERNGRADIENT Compute a cross gradient between two GG WHITE kernels.
% FORMAT
% DESC computes cross gradient of parameters of a cross kernel between two
%	gg white kernels for the multiple output kernel.
% RETURN g1 : gradient of the parameters of the first kernel, for ordering
%	   see ggwhiteKernExtractParam.
% RETURN g2 : gradient of the parameters of the second kernel, for ordering
%	   see ggwhiteKernExtractParam.
% ARG ggwhiteKern1 : the kernel structure associated with the first GG white
%	   kernel.
% ARG ggwhiteKern2 : the kernel structure associated with the second GG white
%	   kernel.
% ARG x : inputs for which kernel is to be computed.
% ARG covgrad : gradient of the objective function with respect to the
%	   elements of the cross kernel matrix.
%
% FORMAT
% DESC computes cross kernel terms between two GG WHITE kernels for the multiple
%	output kernel.
% RETURN g1 : gradient of the parameters of the first kernel, for ordering
%	   see ggwhiteKernExtractParam.
% RETURN g2 : gradient of the parameters of the second kernel, for ordering
%	   see ggwhiteKernExtractParam.
% ARG ggwhiteKern1 : the kernel structure associated with the first GG WHITE
%	   kernel.
% ARG ggwhiteKern2 : the kernel structure associated with the second GG WHITE
%	   kernel.
% ARG x : row inputs for which kernel is to be computed.
% ARG x2 : column inputs for which kernel is to be computed.
% ARG covgrad : gradient of the objective function with respect to the
%	   elements of the cross kernel matrix.
%
% SEEALSO : multiKernParamInit, multiKernCompute, ggwhiteKernParamInit,
% ggwhiteKernExtractParam
%
% COPYRIGHT : Mauricio A. Alvarez and Neil D. Lawrence, 2008
%
% MODIFICATIONS : Mauricio A. Alvarez, 2009.

% KERN

if nargin < 5
    covGrad = x2;
    x2 = x;
end

[K, Pinv, Lqrinv, Lsrinv, Kbase, factorNoise, factorVar1, factorVar2, dist] = ...
    ggwhiteXggwhiteKernCompute(ggwhiteKern1, ggwhiteKern2, x, x2);
P = 1./Pinv;

if ggwhiteKern1.isArd
    matGradLqr = zeros(ggwhiteKern1.inputDimension,1);
    matGradLsr = zeros(ggwhiteKern1.inputDimension,1);
    for i=1:ggwhiteKern1.inputDimension
        X = repmat(x(:,i),1, size(x2,1));
        X2 = repmat(x2(:,i)',size(x,1),1);
        X_X2 = (X - X2).*(X - X2);
        matGradLqr(i) = sum(sum(0.5*covGrad.*K.*...
            (-0.5*Lqrinv(i) + Lqrinv(i)*P(i)*Lqrinv(i) - Lqrinv(i)*P(i)*X_X2*P(i)*Lqrinv(i) )));
        matGradLsr(i) = sum(sum(0.5*covGrad.*K.*...
            (-0.5*Lsrinv(i) + Lsrinv(i)*P(i)*Lsrinv(i) - Lsrinv(i)*P(i)*X_X2*P(i)*Lsrinv(i) )));
    end
else
    matGradLqr = sum(sum(0.5*covGrad.*K.*( -0.5*ggwhiteKern1.inputDimension*Lqrinv...
        + ((P*Lqrinv)^2)*(ggwhiteKern1.inputDimension*Pinv - dist))    ));
    matGradLsr = sum(sum(0.5*covGrad.*K.*( -0.5*ggwhiteKern1.inputDimension*Lsrinv...
        + ((P*Lsrinv)^2)*(ggwhiteKern1.inputDimension*Pinv - dist))   ));
end
grad_sigma2Noise = factorNoise*sum(sum(covGrad.*Kbase));
grad_variance1 = factorVar1*sum(sum(covGrad.*Kbase));
grad_variance2 = factorVar2*sum(sum(covGrad.*Kbase));
% only pass the gradient with respect to the inverse width to one
% of the gradient vectors ... otherwise it is counted twice.
g1 = [matGradLqr(:)' grad_sigma2Noise grad_variance1];
%g1 = [matGradLqr(:)' 0 grad_variance1];
g2 = [matGradLsr(:)' 0 grad_variance2];


%IM2COL Convert an image to pixel per row format
%
% OUT = IM2COL(IM) is a matrix (NxP) where each row represents a single
% of the image IM (HxWxP).  The pixels are in image column order (ie. column
% 1, column 2 etc) and there are N=WxH rows.
%
% OUT = IM2COL(IM, MASK) as above but only includes pixels if:
% - the corresponding element of MASK (HxW) is non-zero
% - the corresponding element of MASK (N) is non-zero where N=HxW
% - the pixel index is included in the vector MASK
%
% See also COL2IM.

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

function c = im2col(im, mask)

    if ndims(im) == 3
        c = reshape(shiftdim(im, 2), 3, [])';
    else
        c = reshape(im, 1, [])';
    end

    if nargin > 1 && ~isempty(mask)
        d = size(im);
        if ndims(mask) == 2 && all(d(1:2) == size(mask))
            k = find(mask);
        elseif isvector(mask)
            k = mask;
        else
            error('MVTB:im2col:badarg', 'mask must be same size as image or a vector');
        end

        c = c(k,:);
    end
end


function opt_vect = foptions()
% FOPTIONS Sets default parameters for optimisation routines
% For compatibility with MATLAB's foptions()
%
% Copyright (c) Dharmesh Maniyar, Ian T. Nabney (2004)

opt_vect      = zeros(1, 18);
opt_vect(2:3) = 1e-4;
opt_vect(4)   = 1e-6;
opt_vect(16)  = 1e-8;
opt_vect(17)  = 0.1;


function h = match_plot(img1,img2,points1,points2)
%MATCH_PLOT
%   h = match_plot(img1,img2,points1,points2)
%   plot coresponding points between two images
%
%   points1 = [x1 y1; x2 y2; ...] = coresponding points in img1
%   points2 = [x1 y1; x2 y2; ...] = coresponding points in img2
%
%   origin is the top left of the image
%   x axis pointing right, y axis pointing down.
%   points 2 has to be the same size as points 1
%
%   if 2 images have different size, the smaller one is rescaled.
%
%   coresponding lines are plot in different colors, from red to blue in
%   rainbow order.
%
%   returns the figure handle object h
%
%   written by Gooly 4/21/2011
%   http://computervisionblog.wordpress.com/

h = figure;
colormap = {'b','r','m','y','g','c'};
height = max(size(img1,1),size(img2,1));
img1_ratio = height/size(img1,1);
img2_ratio = height/size(img2,1);
img1 = imresize(img1,img1_ratio);
img2 = imresize(img2,img2_ratio);
points1 = points1 * img1_ratio;
points2 = points2 * img2_ratio;
points1 = [points1(:,2) points1(:,1)];
points2 = [points2(:,2) points2(:,1)];
match_img = zeros(height, size(img1,2)+size(img2,2), size(img2,3));
match_img(1:size(img1,1),1:size(img1,2),:) = img1;
match_img(1:size(img2,1),size(img1,2)+1:end,:) = img2;
imshow(uint8(match_img));
hold on;
for i=1:size(points1,1)
    plot([points1(i,2) points2(i,2)+size(img1,2)],[points1(i,1) points2(i,1)],colormap{mod(i,6)+1});
end

hold off;

end


 function tester_tomo2(A1, mask, varargin)
%function tester_tomo2(A1, mask, [options])
%|
%| Test suite for a Fatrix-type 2D or 3D system object, including Gblock tests.
%|
%| in
%|	A1	Fatrix or fatrix2
%|	mask	logical [nx ny] or [nx ny nz]
%|
%| option
%|	'A2'	Fatrix	optional 2nd object for testing and comparisons
%|			(it is also put through all the same tests)
%|	'multi'	0|1	see Fatrix_test_basic()
%|	'halt'	0|1	see Fatrix_test_basic()
%|	'equiv_thresh'	instead of jf_equal, use equivs() with this threshold
%|			default: [], which means use jf_equal
%|	'nblock'	# of blocks for testing block version (default 2)
%|			set to 0 to prevent block test
%|
%| Copyright 2005-8-2, Jeff Fessler, University of Michigan

if nargin < 2, ir_usage, end

arg.multi = true;
arg.A2 = [];
arg.halt = true;
arg.equiv_thresh = [];
arg.nblock = 2; % for block test
arg = vararg_pair(arg, varargin, 'subs', {'G2', 'A2'});

Fatrix_test_basic(A1, mask, 'multi', arg.multi, ...
	'halt', arg.halt, ...
	'name', inputname(1), 'caller', caller_name)

switch ndims(mask)
case 2
	[nx, ny] = size(mask);
	ig = image_geom('nx', nx, 'ny', ny, 'dx', 1);
	x = ellipse_im(ig, []);

case 3
	[nx, ny, nz] = size(mask);
	ig = image_geom('nx', nx, 'ny', ny, 'nz', nz, 'dx', 1);
	x = ellipsoid_im(ig, '');
	x = x .* mask;
end

if arg.nblock
	tester_tomo2_block(A1, mask, x, arg.nblock, arg.multi, arg.equiv_thresh)
end

if ~isempty(arg.A2)
	Fatrix_test_basic(arg.A2, mask, 'multi', arg.multi, ...
		'name', inputname(4), 'caller', caller_name)
	tester_tomo2_compare(A1, arg.A2, x)
end

%
% tester_tomo2_compare()
%
function tester_tomo2_compare(A1, A2, x)

y1 = A1 * x;
y2 = A2 * x;
my_compare(y1, y2, 'A*x')

x1 = A1' * y1;
x2 = A2' * y1;
equivs(x1, x2)

j = round(size(A1,2) / 2); % roughly a middle pixel
y1 = A1(:,[j j+1]);
y2 = A2(:,[j j+1]);
y1 = [y1(:,1) y1(:,2)]; % for fatrix2
y2 = [y2(:,1) y2(:,2)]; % for fatrix2
my_compare(y1, y2, 'A(:,j)')

% check A(:,:)
if 0 && size(x,1) < 100
	t1 = A1(:,:);
	t2 = A2(:,:);
	my_compare(t1, t2, '(:,:)');
%	mpd = max_percent_diff(t1,t2);
%	printf('A(:,:)	mpd %g', mpd)
%	if mpd/100 > 1e-6, error 'A(:,:)', end
end

printm('passed %s', A1.caller)

%
% tester_tomo2_block()
% now block version
%
function tester_tomo2_block(A1, mask, x, nblock, multi, equiv_thresh)

B1 = Gblock(A1, nblock);

% B * x
y1 = A1 * x;
y2 = B1 * x;
my_compare(y1, y2, 'B*x')

y0 = y1;
odim = A1.arg.odim;
na = odim(end);
switch length(odim)
case 3
	getp = @(x,i) x(:,:,i);
case 2
	getp = @(x,i) x(:,i);
otherwise
	fail 'not done'
end
% caution: handle single view 3D projectors [ns nt 1 nrep]
catp = @(a,b) cat(length(odim)+1, a, b);

% B' * y
x1 = A1' * y0;
x2 = B1' * y0;
my_compare(x1, x2, 'B''*y')

comp = @(t1, t2, str) my_compare2(t1, t2, str, equiv_thresh);

%
% block operations
%
for k=1:nblock
	ia = k:nblock:na;
	str = sprintf('B{%d}', k);

	% check B{k} * x
	t1 = A1 * x;
	t1 = getp(t1,ia);
	t2 = B1{k} * x;
	comp(t1, t2, 'B{k} * x')

	% B{k} * [x x]
	if multi
		t2 = B1{k} * stackup(x,x);
		comp(catp(t1, t1), t2, [str ' * [x x]'])
	end

	% check B{k} * x(mask)
	t2 = B1{k} * x(mask);
	t2 = reshape(t2, size(t1));
	comp(t1, t2, [str ' * x()'])

	% check B{k} * [x(mask) x(mask)]
	if multi
		t2 = B1{k} * [x(mask) x(mask)];
		comp([t1(:) t1(:)], t2, [str ' * [x() x()]'])
	end

	% check B{k}' * y()
	tmp = block_insert(ia, odim, getp(y0,ia));
	t1 = A1' * tmp(:);
	t2 = B1{k}' * col(getp(y0,ia));
	if isempty(equiv_thresh)
%		my_compare(t1, t2, [str ''' * y'])
		mpd = max_percent_diff(t1,t2);
		if mpd
			printf([str '''*y mpd %g'], mpd)
			if mpd/100 > 1e-6
				fail 'B{k}'' * y()'
%				keyboard
			end
		end
	else
		comp(t1, t2, [str ''' * y'])
	end
end

% my_compare()
function my_compare(t1, t2, arg)
%max_percent_diff(t1, t2, arg)
%try
	jf_equal(t1, t2)
%catch
%	warn('%s failed', arg)
%	keyboard
%end

function my_compare2(t1, t2, arg, equiv_thresh)
if ~isempty(equiv_thresh)
	equivs(t1, t2, 'thresh', equiv_thresh)
else
	try
		my_compare(t1, t2, arg)
	catch
	%	keyboard
		fail('testing %s', arg)
	end
end

% block_insert()
% for block or OS methods, make data array that is all zeros but at "ia"
function out = block_insert(ia, dims, data)
out = zeros(dims);
switch length(dims)
case 2
	out(:,ia) = data;
case 3
	out(:,:,ia) = data;
otherwise
	fail 'not done'
end


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

%% -*- texinfo -*-
%% @documentencoding UTF-8
%% @deftypemethod  @@sym {@var{d} =} size (@var{x})
%% @deftypemethodx @@sym {[@var{n}, @var{m}] =} size (@var{x})
%% @deftypemethodx @@sym {@var{d} =} size (@var{x}, @var{dim})
%% Return the size of a symbolic array.
%%
%% Examples:
%% @example
%% @group
%% syms x
%% A = [1 2 x; x 3 4];
%% [n, m] = size(A)
%%   @result{} n = 2
%%   @result{} m = 3
%% @end group
%%
%% @group
%% A = sym('a', [3 4]);
%% [n, m] = size(A)
%%   @result{} n = 3
%%   @result{} m = 4
%% size(A, 1)
%%   @result{} 3
%% size(A, 2)
%%   @result{} 4
%% @end group
%% @end example
%%
%% Symbolic-sized matrices currently return @code{1 × 1} but we might
%% prefer @code{NaN × NaN}:
%% @example
%% @group
%% syms n m integer
%% A = sym('a', [n m])
%%   @result{} A = (sym) a  (n×m matrix expression)
%%
%% size(A)          % doctest: +XFAIL
%%   @result{} NaN   NaN
%% @end group
%% @end example
%%
%% @seealso{@@sym/length, @@sym/numel}
%% @end deftypemethod

function [n, m] = size(x, dim)

  % Note: symbolic sized matrices should return double, not sym/string.

  n = x.size;

  % FIXME: for now, we artificially force symbolic sized objects
  % (where one or more dimension is recorded as NaN) to be 1x1.
  % This effects MatrixSymbol and MatrixExpr.  See Issue #159.
  if (any(isnan(n)))
    n = [1 1];
  end
  % Alternatively:
  %n(isnan(n)) = 1;

  if (nargin == 2) && (nargout == 2)
    print_usage ();
  elseif (nargout == 2)
    m = n(2);
    n = n(1);
  elseif (nargin == 2)
    n = n(dim);
  end

end

%!test
%! a = sym([1 2 3]);
%! [n,m] = size(a);
%! assert (n == 1 && m == 3)

%!test
%! a = sym([1 2 3]);
%! n = size(a);
%! assert (isequal (n, [1 3]))

%!test
%! %% size, numel, length
%! a = sym([1 2 3; 4 5 6]);
%! assert (isa (size(a), 'double'))
%! assert (isa (numel(a), 'double'))
%! assert (isa (length(a), 'double'))
%! assert (isequal (size(a), [2 3]))
%! assert (length(a) == 3)
%! assert (numel(a) == 6)
%! a = sym([1; 2; 3]);
%! assert (isequal (size(a), [3 1]))
%! assert (length(a) == 3)
%! assert (numel(a) == 3)

%!test
%! %% size by dim
%! a = sym([1 2 3; 4 5 6]);
%! n = size(a, 1);
%! assert (n == 2)
%! m = size(a, 2);
%! assert (m == 3)
%! a = sym([1 2 3]');
%! n = size(a, 1);
%! assert (n == 3)
%! m = size(a, 2);
%! assert (m == 1)

%!xtest
%! % symbolic-size matrices
%! syms n m integer
%! A = sym('A', [n m]);
%! d = size(A);
%! assert (~isa(d, 'sym'))
%! assert (isnumeric(d))
%! assert (isequaln (d, [NaN NaN]))

%!xtest
%! % half-symbolic-size matrices
%! % FIXME: will fail until size stop lying by saying 1x1
%! syms n integer
%! A = sym('A', [n 3]);
%! assert (isequaln (size(A), [NaN 3]))
%! A = sym('A', [4 n]);
%! assert (isequaln (size(A), [4 NaN]))

%!xtest
%! % half-symbolic-size empty matrices
%! % FIXME: will fail until size stop lying by saying 1x1
%! syms n integer
%! A = sym('A', [n 0]);
%! assert (isequaln (size(A), [NaN 0]))


%type3detransform.m
%written by: Duncan Po
%Date: June 27/2002
% utility file used in tree2contourlet.m
% usage [x,y] = type3detransform(z)
% decomposes z into x and y

function [x,y] = type3detransform(z)

row = size(z,1);
col = size(z,2);
z = z.';
z = reshape(z, col*2, row/2);
z = z.';
x = z(:, 1:col);
y = z(:,(col+1):(2*col));


function nc = wavepaste(type,c,s,n,x)
%WAVEPASTE Puts coefficients in a wavelet decomposition structure.
%   NC = WAVEPASTE(TYPE,C,S,N,X) returns the new decomposition structure
%   after pasting X into it based on TYPE and N.
%
%   INPUTS:
%     TYPE      Coefficient category
%     -------------------------------------
%     'a'       Approximation coefficients
%     'h'       Horizontal details
%     'v'       Vertical details
%     'd'       Diagonal details
%
%     [C, S] is a wavelet data structure.
%     N specifies a decomposition level (Ignored if TYPE = 'a').
%     X is a 2- or 3-D approximation or detail coefficient matrix whose
%       dimensions are appropriate for decomposition level N.
%
%   See also WAVEWORK, WAVECUT, and WAVECOPY.
%
%   Copyright 2002-2020 Gatesmark
%
%   This function, and other functions in the DIPUM Toolbox, are based
%   on the theoretical and practical foundations established in the
%   book Digital Image Processing Using MATLAB, 3rd ed., Gatesmark
%   Press, 2020.
%
%   Book website: http://www.imageprocessingplace.com
%   License: https://github.com/dipum/dipum-toolbox/blob/master/LICENSE.txt

narginchk(5,5)
nc = wavework('paste',type,c,s,n,x);


function [g, model] = vargplvmPointLogLikeGradient(model, vardistx, y)
% VARGPLVMPOINTLOGLIKEGRADIENT Log-likelihood gradient for of some points of the GP-LVM.
% FORMAT
% DESC returns the gradient of the log likelihood with respect to
% the latent positions, where the log likelihood is conditioned on
% the training set. The function works even when we are interested only in
% one point. See vargplvmPointLogLikelihood for more details.
% ARG model : the model for which the gradient computation is being
% done.
% ARG x : the latent positions where the gradient is being computed.
% ARG y : the positions in data space for which the computation is
% being done.
% RETURN g : the gradient of the log likelihood, conditioned on the
% training data, with respect to the latent position.
%
% SEEALSO : vargplvmPointLogLikelihood, vargplvmOptimisePoint, vagplvmSequenceLogLikeGradient
%
% COPYRIGHT : Michalis K. Titsias and Neil D. Lawrence, 2009, 2011
% COPYRIGHT : Andreas C. Damianou, 2011
% VARGPLVM

if isfield(model, 'dynamics') && ~isempty(model.dynamics)
    dynUsed = 1;
else
    dynUsed = 0;
end

indexMissing = find(isnan(y(1,:)));
indexPresent = setdiff(1:model.d, indexMissing);
y = y(:,indexPresent);

if dynUsed
    % use a special function
    [g, model] = dynPointLogLikeGradient(model, vardistx, y, indexPresent, indexMissing);
    % g = g(:)'; %%% RE-OPT-CODE-REM
    return;
end

% normalize y exactly as model.m is normalized
my = y - repmat(model.bias(indexPresent),size(y,1),1);
my = my./repmat(model.scale(indexPresent),size(y,1),1);

[gPsi0, gPsi1, gPsi2] = vargpCovGrads(model, vardistx, my, indexPresent);

[gKern1, gVarmeans1, gVarcovs1] = kernVardistPsi1Gradient(model.kern, vardistx, model.X_u, gPsi1');
[gKern2, gVarmeans2, gVarcovs2] = kernVardistPsi2Gradient(model.kern, vardistx, model.X_u, gPsi2);
[gKern0, gVarmeans0, gVarcovs0] = kernVardistPsi0Gradient(model.kern, vardistx, gPsi0);

gVarcovs0 = (gVarcovs0(:).*vardistx.covars(:))';
gVarcovs1 = (gVarcovs1(:).*vardistx.covars(:))';
gVarcovs2 = (gVarcovs2(:).*vardistx.covars(:))';

% KL divergence terms
gVarmeansKL = - vardistx.means(:)';
% !!! the covars are optimized in the log space
gVarcovsKL = 0.5 - 0.5*vardistx.covars(:)';

gVarmeans = gVarmeans0 + gVarmeans1 + gVarmeans2 + gVarmeansKL;
gVarcovs = gVarcovs0 + gVarcovs1 + gVarcovs2 + gVarcovsKL;

g = [gVarmeans gVarcovs];

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% --------------------------------------------------------
function [gPsi0, gPsi1, gPsi2] = vargpCovGrads(model, vardistx, my, indexPresent)
%
%

d = prod(size(indexPresent));

% change the data (by including the new point and taking only the present indices)
model.m = model.m(:,indexPresent);
model.m = [my; model.m];

pointPsi1 = kernVardistPsi1Compute(model.kern, vardistx, model.X_u);
pointPsi2 = kernVardistPsi2Compute(model.kern, vardistx, model.X_u);

model.Psi1 = [pointPsi1; model.Psi1];

model.C = model.invLm * (model.Psi2 + pointPsi2) * model.invLmT;
model.TrC = sum(diag(model.C)); % Tr(C)
model.At = (1/model.beta) * eye(size(model.C,1)) + model.C;
model.Lat = jitChol(model.At)';
model.invLat = model.Lat\eye(size(model.Lat,1));
model.invLatT = model.invLat';
model.logDetAt = 2*(sum(log(diag(model.Lat)))); % log |At|
model.P1 = model.invLat * model.invLm; % M x M
model.P = model.P1 * (model.Psi1' * model.m);
model.TrPP = sum(sum(model.P .* model.P));
model.B = model.P1' * model.P;
P1TP1 = (model.P1' * model.P1);
Tb = (1/model.beta) * d * P1TP1;
Tb = Tb + (model.B * model.B');
model.T1 = d * model.invK_uu - Tb;

gPsi2 = (model.beta/2) * model.T1;

gPsi0 = -0.5 * model.beta * d;

gPsi1 = model.beta*(P1TP1*model.Psi1'*model.m*my');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% --------------------------------------------------------
function [gPointDyn, model] = dynPointLogLikeGradient(model, vardistx, y, indexPresent, indexMissing)
jitter = 1e-6;

%%% RE-OPT-CODE-NEW_
if isfield(model.dynamics, 'reoptimise') && model.dynamics.reoptimise
    % In this case the inducing points and theta_t are optimised and
    % since updateStats is not called, any computations which need X_u
    % or theta_t must be done here.
    model = vargplvmDynamicsUpdateStats(model);
    model.K_uu = kernCompute(model.kern, model.X_u);
    model.K_uu = model.K_uu ...
        + sparseDiag(repmat(jitter, size(model.K_uu, 1), 1));
    model.Lm = jitChol(model.K_uu)';
    model.invLm = model.Lm\eye(model.k);
    model.invLmT = model.invLm';
    model.invK_uu = model.invLmT * model.invLm;
end %%% _RE-OPT-CODE-NEW

%%%%%%%%% Only the missing parts and from the training data only
mOrig = model.m;
vardistDynTemp = model.dynamics.vardist;

N = model.N;
Nstar = size(y,1);
Kt = zeros(N+Nstar, N+Nstar);

%model.y = model.y(:,indexMissing);
model.m = model.m(:,indexMissing);
model.d = prod(size(indexMissing));
% Augment the time vector to include the timestamp of the new point
model.dynamics.t = [model.dynamics.t; model.dynamics.t_star];
% Augment the reparametrized variational parameters mubar and lambda
model.dynamics.vardist.means = [model.dynamics.vardist.means; vardistx.means];
model.dynamics.vardist.covars = [model.dynamics.vardist.covars; vardistx.covars];
model.dynamics.N = model.dynamics.N + Nstar;
model.vardist.numData = model.dynamics.N;
model.dynamics.vardist.numData = model.dynamics.N;
model.vardist.nParams = 2*prod(size(model.dynamics.vardist.means));
model.dynamics.vardist.nParams = 2*prod(size(model.dynamics.vardist.means));
%model.dynamics.seq = model.dynamics.N; %%%%%% Chec
% Faster computation of the Kt matrix
% (all this could have been avoided as Kt is constant... we need to do these
% precomputations outside of this function)
% construct Kt
Kt(1:N,1:N) = model.dynamics.Kt;
% new diagonal block
Kt(N+1:end, N+1:end) = kernCompute(model.dynamics.kern, model.dynamics.t_star);
% cross block
if ~isfield(model.dynamics, 'seq') || isempty(model.dynamics.seq)
    Kt(1:N, N+1:end) = kernCompute(model.dynamics.kern, model.dynamics.t(1:N), model.dynamics.t_star);
    Kt(N+1:end, 1:N) = Kt(1:N, N+1:end)';
end
model.dynamics.Kt = Kt;
model.dynamics.fixedKt = 1;
model = vargpTimeDynamicsUpdateStats(model);

vardist2 = model.vardist;
vardist2.means = model.vardist.means(1:end-Nstar,:);
vardist2.covars = model.vardist.covars(1:end-Nstar,:);
vardist2.nParams = 2*prod(size(vardist2.means));
vardist2.numData = size(vardist2.means,1);
model.Psi0 = kernVardistPsi0Compute(model.kern, vardist2);
model.Psi1 = kernVardistPsi1Compute(model.kern, vardist2, model.X_u);
model.Psi2 = kernVardistPsi2Compute(model.kern, vardist2, model.X_u);

model.C = model.invLm * model.Psi2 * model.invLmT;
%model.TrC = sum(diag(model.C)); % Tr(C)
model.At = (1/model.beta) * eye(size(model.C,1)) + model.C; % At = beta^{-1} I + C
model.Lat = jitChol(model.At)';
model.invLat = model.Lat\eye(size(model.Lat,1));
%model.invLatT = model.invLat';
%model.logDetAt = 2*(sum(log(diag(model.Lat)))); % log |At|
model.P1 = model.invLat * model.invLm; % M x M
model.P = model.P1 * (model.Psi1' * model.m);
%model.TrPP = sum(sum(model.P .* model.P));
model.B = model.P1' * model.P;
%model.invK_uu = model.invLmT * model.invLm;
Tb = (1/model.beta) * model.d * (model.P1' * model.P1);
Tb = Tb + (model.B * model.B');
model.T1 = model.d * model.invK_uu - Tb;

modelTmp = model;
modelTmp.vardist = vardist2;
modelTmp.dynamics.vardist = vardistDynTemp;
modelTmp.dynamics.Kt = modelTmp.dynamics.Kt(1:end-Nstar,1:end-Nstar);
modelTmp.dynamics.N = N;
modelTmp.dynamics.t = modelTmp.dynamics.t(1:end-Nstar);
modelTmp.dynamics.vardist.numData = modelTmp.dynamics.N; %%%% new...
modelTmp.vardist.numData = modelTmp.N;%%%% new...
%modelTmp.TrYY = sum(sum(model.m .* model.m));

% GRADIENT OF THE LL1 TERM mu,S from the training data

% To understand the following code it's helpful to see
% vargpTimeDynamicsPriorReparamGrads.m; LL1 term now is not computed
% together with KL so we cannot use that function here; however, it does
% contain theta_t so these computations must be done but only for the part
% corresponding to modelTmp. Thus, the following code actually is a copy of
% vargpTimeDynamicsPriorReparamGrads but is applied only on the appropriate
% part of Kt.
% i.e: gPointDyn1Tmp(:,1:model.dynamics.q) -> gVarmeansLik
%      gPointDyn1Tmp(:,model.dynamics.q+q) -> gVarcovsLik(:,q)

%gPointDyn1 = zeros(Nstar,modelTmp.dynamics.q*2);
gPointDyn1 = zeros(N+Nstar,modelTmp.dynamics.q*2);
if ~isempty(indexMissing)
    if isfield(model.dynamics, 'reoptimise') && model.dynamics.reoptimise %%% RE-OPT-CODE-NEW
        % gDynKern will be empty in that case (includeKL is 0) %%% RE-OPT-CODE-NEW
        [gPointDyn1Tmp, gDynKern, gInd1]= vargplvmLogLikeGradientsVar1(modelTmp, 0); %%% RE-OPT-CODE-NEW
        sumTrGradKL = 0; %%% RE-OPT-CODE-NEW
    else %%% RE-OPT-CODE-NEW
        gPointDyn1Tmp = vargplvmLogLikeGradientsVar1(modelTmp, 0);
    end %%% RE-OPT-CODE-NEW
    gPointDyn1Tmp = reshape(gPointDyn1Tmp, modelTmp.dynamics.vardist.numData, modelTmp.dynamics.q*2);

    % means (Note: Kt(1:N,:)' == Kt(:,1:N)  )
    gPointDyn1(:,1:modelTmp.dynamics.q) = model.dynamics.Kt(1:N,:)'*gPointDyn1Tmp(:,1:model.dynamics.q);

    % covars
    %gcovTmp = zeros(Nstar,modelTmp.dynamics.q);
    gcovTmp = zeros(N+Nstar,modelTmp.dynamics.q);
    sumTrGradKL1 = zeros(N+Nstar,N);
    sumTrGradKL2 = zeros(N+Nstar, N+Nstar);
    for q=1:model.dynamics.q
        LambdaH_q = model.dynamics.vardist.covars(:,q).^0.5;
        Bt_q = eye(model.dynamics.N) + LambdaH_q*LambdaH_q'.*model.dynamics.Kt;
        % Invert Bt_q
        Lbt_q = jitChol(Bt_q)';
        G1 = Lbt_q \ diag(LambdaH_q);
        G = G1*model.dynamics.Kt;
        % Find Sq
        Sq = model.dynamics.Kt - G'*G;
        Sq = - (Sq .* Sq);

        % only the cross matrix is needed as in barmu case
        %gcovTmp(:,q) = Sq(1:N,N+1:end)'*gPointDyn1Tmp(:,model.dynamics.q+q);

        % gPointDyn1Tmp contains [means covars]. model.dynamics.q+q gives
        % us only the covars.
        gcovTmp(:,q) = Sq(1:N,:)'*gPointDyn1Tmp(:,model.dynamics.q+q);

        %%% RE-OPT-CODE-NEW_
        if isfield(model.dynamics, 'reoptimise') && model.dynamics.reoptimise
            % Find the coefficient for the grad. wrt theta_t (params of Kt)
            G1T=G1';
            Bhat=G1T*G1;
            BhatKt=G1T*G;

            IBK = eye(model.dynamics.N) - BhatKt;

            diagVarcovs = repmat(gPointDyn1Tmp(:,model.dynamics.q+q)', model.dynamics.N,1);
            sumTrGradKL2 = sumTrGradKL2  +  (IBK(:,1:N).*diagVarcovs)*IBK(:,1:N)';

           %%%
         %   tmp = [gPointDyn1Tmp(:,model.dynamics.q+q)' zeros(1,Nstar)]; %tmp
         %   tmp2=IBK*diag(tmp)*IBK'; %tmp
         %   sumTrGradKL2 = sumTrGradKL2  +  tmp2; % tmp
           %%%

            sumTrGradKL1 = sumTrGradKL1 + model.dynamics.vardist.means(:,q)*gPointDyn1Tmp(:,q)';
            %if ~isempty(gInd)
            %    trGradKL = trGradKL + dynModel.vardist.means(:,q) * gInd(:,q)';
            %end
        end
        %%% _RE-OPT-CODE-NEW
    end

    gPointDyn1(:,(modelTmp.dynamics.q+1):(modelTmp.dynamics.q*2)) = gcovTmp;

    if isfield(model.dynamics, 'reoptimise') && model.dynamics.reoptimise                   %%% RE-OPT-CODE-NEW
        gDynKern1 = kernGradient(model.dynamics.kern, model.dynamics.t, model.dynamics.t(1:N),  sumTrGradKL1)  ; %%% RE-OPT-CODE-NEW
        gDynKern1 = gDynKern1 + kernGradient(model.dynamics.kern, model.dynamics.t, sumTrGradKL2); %%% RE-OPT-CODE-NEW
    end                                                                                %%% RE-OPT-CODE-NEW

end

% GRADIENT FOR LL2 plus KL TERMS
%
model.m = mOrig;
% normalize y exactly as model.m is normalized
my = y - repmat(model.bias(indexPresent), Nstar, 1);
my = my./repmat(model.scale(indexPresent), Nstar, 1);
model.m = model.m(:,indexPresent);
model.m = [model.m; my];
model.N = model.N + Nstar;
d = prod(size(indexPresent));
model.d = d;
model.dynamics.nParams = model.dynamics.nParams + 2*prod(size(vardistx.means));
model.nParams = model.nParams + 2*prod(size(vardistx.means));

vardist2 = model.vardist;
vardist2.means = model.vardist.means(end-Nstar+1:end,:);
vardist2.covars = model.vardist.covars(end-Nstar+1:end,:);
vardist2.nParams = 2*prod(size(vardist2.means));
vardist2.numData = size(vardist2.means,1);
pointPsi0 = kernVardistPsi0Compute(model.kern, vardist2);
pointPsi1 = kernVardistPsi1Compute(model.kern, vardist2, model.X_u);
pointPsi2 = kernVardistPsi2Compute(model.kern, vardist2, model.X_u);
model.Psi1 = [model.Psi1; pointPsi1];
model.Psi2 = model.Psi2 + pointPsi2;
model.Psi0 = model.Psi0 + pointPsi0;

model.C = model.invLm * model.Psi2 * model.invLmT;
%model.TrC = sum(diag(model.C)); % Tr(C)
model.At = (1/model.beta) * eye(size(model.C,1)) + model.C; % At = beta^{-1} I + C
model.Lat = jitChol(model.At)';
model.invLat = model.Lat\eye(size(model.Lat,1));
%model.invLatT = model.invLat';
%model.logDetAt = 2*(sum(log(diag(model.Lat)))); % log |At|
model.P1 = model.invLat * model.invLm; % M x M
model.P = model.P1 * (model.Psi1' * model.m);
%model.TrPP = sum(sum(model.P .* model.P));
model.B = model.P1' * model.P;
%model.invK_uu = model.invLmT * model.invLm;
Tb = (1/model.beta) * model.d * (model.P1' * model.P1);
Tb = Tb + (model.B * model.B');
model.T1 = model.d * model.invK_uu - Tb;

if isfield(model.dynamics, 'reoptimise') && model.dynamics.reoptimise %%% RE-OPT-CODE-NEW
    [gPointDyn2, gDynKern2, gInd2] = vargplvmLogLikeGradientsVar1(model,1); %%% RE-OPT-CODE-NEW
else %%% RE-OPT-CODE-NEW
    gPointDyn2 = vargplvmLogLikeGradientsVar1(model,1);
end %%% RE-OPT-CODE-NEW

gPointDyn2 = reshape(gPointDyn2, model.dynamics.vardist.numData, model.dynamics.q*2);
%gPointDyn2 = gPointDyn2(N+1:end,:);

gPointDyn = gPointDyn1 + gPointDyn2;

%%% RE-OPT-CODE-NEW_
gPointDyn = gPointDyn(:)';
if isfield(model.dynamics, 'reoptimise') && model.dynamics.reoptimise
    gDynKern = gDynKern1 + gDynKern2;
    gInd = gInd1 + gInd2;
    if strcmp(model.dynamics.kern.comp{1}.type,'rbf') || strcmp(model.dynamics.kern.comp{1}.type,'matern32')
        if ~isfield(model.dynamics, 'learnVariance') || ~model.dynamics.learnVariance
            gDynKern(2) = 0;
        end
    end
    gPointDyn = [gPointDyn 0*gDynKern gInd]; %%%%%%%%%% TEMP!!!!
end
%%% _RE-OPT-CODE-NEW

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% --------------------------------------------------------
%function gVar = vargplvmLogLikeGradientsVar1(model, includeKL) %%% RE-OPT-CODE-REM
function [gVar, gDynKern, gInd] = vargplvmLogLikeGradientsVar1(model, includeKL) %%% RE-OPT-CODE-NEW
% Like vargplvmLogLikeGradients but only for the variational parameters (ehm, not exactly). %%% RE-OPT-CODE-MOD

% Likelihood terms (coefficients)
gPsi1 = model.beta * model.m * model.B';
gPsi1 = gPsi1'; % because it is passed to "kernVardistPsi1Gradient" as gPsi1'...
gPsi2 = (model.beta/2) * model.T1;
gPsi0 = -0.5 * model.beta * model.d;

[gKern1, gVarmeans1, gVarcovs1, gInd1] = kernVardistPsi1Gradient(model.kern, model.vardist, model.X_u, gPsi1');
[gKern2, gVarmeans2, gVarcovs2, gInd2] = kernVardistPsi2Gradient(model.kern, model.vardist, model.X_u, gPsi2);
[gKern0, gVarmeans0, gVarcovs0] = kernVardistPsi0Gradient(model.kern, model.vardist, gPsi0);

gVarmeansLik = gVarmeans0 + gVarmeans1 + gVarmeans2;

gVarcovsLik = gVarcovs0 + gVarcovs1 + gVarcovs2;
if includeKL
    %[gVarmeans gVarcovs gDynKern] = modelPriorReparamGrads(model.dynamics, gVarmeansLik, gVarcovsLik);
    % TODO: This may have to be changed if we have model.fixInducing==1.
    [gVarmeans gVarcovs gDynKern] = modelPriorReparamGrads(model.dynamics, gVarmeansLik, gVarcovsLik,[]);
else
    dynModel = model.dynamics;
    gVarmeansLik = reshape(gVarmeansLik,dynModel.N,dynModel.q);
    gVarcovsLik = reshape(gVarcovsLik,dynModel.N,dynModel.q);
    gVarmeans = gVarmeansLik;
    gVarcovs = gVarcovsLik;

    gVarcovs = gVarcovs(:)';
    gVarmeans = gVarmeans(:)';
end

gVarcovs = (gVarcovs(:).*model.dynamics.vardist.covars(:))';
gVar = [gVarmeans gVarcovs];

%%% RE-OPT-CODE-NEW_
if isfield(model.dynamics, 'reoptimise') && model.dynamics.reoptimise
    % Compute Gradients with respect to X_u
    gK_uu = 0.5 * (model.T1 - (model.beta * model.d) * model.invLmT * model.C * model.invLm);
    gKX = kernGradX(model.kern, model.X_u, model.X_u);
    gKX = gKX*2;
    dgKX = kernDiagGradX(model.kern, model.X_u);
    for i = 1:model.k
        gKX(i, :, i) = dgKX(i, :);
    end
    gX_u = zeros(model.k, model.q);
    for i = 1:model.k
        for j = 1:model.q
            gX_u(i, j) = gKX(:, j, i)'*gK_uu(:, i);
        end
    end
    gInd = gInd1 + gInd2 + gX_u(:)';
    if ~includeKL
        gDynKern = [];
    end
end
%%% _RE-OPT-CODE-NEW


function title = p20_title ( option )

%*****************************************************************************80
%
%% P20_TITLE sets the title for problem 20.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 October 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer OPTION, the option index.
%
%    Output, string TITLE, the title of the problem.
%    TITLE will never be longer than 80 characters.
%
  if ( option == 1 )
    title = 'The Buckling Spring, F(L,Theta,Lambda,Mu).';
  else
    title = '???';
    fprintf ( 1, '\n' );
    fprintf ( 1, 'P20_TITLE - Fatal error!\n' );
    fprintf ( 1, '  Unrecognized option number.\n' );
    error ( 'P20_TITLE - Fatal error!' );
  end

  return
end


function tMat = flatLevelTSeries(flat,scan,recomputeFlag);
% tMat = flatLevelTSeries(flat,[scan,recomputeFlag]);
%
% For Flat multi-level views:
%
% Create a 4D array of size x by y by slices by time,
% with the values from the tSeries interpolated across
% the (unmasked) flat mesh for each slice/time point.
% Also compute the mean image across levels for each
% hemisphere/time point.
%
% flat: flat view
%
% tSeries: tSeries for the flat view. If not
% entered, gets it from the view.
%
% scan: number of scan for tSeries. Defaults to
% current scan.
%
% recomputeFlag: if 1, will recompute even if a saved
% file already exists with the data. (Otherwise, will
% check and load existing files rather than recomputing.)
%
% Will also save a file 'interpolatedTSeries' in
% the scan's tSeries directory with the 4D matrix,
% as well as the appropriate coords/indices for
% mapping back and forth between the measured
% points on the flat map (in the normal tSeries
% files) and the interpolated image (same format
% as anat/amp/co/ph/map).
%
% ras, 10/2004
tic

if ieNotDefined('scan')
    scan = getCurScan(flat);
end

if ieNotDefined('recomputeFlag')
    recomputeFlag = 0;
end

% params
imageSize = flat.ui.imSize;
nSlices = 2 + sum(flat.numLevels);
nFrames = numFrames(flat,scan);
numLevels = flat.numLevels;
mask = flat.ui.mask;
savePath = fullfile(tSeriesDir(flat),sprintf('Scan%i',scan),'interpolatedTSeries.mat');

% check if the file already exists
% -- if so, load it and skip the computation:
if recomputeFlag==0 & exist(savePath,'file')
    fprintf('Loading %s ...\n',savePath);
    load(savePath,'tMat');
    return
end

% combine coords across hemispheres,
% get indices for going the reverse direction
coords = flat.coords;
indices = flat.indices;

% initialize the 4D array -- if there are memory
% constraints, this will hopefully give a hint:
% tMat = zeros(imageSize(1),imageSize(2),nSlices,nFrames);

% (There are --- making it a uint16 to reduce the load):
for i = 1:nFrames
    tMat(:,:,:,i) = uint16(zeros(imageSize(1),imageSize(2),nSlices));
end

%% get the min and max value for uint8 scaling ;(
%minVal = min(tSeries(find(tSeries)))
%maxVal = max(tSeries(find(tSeries)))

skipSlices = [];

waitHandle = mrvWaitbar(0,'Computing mean tSeries across gray levels...');
set(waitHandle,'Units','Normalized');
pos = get(waitHandle,'Position');
set(waitHandle,'Position',pos+[0 .1 0 0]);

for slice = 1:nSlices
    % load the tSeries slice
    tData = loadtSeries(flat,scan,slice);

        % need to figure out the hemisphere for this slice
        if slice==1 | (slice>2 & slice<=2+numLevels(1))
            h = 1;
        else
            h = 2;
        end

        % get coordinates from this slice
        subCoords = coords{slice}(1:2,:);

    if size(subCoords,2) < 10
        skipSlices = [skipSlices slice];
    else

        % interpolate each frame in tMat
        sliceWait = mrvWaitbar(0,'Interpolating slice across frames...');
        for t = 1:nFrames
            vals = tData(t,:);

            % The operator .' is the NON-CONJUGATE transpose.  Very important.
            tMat(:,:,slice,t) = myGriddata(subCoords,vals.',mask(:,:,h));

            mrvWaitbar(t/nFrames,sliceWait);
        end
    close(sliceWait);

    end

    mrvWaitbar(slice/nSlices,waitHandle);
end

close(waitHandle);

% % remove skipped slices
% tMat = tMat(:,:,setdiff(1:nSlices,skipSlices),:);

% save the 4D matrix
save(savePath,'tMat','coords','indices'); %,'minVal','maxVal');
fprintf('Saved %s. \n',savePath);

toc

return

% % % if arg out is specified, sample
% % % the mean tSeries at the data points
% % % measured (specified in coords/indices):
%  if nargout > 0
%  	waitHandle = mrvWaitbar(0,'Grabbing the mean tSeries...');
%
%  	for h = 1:2
%          % find coordinates of mean tSeries for this hemi
%          subCoords = find(coords(3,:)==h);
%
%         % get the indices for measured points for this hemi
%         measured = indices(find(indices(:,:,h)));
%
%         % error check: subCoords and measured should
%         % represent the same voxels:
%         [size(subCoords) size(measured)]
%         if size(subCoords)~=size(measured)
%             error('Logical error -- size mismatch b/w subCoords & measured.')
%         end
%
%         % I'll attempt to do a (fast) one-shot re-indexing,
%         % across time, but this requires that the indices be
%         % specified correctly. Replicate the 2D row/column
%         % specifications to run across frames, then get a
%         % single index into the big 4D matrix:
%         [x y] = ind2sub([imageSize(1) imageSize(2)],measured);
%         x = repmat(x,[1 nFrames]);
%         y = repmat(y,[1 nFrames]);
%         z = repmat(h,size(x));
%         t = repmat(1:nFrames,[length(measured) 1])';
%         t = t(:);
%         subIndices = sub2ind(size(tMat),x,y,z,t);
%
%         % assign the tSeries from the measured points
%         % (first convert back from uint8 to double)
%         subData = tMat(subIndices);
%         subData = minVal + maxVal .* double(subData);
%         tSeries(:,subCoords) = subData; % check for inaccuracies
%
%         mrvWaitbar(h/2,waitHandle);
%     end
%
%     close(waitHandle);
% end


% Copyright (C) 2017-2018 Titus Cieslewski, RPG, University of Zurich,
%   Switzerland
%   You can contact the author at <titus at ifi dot uzh dot ch>
% Copyright (C) 2017-2018 Siddharth Choudhary, College of Computing,
%   Georgia Institute of Technology, Atlanta, GA, USA
% Copyright (C) 2017-2018 Davide Scaramuzza, RPG, University of Zurich,
%   Switzerland
%
% This file is part of dslam_open.
%
% dslam_open is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% dslam_open is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with dslam_open. If not, see <http://www.gnu.org/licenses/>.

function arrow = poseToQuiver(T)
arrow = zeros(1, 6);
arrow(1) = T(1,4);
arrow(2) = T(2,4);
arrow(3) = T(3,4);
arrow(4) = T(1,1);
arrow(5) = T(2,1);
arrow(6) = T(3,1);
end


function view_components(Y,A,C,b,f,Cn,options)

% plot spatial components and temporal traces against filtered background
% Y:        raw data
% A:        spatial footprints
% C:        temporal components
% b:        spatial background
% f:        temporal background
% Cn:       background image (default: mean image)
% options:  options structure

% Written by:
% Eftychios A. Pnevmatikakis, Simons Foundation, 2015

defoptions = CNMFSetParms;
memmaped = isobject(Y);
if nargin < 7 || isempty(options); options = defoptions; end
if ~isfield(options,'d1') || isempty(options.d1); d1 = input('What is the total number of rows? \n'); else d1 = options.d1; end          % # of rows
if ~isfield(options,'d2') || isempty(options.d2); d2 = input('What is the total number of columns? \n'); else d2 = options.d2; end          % # of columns
% if ~isfield(options,'normalize') || isempty(options.normalize); options.normalize = ones(size(A,1),1); end
%     sn = options.normalize;
if ~isfield(options,'plot_df') || isempty(options.plot_df); options.df = defoptions.plot_df; end
    plot_df = options.plot_df;
if ~isfield(options,'make_gif') || isempty(options.make_gif); options.make_gif = defoptions.make_gif; end
    make_gif = options.make_gif;
if ~isfield(options,'save_avi') || isempty(options.save_avi); options.save_avi = defoptions.save_avi; end
    save_avi = options.save_avi;
if ~isfield(options,'sx') || isempty(options.sx); options.sx = defoptions.sx; end
    sx = min([options.sx,floor(d1/2),floor(d2/2)]);
if ~isfield(options,'pause_time') || isempty(options.pause_time); options.pause_time = defoptions.pause_time; end
    pause_time = options.pause_time;
if isfield(options,'name') && ~isempty(options.name);
    name = [options.name,'_components'];
else
    name = [defoptions.name,'_components'];
end
if ~isfield(options,'full_A') || isempty(options.full_A); full_A = defoptions.full_A; else full_A = options.full_A; end

T = size(C,2);
if ndims(Y) == 3
    Y = reshape(Y,d1*d2,T);
end
if nargin < 6 || isempty(Cn);
    Cn = reshape(mean(Y,2),d1,d2);
end

nA = sqrt(sum(A.^2))';
[K,~] = size(C);
A = A/spdiags(nA,0,K,K);    % normalize spatial components to unit energy
C = spdiags(nA,0,K,K)*C;

nr = size(A,2);     % number of ROIs
nb = size(f,1);     % number of background components
%nA = full(sum(A.^2))';  % energy of each row
%Y_r = spdiags(nA,0,nr,nr)\(A'*Y- (A'*A)*C - (A'*full(b))*f) + C;
step = 5e3;
if memmaped
    AY = zeros(K,T);
    for i = 1:step:d
        AY = AY + A(i:min(i+step-1,d),:)'*double(Y.Yr(i:min(i+step-1,d),:));
    end
else
    if issparse(A) && isa(Y,'single')
        if full_A
            AY = full(A)'*Y;
        else
            AY = A'*double(Y);
        end
    else
        AY = A'*Y;
    end
end
Y_r = (AY- (A'*A)*C - full(A'*double(b))*f) + C;

if plot_df
    %[~,Df] = extract_DF_F(Y,[A,b],[C;f],size(A,2)+1);
    [~,Df] = extract_DF_F(Y,A,C,[],options);
else
    Df = ones(size(A,2)+1,1);
end

if save_avi
    vidObj = VideoWriter([name,'.avi']);
    set(vidObj,'FrameRate',1);
    open(vidObj);
end
thr = 0.9;
fig = figure;
    set(gcf,'Position',2*[300,300,960,480]);
    set(gcf,'PaperPosition',2*[300,300,960,480]);
    int_x = zeros(nr,2*sx);
    int_y = zeros(nr,2*sx);
    cm = com(A,d1,d2);
for i = 1:nr+nb
    if i <= nr
    subplot(3,2,5);
        Atemp = reshape(A(:,i),d1,d2);
        int_x(i,:) = round(cm(i,1)) + (-(sx-1):sx);
        if int_x(i,1)<1
            int_x(i,:) = int_x(i,:) + 1 - int_x(i,1);
        end
        if int_x(i,end)>d1
            int_x(i,:) = int_x(i,:) - (int_x(i,end)-d1);
        end
        int_y(i,:) = round(cm(i,2)) + (-(sx-1):sx);
        if int_y(i,1)<1
            int_y(i,:) = int_y(i,:) + 1 - int_y(i,1);
        end
        if int_y(i,end)>d2
            int_y(i,:) = int_y(i,:) - (int_y(i,end)-d2);
        end
        Atemp = Atemp(int_x(i,:),int_y(i,:));
        imagesc(int_x(i,:),int_y(i,:),Atemp); axis square;
    end
    subplot(3,2,[1,3]);
    if i <= nr
        imagesc(2*Cn); axis equal; axis tight; axis off; hold on;
        A_temp = full(reshape(A(:,i),d1,d2));
        A_temp = medfilt2(A_temp,[3,3]);
        A_temp = A_temp(:)/norm(A_temp(:));
        [temp,ind] = sort(A_temp(:).^2,'ascend');
        temp =  cumsum(temp);
        ff = find(temp > (1-thr)*temp(end),1,'first');
        if ~isempty(ff)
            [~,ww] = contour(reshape(A_temp,d1,d2),[0,0]+A_temp(ind(ff)),'LineColor','k');
            ww.LineWidth = 2;
        end
        title(sprintf('Component %i ',i),'fontsize',16,'fontweight','bold'); drawnow; %pause;
    else
        imagesc(reshape(b(:,i-nr),d1,d2)); axis equal; axis tight;
        title('Background component','fontsize',16,'fontweight','bold'); drawnow;
    end
    subplot(3,2,[2,4,6]);
    if i <= nr
        plot(1:T,Y_r(i,:)/Df(i),'linewidth',2); hold all; plot(1:T,C(i,:)/Df(i),'linewidth',2);
        if plot_df
            title(sprintf('Component %i (calcium DF/F value)',i),'fontsize',16,'fontweight','bold');
        else
            title(sprintf('Component %i (calcium raw value)',i),'fontsize',16,'fontweight','bold');
        end
        leg = legend('Raw trace (filtered)','Inferred');
        set(leg,'FontSize',14,'FontWeight','bold');
        drawnow;
        hold off;
        if make_gif
            frame = getframe(fig); %getframe(1);
              im = frame2im(frame);
              [imind,clm] = rgb2ind(im,256);
              if i == 1;
                  imwrite(imind,clm,[name,'.gif'],'gif', 'Loopcount',inf);
              else
                  imwrite(imind,clm,[name,'.gif'],'gif','WriteMode','append');
              end
        else
            if i < nr+nb && ~save_avi
                fprintf('component %i. Press any key to continue.. \n', i);
                if pause_time == Inf;
                    pause;
                else
                    pause(pause_time);
                end
            end
        end
    else
        plot(1:T,f(i-nr,:)); title('Background activity','fontsize',16,'fontweight','bold');
        drawnow;
        if make_gif
            frame = getframe(fig); %getframe(1);
              im = frame2im(frame);
              [imind,clm] = rgb2ind(im,256);
              if i == 1;
                  imwrite(imind,clm,[name,'.gif'],'gif', 'Loopcount',inf);
              else
                  imwrite(imind,clm,[name,'.gif'],'gif','WriteMode','append');
              end
        else
            if i < nr+nb && ~save_avi
                fprintf('background component %i. Press any key to continue.. \n', i-nr);
                if pause_time == Inf;
                    pause;
                else
                    pause(pause_time);
                end
            end
        end
    end
    if save_avi
        currFrame = getframe(fig);
        writeVideo(vidObj,currFrame);
    else
        pause(0.05);
    end

end

if save_avi
    close(vidObj);
end


function [rmain,r1]= ReasInteract(var1,newcat,rfact,xmeff)

	%ORIGINAL FROM ZMAP: NEEDS WORK FOR MAPSEIS
	%SUBFUNCTION: ReasenbergDeclus.m MIGHT NOT BE NEEDED
	%---------------------------------------------------

	%--------->NOT REALLY NEEDED

	%interact.m                                        A.Allmann
	% calculates the interaction zones of the earthquakes
	% in [km]
	%Last modification 6/95

	%global newcat rfact xmeff

	if var1==1
		rmain = 0.011*10.^(0.4*newcat(:,6)); %interaction zone for mainshock
		%rmain = 10.^(-2.44+(.59*newcat(:,6)));

		%tm1=find(rmain==0.011);             %these eqs got no magnitude in the catalog
		%tm2= 0.011*10^(0.4*xmeff);          %assume that for eqs with magnitude 0
		%rmain(tm1)=tm2*ones(1,length(tm1)); %the real magnitude is around xmeff

		r1    =rfact*rmain;                  %interaction zone if included in a cluster

	end

	%That function can be directly integrated it consist out of two functions anyway (DE)

end


% pop_newtimef() - Returns estimates and plots of event-related (log) spectral
%           perturbation (ERSP) and inter-trial coherence (ITC) changes
%           timelocked to a set of input events in one data channel.
%
% Usage:
%   >> pop_newtimef(EEG, typeplot); % pop_up window
%   >> pop_newtimef(EEG, typeplot, lastcom); % pop_up window
%   >> pop_newtimef(EEG, typeplot, channel); % do not pop-up
%   >> pop_newtimef(EEG, typeproc, num, tlimits,cycles,
%                        'key1',value1,'key2',value2, ... );
%
% Inputs:
%   INEEG    - input EEG dataset
%   typeproc - type of processing. 1 process the raw
%              data and 0 the ICA components
%   num      - component or channel number
%   tlimits  - [mintime maxtime] (ms) sub-epoch time limits
%   cycles   -  >0 -> Number of cycles in each analysis wavelet
%               0 -> Use FFTs (with constant window length)
%
% Optional inputs:
%    See the newtimef() function.
%
% Outputs: same as newtimef(), no outputs are returned when a
%          window pops-up to ask for additional arguments
%
% Getting the ERSP and ITC output values:
% Simply look up the history using the eegh function (type eegh).
% Then copy and paste the pop_newtimef command call and manually add output
% (see the newtimef function for a list of outputs). For instance
% [ersp itc powbase times frequencies] = pop_newtimef( EEG, ....);
%
% Author: Arnaud Delorme, CNL / Salk Institute, 2001
%
% See also: newtimef(), eeglab()

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

% 01-25-02 reformated help & license -ad
% 03-08-02 add eeglab option & optimize variable sizes -ad
% 03-10-02 change newtimef call -ad
% 03-18-02 added title -ad & sm
% 04-04-02 added outputs -ad & sm

function varargout = pop_newtimef(EEG, typeproc, num, tlimits, cycles, varargin );

varargout{1} = '';
% display help if not enough arguments
% ------------------------------------
if nargin < 2
	help pop_newtimef;
	return;
end;
lastcom = [];
if nargin < 3
	popup = 1;
else
	popup = isstr(num) | isempty(num);
	if isstr(num)
		lastcom = num;
	end;
end;

% pop up window
% -------------
if popup
	[txt vars] = gethelpvar('newtimef.m');

    g = [1 0.3 0.6 0.34];
	geometry = { g g g g g g g g [1.025 1.27] [1] [1.2 1 1.2]};
    uilist = { ...
               { 'Style', 'text', 'string', fastif(typeproc, 'Channel number', 'Component number'), 'fontweight', 'bold'  } ...
			   { 'Style', 'edit', 'string', getkeyval(lastcom,3,[],'1') 'tag' 'chan'} {} {} ...
               ...
			   { 'Style', 'text', 'string', 'Sub epoch time limits [min max] (msec)', 'fontweight', 'bold' } ...
			   { 'Style', 'edit', 'string', getkeyval(lastcom,4,[],[ int2str(EEG.xmin*1000) ' ' int2str(EEG.xmax*1000) ]) 'tag' 'tlimits' } ...
               { 'Style', 'popupmenu', 'string', 'Use 50 time points|Use 100 time points|Use 150 time points|Use 200 time points|Use 300 time points|Use 400 time points' 'tag' 'ntimesout' 'value' 4} { } ...
			   ...
			   { 'Style', 'text', 'string', 'Frequency limits [min max] (Hz) or sequence', 'fontweight', 'bold' } ...
			   { 'Style', 'edit', 'string', '' 'tag' 'freqs'  } ...
               { 'Style', 'popupmenu', 'string', 'Use limits, padding 1|Use limits, padding 2|Use limits, padding 4|Use actual freqs.' 'tag' 'nfreqs' }  ...
               { 'Style', 'checkbox', 'string' 'Log spaced' 'value' 0 'tag' 'freqscale' } ...
			   ...
			   { 'Style', 'text', 'string', 'Baseline limits [min max] (msec) (0->pre-stim.)', 'fontweight', 'bold' } ...
			   { 'Style', 'edit', 'string', '0' 'tag' 'baseline' } ...
			   { 'Style', 'popupmenu',  'string', 'Use divisive baseline|Use standard deviation' 'tag' 'basenorm' } ...
               { 'Style', 'checkbox', 'string' 'No baseline' 'tag' 'nobase' } ...
               ...
               { 'Style', 'text', 'string', 'Wavelet cycles [min max/fact] or sequence', 'fontweight', 'bold' } ...
               { 'Style', 'edit', 'string', getkeyval(lastcom,5,[],'3 0.5') 'tag' 'cycle' } ...
               { 'Style', 'popupmenu', 'string', 'Use limits|Use actual seq.' 'tag' 'ncycles' } ...
               { 'Style', 'checkbox', 'string' 'Use FFT' 'value' 0 'tag' 'fft' } ...
			   ...
			   { 'Style', 'text', 'string', 'ERSP color limits [max] (min=-max)', 'fontweight', 'bold' } ...
               { 'Style', 'edit', 'string', '' 'tag' 'erspmax'} ...
               { 'Style', 'checkbox', 'string' 'see log power (set)' 'tag' 'scale' 'value' 1} {} ...
			   ...
			   { 'Style', 'text', 'string', 'ITC color limits [max]', 'fontweight', 'bold' } ...
               { 'Style', 'edit', 'string', '' 'tag' 'itcmax'} ...
               { 'Style', 'checkbox', 'string' 'plot ITC phase (set)' 'tag' 'plotphase' } {} ...
			   ...
			   { 'Style', 'text', 'string', 'Bootstrap significance level (Ex: 0.01 -> 1%)', 'fontweight', 'bold' } ...
               { 'Style', 'edit', 'string', getkeyval(lastcom,'alpha') 'tag' 'alpha'} ...
               { 'Style', 'checkbox', 'string' 'FDR correct (set)' 'tag' 'fdr' } {} ...
			   ...
			   { 'Style', 'text', 'string', 'Optional newtimef() arguments (see Help)', 'fontweight', 'bold', ...
				 'tooltipstring', 'See newtimef() help via the Help button on the right...' } ...
			   { 'Style', 'edit', 'string', '' 'tag' 'options' } ...
			   {} ...
			   { 'Style', 'checkbox', 'value', ~getkeyval(lastcom,'plotersp','present',0), 'string', ...
				 'Plot Event Related Spectral Power', 'tooltipstring', ...
				 'Plot log spectral perturbation image in the upper panel' 'tag' 'plotersp' } ...
			   { 'Style', 'checkbox', 'value', ~getkeyval(lastcom,'plotitc','present',0), 'string', ...
				 'Plot Inter Trial Coherence', 'tooltipstring', ...
				 'Plot the inter-trial coherence image in the lower panel' 'tag' 'plotitc' } ...
			   { 'Style', 'checkbox', 'value', 0, 'string', ...
				 'Plot curve at each frequency' 'tag' 'plotcurve' } ...
			 };
      % { 'Style', 'edit', 'string', '''padratio'', 4, ''plotphase'', ''off''' } ...
			   %{ 'Style', 'text', 'string',  '[set] -> Plot ITC phase sign', 'fontweight', 'bold', ...
			%	 'tooltipstring', ['Plot the sign (+/-) of inter-trial coherence phase' 10 ...
			%		'as red (+) or blue (-)'] } ...
			%   { 'Style', 'checkbox', 'value', ~getkeyval(lastcom,'plotphase','present',1) } { } ...

	[ tmp1 tmp2 strhalt result ] = inputgui( geometry, uilist, 'pophelp(''pop_newtimef'');', ...
					   fastif(typeproc, 'Plot channel time frequency -- pop_newtimef()', ...
							  'Plot component time frequency -- pop_newtimef()'));
	if length( tmp1 ) == 0 return; end;

	if result.fft,      result.cycle = '0'; end;
	if result.nobase,   result.baseline = 'NaN'; end;

	num	     = eval( [ '[' result.chan    ']' ] );
	tlimits	 = eval( [ '[' result.tlimits ']' ] );
	cycles	 = eval( [ '[' result.cycle   ']' ] );
    freqs    = eval( [ '[' result.freqs   ']' ] );
    %result.ncycles == 2 is ignored

    % add topoplot
    % ------------
    options = [];
    if isfield(EEG.chanlocs, 'theta')
        if ~isfield(EEG, 'chaninfo'), EEG.chaninfo = []; end;
        if typeproc == 1
            options = [options ', ''topovec'', ' int2str(num) ...
                        ', ''elocs'', EEG.chanlocs, ''chaninfo'', EEG.chaninfo' ];
        else
            options = [options ', ''topovec'', EEG.icawinv(:,' int2str(num) ...
                       '), ''elocs'', EEG.chanlocs, ''chaninfo'', EEG.chaninfo' ];
      end;
    end;

	if ~isempty( result.baseline ),  options = [ options ', ''baseline'',[' result.baseline ']' ]; end;
    if ~isempty( result.alpha ),     options = [ options ', ''alpha'',' result.alpha ];   end;
	if ~isempty( result.options ),   options = [ options ',' result.options ];            end;
	if ~isempty( result.freqs ),     options = [ options ', ''freqs'', [' result.freqs ']'   ]; end;
	if ~isempty( result.erspmax ),   options = [ options ', ''erspmax'', [' result.erspmax ']' ]; end;
	if ~isempty( result.itcmax ),    options = [ options ', ''itcmax'','  result.itcmax ];      end;
	if ~result.plotersp,             options = [ options ', ''plotersp'', ''off''' ];     end;
	if ~result.plotitc,              options = [ options ', ''plotitc'' , ''off''' ];     end;
	if result.plotcurve,             options = [ options ', ''plottype'', ''curve''' ];   end;
	if result.fdr,                   options = [ options ', ''mcorrect'', ''fdr''' ];     end;
	if result.freqscale,             options = [ options ', ''freqscale'', ''log''' ];    end;
	if ~result.plotphase,            options = [ options ', ''plotphase'', ''off''' ];    end;
	if ~result.scale,                options = [ options ', ''scale'', ''abs''' ];        end;
    if result.basenorm == 2,         options = [ options ', ''basenorm'', ''on''' ];      end;
    if result.ntimesout == 1,        options = [ options ', ''ntimesout'', 50' ];         end;
    if result.ntimesout == 2,        options = [ options ', ''ntimesout'', 100' ];        end;
    if result.ntimesout == 3,        options = [ options ', ''ntimesout'', 150' ];        end;
    if result.ntimesout == 5,        options = [ options ', ''ntimesout'', 300' ];        end;
    if result.ntimesout == 6,        options = [ options ', ''ntimesout'', 400' ];        end;
    if result.nfreqs == 1,           options = [ options ', ''padratio'', 1' ];           end;
    if result.nfreqs == 2,           options = [ options ', ''padratio'', 2' ];           end;
    if result.nfreqs == 3,           options = [ options ', ''padratio'', 4' ];           end;
    if result.nfreqs == 4,           options = [ options ', ''nfreqs'', ' int2str(length(freqs)) ]; end;

    % add title
    % ---------
	if isempty( findstr(  '''title''', result.options))
        if ~isempty(EEG.chanlocs) & typeproc
            chanlabel = EEG.chanlocs(num).labels;
        else
            chanlabel = int2str(num);
        end;
	end;

	figure; try, icadefs; set(gcf, 'color', BACKCOLOR); catch, end;
else
    options = [ ',' vararg2str(varargin) ];
end;

% compute epoch limits
% --------------------
if isempty(tlimits)
	tlimits = [EEG.xmin, EEG.xmax]*1000;
end;
pointrange1 = round(max((tlimits(1)/1000-EEG.xmin)*EEG.srate, 1));
pointrange2 = round(min((tlimits(2)/1000-EEG.xmin)*EEG.srate, EEG.pnts));
pointrange = [pointrange1:pointrange2];

% call function sample either on raw data or ICA data
% ---------------------------------------------------
if typeproc == 1
	tmpsig = EEG.data(num,pointrange,:);
else
	if ~isempty( EEG.icasphere )
        eeglab_options; % changed from eeglaboptions 3/30/02 -sm
 	    if option_computeica
    		tmpsig = EEG.icaact(num,pointrange,:);
 	    else
            tmpsig = (EEG.icaweights(num,:)*EEG.icasphere)*reshape(EEG.data(:,pointrange,:), EEG.nbchan, EEG.trials*length(pointrange));
        end;
	else
		error('You must run ICA first');
	end;
end;
tmpsig = reshape( tmpsig, length(num), size(tmpsig,2)*size(tmpsig,3));

% outputs
% -------
outstr = '';
if ~popup
    for io = 1:nargout, outstr = [outstr 'varargout{' int2str(io) '},' ]; end;
    if ~isempty(outstr), outstr = [ '[' outstr(1:end-1) '] =' ]; end;
end;

% plot the datas and generate output command
% --------------------------------------------
if length( options ) < 2
    options = '';
end;
if nargin < 4
    varargout{1} = sprintf('figure; pop_newtimef( %s, %d, %d, [%s], [%s] %s);', inputname(1), typeproc, num, ...
			int2str(tlimits), num2str(cycles), options);
end;
com = sprintf('%s newtimef( tmpsig(:, :), length(pointrange), [tlimits(1) tlimits(2)], EEG.srate, cycles %s);', outstr, options);
eval(com)

return;

% get contextual help
% -------------------
function txt = context(var, allvars, alltext);
	loc = strmatch( var, allvars);
	if ~isempty(loc)
		txt= alltext{loc(1)};
	else
		disp([ 'warning: variable ''' var ''' not found']);
		txt = '';
	end;


function noise = gaussianNoiseExpandParam(noise, params)

% GAUSSIANNOISEEXPANDPARAM Create noise structure from GAUSSIAN noise's parameters.
% FORMAT
% DESC returns a Gaussian noise structure filled with the
% parameters in the given vector. This is used as a helper function to
% enable parameters to be optimised in, for example, the NETLAB
% optimisation functions.
% ARG noise : the noise structure in which the parameters are to be
% placed.
% ARG param : vector of parameters which are to be placed in the
% noise structure.
% RETURN noise : noise structure with the given parameters in the
% relevant locations.
%
% SEEALSO : gaussianNoiseParamInit, gaussianNoiseExtractParam, noiseExpandParam
%
% COPYRIGHT : Neil D. Lawrence, 2004, 2005

% NOISE

noise.bias = params(1:end-1);
noise.sigma2 = params(end);


%% housekeeping
close all
clear
clc
%% Information for the title page

% N.B: Be careful with the "_" it has to be escaped with a "\" in order for
% latex to process it as we wish.

rep_data=struct();
myfields={'name','title','address','author','email','abstract'};

rep_data.name='newkeynesswitch'; % Name under which the report will be saved
rep_data.title='Switches in the US Macroeconomic Data: Policy or Volatility?';
rep_data.address='Your institution';
rep_data.author='first\_name last\_name'; % your name
rep_data.email='first\_name@last\_name.com'; % your email
myabstract={['This report investigates switches in the parameters of a ',...
    ' simple new Keynesian model estimated on US data. 4 variants of the model',...
    'are estimated: (i) the first variant allows for switches in volalitily only; ',...
    '(ii) the second model allows for switches in the policy parameters only; ',...
    '(iii) the third specification allows for switches in both policy parameters ',...
    'and the volatility of shocks, but in a synchronized fashion; (iv) the ',...
    'third variant allows for independent switches in both parameters and the ',...
    'volatility of shocks.']
    ' ' % leave a blank space to start the next sentence in a new line
    'We find ample evidence in favor of switching parameters... '
    };
rep_data.abstract=myabstract;
%% load the estimated models and relabel them if necessary
nk_models={'volatilityOnly','policyOnly','volatilityPolicySame','volatilityPolicyIndependent'};
nk_models_newlabels={'volOnly','polOnly','volPolSame','volPolInd'};

model_objects=rise.empty(0);
for imod=1:numel(nk_models)
    tmp=load([nk_models{imod},filesep,'estimation',filesep,'estimated_model']);
    obj=tmp.obj;
    model_objects(imod,1)=obj;
    model_objects(imod,1).legend=nk_models_newlabels{imod};
end
Tao_report(model_objects,rep_data)


%kmlud 'Compute LU Decomposition of Matrix (Input = L*U)'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros mlud.pane file
%
% Parameters:
% InputFile: i 'Input ', required: 'Input matrix'
% OutputFile: o1 'Lower Triangular Matrix', optional: 'Resulting lower triangular output matrix'
% OutputFile: o2 'Upper Triangular Matrix', optional: 'Resulting upper triangular output matrix'
% OutputFile: o3 'Pivot Index Vector', optional: 'Pivot index vector'
%
% Example: [o1, o2, o3] = kmlud(i, {'i','';'o1','';'o2','';'o3',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% mlud - Compute LU Decomposition of Matrix  (Input = L*U)
%
%  DESCRIPTION
% .I mlud
% computes the LU decomposition of a matrix with partial pivoting and
% row interchanges.  If A is the input matrix, "mlud\fR will solve
% the system P*L*U = A for the L and U matrices. The P matrix is
% represented on output by a pivot index vector PI, where row i has been
% interchanged with row PI[i].  U is an upper
% triangular matrix, and L lower triangular with unit diagonal. PI is of length
% min(rows,cols).  The LAPACK routines DGETRF and ZGETRF are used to perform
% the actual decomposition.
%
% After execution of the appropriate LAPACK routine, a diagnostic may be
% printed out indicating that the input matrix is singular and at what point
% this was detected. This will be printed only if KHOROS_NOTIFY is set to
% STANDARD or more verbosity. This message is NOT an error, just information,
% and "mlud\fR will run to completion anyway.
%
%
%
%  EXAMPLES
%
%  "SEE ALSO"
%
%  RESTRICTIONS
%
%  REFERENCES
% LAPACK Users' Guide, E. Anderson et. al., SIAM 1992. ISBN 0-89871-294-7
%
%  COPYRIGHT
% Copyright (C) 1993 - 1997, Khoral Research, Inc. ("KRI")  All rights reserved.
%

function varargout = kmlud(varargin)
if nargin ==0
  Inputs={};arglist={'',''};
elseif nargin ==1
  Inputs=varargin{1};arglist={'',''};
elseif nargin ==2
  Inputs=varargin{1}; arglist=varargin{2};
else error('Usage: [out1,..] = kmlud(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'i', '__input';'o1', '__output';'o2', '__output';'o3', '__output'};
maxval={0,1,1,1};
minval={0,1,1,1};
istoggle=[0,1,1,1];
was_set=istoggle * 0;
paramtype={'InputFile','OutputFile','OutputFile','OutputFile'};
% identify the input arrays and assign them to the arguments as stated by the user
if ~iscell(Inputs)
Inputs = {Inputs};
end
NumReqOutputs=0; nextinput=1; nextoutput=1;
  for ii=1:size(arglist,1)
  wasmatched=0;
  for jj=1:size(narglist,1)
   if strcmp(arglist{ii,1},narglist{jj,1})  % a given argument was matched to the possible arguments
     wasmatched = 1;
     was_set(jj) = 1;
     if strcmp(narglist{jj,2}, '__input')
      if (nextinput > length(Inputs))
        error(['Input ' narglist{jj,1} ' has no corresponding input!']);
      end
      narglist{jj,2} = 'OK_in';
      nextinput = nextinput + 1;
     elseif strcmp(narglist{jj,2}, '__output')
      if (nextoutput > nargout)
        error(['Output nr. ' narglist{jj,1} ' is not present in the assignment list of outputs !']);
      end
      if (isempty(arglist{ii,2}))
        narglist{jj,2} = 'OK_out';
      else
        narglist{jj,2} = arglist{ii,2};
      end

      nextoutput = nextoutput + 1;
      if (minval{jj} == 0)
         NumReqOutputs = NumReqOutputs - 1;
      end
     elseif isstr(arglist{ii,2})
      narglist{jj,2} = arglist{ii,2};
     else
        if strcmp(paramtype{jj}, 'Integer') & (round(arglist{ii,2}) ~= arglist{ii,2})
            error(['Argument ' arglist{ii,1} ' is of integer type but non-integer number ' arglist{ii,2} ' was supplied']);
        end
        if (minval{jj} ~= 0 | maxval{jj} ~= 0)
          if (minval{jj} == 1 & maxval{jj} == 1 & arglist{ii,2} < 0)
            error(['Argument ' arglist{ii,1} ' must be bigger or equal to zero!']);
          elseif (minval{jj} == -1 & maxval{jj} == -1 & arglist{ii,2} > 0)
            error(['Argument ' arglist{ii,1} ' must be smaller or equal to zero!']);
          elseif (minval{jj} == 2 & maxval{jj} == 2 & arglist{ii,2} <= 0)
            error(['Argument ' arglist{ii,1} ' must be bigger than zero!']);
          elseif (minval{jj} == -2 & maxval{jj} == -2 & arglist{ii,2} >= 0)
            error(['Argument ' arglist{ii,1} ' must be smaller than zero!']);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} < minval{jj})
            error(['Argument ' arglist{ii,1} ' must be bigger than ' num2str(minval{jj})]);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} > maxval{jj})
            error(['Argument ' arglist{ii,1} ' must be smaller than ' num2str(maxval{jj})]);
          end
        end
     end
     if ~strcmp(narglist{jj,2},'OK_out') &  ~strcmp(narglist{jj,2},'OK_in')
       narglist{jj,2} = arglist{ii,2};
     end
   end
   end
   if (wasmatched == 0 & ~strcmp(arglist{ii,1},''))
        error(['Argument ' arglist{ii,1} ' is not a valid argument for this function']);
   end
end
% match the remaining inputs/outputs to the unused arguments and test for missing required inputs
 for jj=1:size(narglist,1)
     if  strcmp(paramtype{jj}, 'Toggle')
        if (narglist{jj,2} ==0)
          narglist{jj,1} = '';
        end;
        narglist{jj,2} = '';
     end;
     if  ~strcmp(narglist{jj,2},'__input') && ~strcmp(narglist{jj,2},'__output') && istoggle(jj) && ~ was_set(jj)
          narglist{jj,1} = '';
          narglist{jj,2} = '';
     end;
     if strcmp(narglist{jj,2}, '__input')
      if (minval{jj} == 0)  % meaning this input is required
        if (nextinput > size(Inputs))
           error(['Required input ' narglist{jj,1} ' has no corresponding input in the list!']);
        else
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        end
      else  % this is an optional input
        if (nextinput <= length(Inputs))
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end;
     else
     if strcmp(narglist{jj,2}, '__output')
      if (minval{jj} == 0) % this is a required output
        if (nextoutput > nargout & nargout > 1)
           error(['Required output ' narglist{jj,1} ' is not stated in the assignment list!']);
        else
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
          NumReqOutputs = NumReqOutputs-1;
        end
      else % this is an optional output
        if (nargout - nextoutput >= NumReqOutputs)
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end
     end
  end
end
if nargout
   varargout = cell(1,nargout);
else
  varargout = cell(1,1);
end
global KhorosRoot
if exist('KhorosRoot') && ~isempty(KhorosRoot)
w=['"' KhorosRoot];
else
if ispc
  w='"C:\Program Files\dip\khorosBin\';
else
[s,w] = system('which cantata');
w=['"' w(1:end-8)];
end
end
[varargout{:}]=callKhoros([w 'mlud"  '],Inputs,narglist);


function v=simple_endo_priors(obj,filtration) %#ok<INUSD>

% this file demonstrates how to setup a simple endogenous prior problem

nconstr=5;

is_initial=nargin==0;

if is_initial

    v = cell(nconstr,1);

else

    myirfs=irf(obj);

    C_A=double(myirfs.EPS_A.C);

    v = zeros(nconstr,1);

end

pointer=0;

for ii=1:nconstr

    pointer=pointer+1;

    if is_initial

        v{pointer}={0.005,2*0.005,'gamma'};

    else

        v(pointer)=C_A(pointer+1);

    end

end

if is_initial

    v = struct('priors',{v},...
        'kf_filtering_level',0);

end

end