function failed_tutorial_spike

% MEM 8gb
% WALLTIME 00:10:00
% DEPENDENCY ft_read_spike ft_spike_select ft_spike_waveform ft_spike_maketrials ft_spike_isi ft_spike_plot_isireturn ft_spike_psth ft_spikedensity ft_spike_plot_raster ft_spike_rate ft_spike_select ft_spike_xcorr ft_spike_jpsth ft_spike_plot_jpsth

filenex = dccnpath('/home/common/matlab/fieldtrip/data/ftp/tutorial/spikefield/p029_sort_final_01.nex');
spike   = ft_read_spike(filenex);

cfg              = [];
cfg.spikechannel = {'sig002a_wf', 'sig003a_wf'}; % select only the two single units
spike = ft_spike_select(cfg, spike);

cfg             = [];
cfg.fsample     = 40000;
cfg.interpolate = 1; % keep the density of samples as is
[wave, spikeCleaned] = ft_spike_waveform(cfg,spike);

for k = [1 2]
  figure,
  sl = squeeze(wave.dof(k,:,:))>1000; % only keep samples with enough spikes
  plot(wave.time(sl), squeeze(wave.avg(k,:,sl)),'k') % factor 10^6 to get microseconds
  hold on

  % plot the standard deviation
  plot(wave.time(sl), squeeze(wave.avg(k,:,sl))+sqrt(squeeze(wave.var(k,:,sl))),'k--')
  plot(wave.time(sl), squeeze(wave.avg(k,:,sl))-sqrt(squeeze(wave.var(k,:,sl))),'k--')

  axis tight
  set(gca,'Box', 'off')
  xlabel('time')
  ylabel('normalized voltage')
end

event = ft_read_event(filenex);

cfg          = [];
cfg.dataset  = filenex;
cfg.trialfun = 'trialfun_stimon';
cfg = ft_definetrial(cfg);

cfg.timestampspersecond =  spike.hdr.FileHeader.Frequency; % 40000
spikeTrials = ft_spike_maketrials(cfg,spike);

spikeTrials.trialtime(1:5,:)
spikeTrials.cfg.trl(1:5,:)

cfg                     = [];
hdr                     = ft_read_header(filenex);
cfg.trl                 = [0 hdr.nSamples*hdr.TimeStampPerSample 0];
cfg.timestampspersecond =  spike.hdr.FileHeader.Frequency; % 40000
spike_notrials   = ft_spike_maketrials(cfg,spike);

dat = ft_checkdata(spikeTrials,'datatype', 'raw', 'fsample', 1000);

dat.trial{1}(:,4000:4004)

spike_converted = ft_checkdata(dat,'datatype', 'spike');

cfg       = [];
cfg.bins  = [0:0.0005:0.1]; % use bins of 0.5 milliseconds
cfg.param = 'coeffvar'; % compute the coefficient of variation (sd/mn of isis)
isih = ft_spike_isi(cfg,spikeTrials);

for k = [1 2] % only do for the single units
  cfg              = [];
  cfg.spikechannel = isih.label{k};
  cfg.interpolate  = 5; % interpolate at 5 times the original density
  cfg.window       = 'gausswin'; % use a gaussian window to smooth
  cfg.winlen       = 0.004; % the window by which we smooth has size 4 by 4 ms
  cfg.colormap     = jet(300); % colormap
  cfg.scatter      = 'no'; % do not plot the individual isis per spike as scatters
  figure, ft_spike_plot_isireturn(cfg,isih)
end

% read in the .t file
filet = dccnpath('/home/common/matlab/fieldtrip/data/ftp/tutorial/spike/tt6_7.t');

cfg         = [];
cfg.dataset = filet;
spike2 = ft_read_spike(cfg.dataset);

% convert timestamps to seconds
cfg                     = [];
cfg.trl                 = [0 max(spike2.timestamp{1})+1 0];
cfg.timestampspersecond = 10^6;
spike2Trial = ft_spike_maketrials(cfg,spike2);

% run the isi histogram
cfg      = [];
cfg.bins = [0:0.001:0.2];
isih = ft_spike_isi(cfg,spike2Trial);

% plot the isi histogram with the Poincare return map
cfg             = [];
cfg.interpolate = 5;
cfg.window      = 'gausswin';
cfg.winlen      = 0.005;
cfg.scatter     = 'no';
cfg.colormap    = jet(300);
figure, ft_spike_plot_isireturn(cfg,isih)

cfg             = [];
cfg.binsize     =  0.1; % if cfgPsth.binsize = 'scott' or 'sqrt', we estimate the optimal bin size from the data itself
cfg.outputunit  = 'rate'; % give as an output the firing rate
cfg.latency     = [-1 3]; % between -1 and 3 sec.
cfg.vartriallen = 'yes'; % variable trial lengths are accepted
cfg.keeptrials  = 'yes'; % keep the psth per trial in the output
psth = ft_spike_psth(cfg,spikeTrials);

cfg         = [];
cfg.binsize =  [0.05];
cfg.latency = [-1 3];
psth = ft_spike_psth(cfg,spikeTrials);

cfg              = [];
cfg.topplotfunc  = 'line'; % plot as a line
cfg.spikechannel = spikeTrials.label([1 2]);
cfg.latency      = [-1 3];
cfg.errorbars    = 'std'; % plot with the standard deviation
cfg.interactive  = 'no'; % toggle off interactive mode
figure, ft_spike_plot_raster(cfg,spikeTrials, psth)

cfg         = [];
cfg.latency = [-1 3];
cfg.timwin  = [-0.025 0.025];
cfg.fsample = 1000; % sample at 1000 hz
sdf = ft_spikedensity(cfg,spikeTrials);

cfg              = [];
cfg.topplotfunc  = 'line'; % plot as a line plot
cfg.spikechannel = spikeTrials.label([1 2]); % can also select one unit here
cfg.latency      = [-1 3];
cfg.errorbars    = 'std'; % plot with standard deviation
cfg.interactive  = 'no'; % toggle off interactive mode
figure, ft_spike_plot_raster(cfg,spikeTrials, sdf)

cfg         = [];
cfg.latency = [-1 3];
cfg.timwin  = [-0.1 0.1];
cfg.fsample = 1000; % sample at 1000 hz
[sdf, sdfdata] = ft_spikedensity(cfg,spikeTrials);

sdfdata.trial{1}(:,3000:3005)

cfg            = [];
cfg.latency    = [0.3 max(spikeTrials.trialtime(:))]; % sustained response period
cfg.keeptrials = 'yes';
rate = ft_spike_rate(cfg,spikeTrials);

[R,P] = corrcoef(rate.trial);

% read in the data, select the channels and define the trials
spike = ft_read_spike(filenex);

cfg              = [];
cfg.spikechannel = {'sig001U_wf', 'sig002U_wf', 'sig003U_wf', 'sig004U_wf'}; % select only the MUA
spike = ft_spike_select(cfg, spike);

cfg          = [];
cfg.dataset  = filenex;
cfg.trialfun = 'trialfun_stimon';
cfg = ft_definetrial(cfg);
cfg.timestampspersecond =  spike.hdr.FileHeader.Frequency; % 40000
spikeTrials = ft_spike_maketrials(cfg,spike);

cfg             = [];
cfg.maxlag      = 0.2; % maximum 200 ms
cfg.binsize     = 0.001; % bins of 1 ms
cfg.outputunit  = 'proportion'; % make unit area
cfg.latency     = [-2.5 0];
cfg.vartriallen = 'no'; % do not allow variable trial lengths
cfg.method      = 'xcorr'; % compute the normal cross-correlogram
Xc = ft_spike_xcorr(cfg,spikeTrials);

% compute the shuffled correlogram
cfg.method      = 'shiftpredictor'; % compute the shift predictor
Xshuff = ft_spike_xcorr(cfg,spikeTrials);

iCmb = 3;
jCmb = 4;
figure
xcSmoothed = conv(squeeze(Xc.xcorr(iCmb,jCmb,:)),ones(1,5)./5,'same'); % do some smoothing
hd = plot(Xc.time(3:end-2),xcSmoothed(3:end-2),'k'); % leave out borders (because of smoothing)
hold on
xcSmoothed = conv(squeeze(Xshuff.shiftpredictor(iCmb,jCmb,:)),ones(1,5)./5,'same');
plot(Xc.time(3:end-2),xcSmoothed(3:end-2),'r')
hold on
xlabel('delay')
ylabel('proportion of coincidences')
title([Xc.label{iCmb} Xc.label{jCmb}])
axis tight

% compute the spike densities
cfg         = [];
cfg.latency = [-1 3];
cfg.timwin  = [-0.025 0.025];
cfg.fsample = 200;
[sdf] = ft_spikedensity(cfg,spikeTrials);

% compute the joint psth
cfg               = [];
cfg.normalization = 'no';
cfg.channelcmb    = spikeTrials.label(3:4);
cfg.method        = 'jpsth';
jpsth = ft_spike_jpsth(cfg,sdf);

cfg.method = 'shiftpredictor';
jpsthShuff = ft_spike_jpsth(cfg,sdf);

% subtract the predictor
jpsthSubtr = jpsth;
jpsthSubtr.jpsth = jpsth.jpsth-jpsthShuff.shiftpredictor;

cfg        = [];
figure
ft_spike_plot_jpsth(cfg,jpsth)
figure
ft_spike_plot_jpsth(cfg,jpsthShuff)
figure
ft_spike_plot_jpsth(cfg,jpsthSubtr)


%MDL_IRB140 Create model of ABB IRB 140 manipulator
%
% MDL_IRB140 is a script that creates the workspace variable irb140 which
% describes the kinematic characteristics of an ABB IRB 140 manipulator
% using standard DH conventions.
%
% Also define the workspace vectors:
%   qz         zero joint angle configuration
%   qr         vertical 'READY' configuration
%   qd         lower arm horizontal as per data sheet
%
% Reference::
% - "IRB 140 data sheet", ABB Robotics.
% - "Utilizing the Functional Work Space Evaluation Tool for Assessing a
%   System Design and Reconfiguration Alternatives"
%   A. Djuric and R. J. Urbanic
%
% Notes::
% - SI units of metres are used.
% - Unlike most other mdl_xxx scripts this one is actually a function that
%   behaves like a script and writes to the global workspace.
%
% See also mdl_fanuc10l, mdl_m16, mdl_motormanHP6, mdl_S4ABB2p8, mdl_puma560, SerialLink.

% MODEL: ABB, IRB140, 6DOF, standard_DH

% Copyright (C) 1993-2017, 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

function r = mdl_irb140()

    deg = pi/180;

    % robot length values (metres)
    d1 = 0.352;
    a1 = 0.070;
    a2 = 0.360;
    d4 = 0.380;
    d6 = 0.065;

    % DH parameter table
    %     theta d a alpha
    dh = [0 d1 a1  -pi/2
          0 0  a2  0
          0 0  0   pi/2
          0 d4 0   -pi/2
          0 0  0   pi/2
          0 d6 0   pi/2];

    % and build a serial link manipulator

    robot = SerialLink(dh, 'name', 'IRB 140', ...
        'manufacturer', 'ABB', 'ikine', 'nooffset');

    % place the variables into the global workspace
    if nargin == 1
        r = robot;
    elseif nargin == 0
        assignin('caller', 'irb140', robot);
        assignin('caller', 'qz', [0 0 0 0 0 0]); % zero angles
        assignin('caller', 'qd', [0 -90 180 0 0 -90]*deg); % data sheet pose, horizontal
        assignin('caller', 'qr', [0 -90 90 0 90 -90]*deg); % ready pose, arm up
    end
end


function newTargets = getImgOverPlanes(ops1)
nFOV = size(ops1,2);
Ly = ops1{1}.Ly;
Lx = ops1{1}.Lx;
planesToInterpolate = ops1{1}.planesToInterpolate;
ds = zeros(length(planesToInterpolate), 2, nFOV);
% planesToInterpolate should be indices of non-flyback planes
% (only those should be aligned)
for i = 2:length(planesToInterpolate) % align consecutive planes
    pl = planesToInterpolate(i);
    for j = 1:nFOV
        ds(i,:,j) = registration_offsets(ops1{pl,j}.mimg, ops1{pl-1,j}, 0);
    end
end
ds = cumsum(ds,1);
ds = bsxfun(@minus, ds, mean(ds,1));
images = zeros(Ly, Lx, length(planesToInterpolate), nFOV);
for i = 1:length(planesToInterpolate)
    for j = 1:nFOV
        images(:,:,i,j) = ops1{planesToInterpolate(i),j}.mimg;
    end
end
ds = reshape(permute(ds, [1 3 2]), [], 2);
images = reshape(images, Ly, Lx, []);
newTargets = register_movie(images, ops1{1}, ds);
newTargets = reshape(newTargets, Ly, Lx, length(planesToInterpolate), nFOV);


classdef rbm
% Restricted Boltzmann Machine Model object:
%----------------------------------------------------------------------------
% Initialize and train an RBM energy-based model. Supports binary, Gaussian,
% and multinomial inputs (still in development).
%
% Supports binary and noisy rectified linear units (NReLU) in the hidden layer.
%
% Supports joint modeling of binary and multinomial variables for classification.
%
% Model regularizers include L2 and L1 (via subgradients) weight decay, hidden
% unit sparsity (binary units only), and hidden unit dropout.
%----------------------------------------------------------------------------
% Dustin E. Stansbury
% stan_s_bury@berkeley.edu

properties
	class = 'rbm'; 		% GENERAL CLASS OF MODEL
	inputType = 'binary';% TYPE OF RBM ('BB','GB')
	classifier = false; % TRAIN MULTINOMIAL UNITS FOR CLASSIFICATION IN PARALLEL
	nClasses;			% # OF OUTPUT CLASSES (.classifier = true)
	nObs;				% # OF TRAINING OBSERVATIONS
	nVis;				% # OF VISIBLE UNITS (DIMENSIONS)
	nHid = 100;			% # OF HIDDEN UNITS
	rlu = 0;			% USE RECTIFIED LINEAR UNITS
	W;					% CONNECTION WEIGHTS
	dW;					% GRADIENT FOR CONN. WEIGHTS
	b;					% VISIBLE UNIT BIASES
	db;					% GRADIENT FOR VIS. BIAS
	c;					% HIDDEN UNIT BIASES
	dc;					% GRADIENT FOR HID. BIAS
	classW=0			% CLASSFIER OUTPUT WEIGHTS
	dClassW; 			% CLASS. WEIGHT GRADIENTS
	d=0;				% CLASSIFIER BIAS
	dd;					% GRADIENT FOR classifier BIASES
	log;				% ERROR AND LEARNING RATE LOGS
	aVis;				% VISIBLE LAYER ACTIVATIONS
	aHid;				% HIDDEN LAYER ACTIVATION
	pHid;				% HIDDEN LAYER PROBS
	pHid0;				% INITIAL HIDDEN LAYER PROBS
	aHid0;				% INITIAL HIDDEN LAYER ACTIVATION
	eHid;				% EXPECTATION OF HIDDEN STATE (POST TRAINING)
	pClass;				% PROBABILITIES OF CLASSIFIER UNITS (.classifier = 1)
	aClass;				% ACTIVATION OF CLASSIFIER UNITS (.classifier = 1)
	docLen;				% DOCUMENT LENGTH (MULTINOMIAL INPUTS)
	lRate = 0.1;		% DEFAULT LEARNING RATE
	batchIdx = [];		% BATCH INDICES INTO TRAINING DATA
	sampleVis = 0;		% SAMPLE THE VISIBLE UNITS
	sampleHid = 1;		% SAMPLE HIDDEN UNITS
	momentum = 0;		% DEFAULT MOMENTUM TERM
	nEpoch = 100;		% # OF FULL PASSES THROUGH TRIANING DATA
	wPenalty = 0;		% CURRENT WEIGHT PENALTY
	sparsity = 0;		% SPARSENESS FACTOR
	dropout = 0;		% HIDDEN UNIT DROPOUT
	doMask = 1;			% DROPOUT MASK
	topoMask = [];		% MASK FOR TOPOGRAPHY
	sparseGain=5;		% LEARNING RATE GAIN FOR SPARSITY
	batchSz = 100;		% # OF TRAINING POINTS PER BATCH
	nGibbs = 1;			% CONTRASTIVE DIVERGENCE (1)
	beginAnneal = Inf;	% # OF EPOCHS TO START SIMULATED ANNEALING
	beginWeightDecay=1% # OF EPOCHS TO START WEIGHT PENALTY
	verbose = 1;		% DISPLAY PROGRESS
	saveEvery = 0;		% # OF EPOCHS TO SAVE INTERMEDIATE MODELS
	displayEvery=500;	% # WEIGHT UPDATES TO VISUALIZE LEARNING
	visFun = [];		% USER-DEFINED FUNCTION ('@myFun')
	auxVars = []; 		% AUXILLARY VARIABLES, JUST IN CASE
	useGPU = 0; 		% USE CUDA, IF AVAILABLE
	gpuDevice;			% GPU DEVICE STRUCTURE
	interactive = 0;	% STORE A GLOBAL COPY FOR INTERACTIVE TRAINING
	saveFold
end % END PROPERTIES

methods

	function self = rbm(arch)
	% r = rbm(arch)
	%--------------------------------------------------------------------------
	% RBM constructor
	%--------------------------------------------------------------------------
	% INPUT:
	%  <arch>:  - a set of arguments defining the RBM architecture.
	%
	% OUTPUT:
	%     <r>:  - an RBM model object.
	%--------------------------------------------------------------------------
		if notDefined('arch')
		else
			self = self.init(arch);
		end
	end

	function print(self)
	% print()
	%--------------------------------------------------------------------------
	% Display the properties and methods for the RBM object class.
	%--------------------------------------------------------------------------
		properties(self)
		methods(self)
	end

	function self = train(self,X,targets)
	% self = train(X,[targets])
	%--------------------------------------------------------------------------
	% Train an RBM using Contrastive Divergence
	%--------------------------------------------------------------------------
	% INPUT:
	%        <X>:  - to-be modeled data |X| = [#Obs x #Vis]
	%  <targets>:  - category targets. can be either [#Obs x #Class] as 1 of
	%                K representation or [#Obs x 1], where each entry is a
	%                numerical category label. (optional)
	% OUTPUT:
	%     <self>:  - trained RBM object.
	%--------------------------------------------------------------------------
		lRate0 = self.lRate;
		if self.sparsity > 0, meanAct = 0; end
		if notDefined('targets')
			targets = 0;
		end

		self.nObs = size(X,1);

		% INITIALIZE CLASSIFIER UNITS
		if self.classifier || any(targets)
			self.classifier = true;
			[self,targets] = self.initClassifer(targets);
		end

		self.log.err = zeros(1,self.nEpoch);
		self.log.lRate = self.log.err;

		wPenalty = self.wPenalty;
		dCount = 1;
		mCount = 1;

		self.batchIdx = self.createBatches(X);

		% SEND DATA TO GPU
		% USER WILL NEED TO IMPLEMENT gpuDistribute.m
		if self.useGPU
			self = gpuDistribute(self);
			X = gpuArray(X);
			targets = gpuArray(targets);
		end

		iE = 1;
		while 1
			sumErr = 0;

			% SIMULATED ANNEALING
			if iE > self.beginAnneal
				self.lRate = max(lRate0*((iE-self.beginAnneal)^(-.25)),1e-8);
			end

			% WEIGHT DECAY
			if iE < self.beginWeightDecay
				self.wPenalty = 0;
			else
				self.wPenalty = wPenalty;
			end

			% LOOP OVER BATCHES
			for jB = 1:numel(self.batchIdx)
				batchX = X(self.batchIdx{jB},:);
				if self.classifier
					batchTargets = targets(self.batchIdx{jB},:);
				else
					batchTargets = 0;
				end

				if strcmp(self.inputType,'multinomial')
					self.docLen = sum(batchX,2);
				end

				if self.dropout > 0 % SAMPLE DROPOUT MASK ONECE PER MINIBATCH
					self.doMask = rand(size(batchX,1),self.nHid)>self.dropout;
				else
					self.doMask = 1;
				end

				% SAMPLE FROM MODEL, CALCULATE GRADIENTS, UPDATE PARAMS
				self = self.runGibbs(batchX,batchTargets);
				self = self.updateParams(batchX,batchTargets);
				sumErr = self.accumErr(batchX,sumErr);

				if ~isempty(self.visFun) & ~mod(dCount,self.displayEvery)&iE>1;
					self.auxVars.batchX = batchX;
					self.auxVars.batchTargets = targets;
					self.auxVars.error = self.log.err(1:iE-1);
					self.auxVars.lRate = self.log.lRate(1:iE-1);
					self.visLearning;
				end
				dCount = dCount+1;
				% MOVING AVERAGE OF HIDDEN ACTIVATIONS FOR SPARSITY
				if self.sparsity & ~self.rlu
					meanAct = mean(self.aHid)*0.1 + 0.9*meanAct;
				end
			end

			% SPARSITY (BINARY HIDDENS ONLY)
			if self.sparsity & ~self.rlu
				dcSparse = -self.lRate*self.sparseGain*(meanAct-self.sparsity);
				self.c = self.c + dcSparse;
			end

 			% ENDUCE SPARSITY
 			% if self.sparsity & ~self.rlu
 			% 	dcSparse = -self.lRate*self.sparseGain*(mean(self.pHid)-self.sparsity);
 			% 	self.c = self.c + dcSparse;
 			% end

			% LOG ERRORS, ETC.
			self.log.err(iE) = sumErr/self.nObs;
			self.log.lRate(iE) = self.lRate;

			if self.verbose
				self.printProgress(sumErr,iE,jB);
			end

			% SAVE?
			if iE > 1
				if ~mod(iE, self.saveEvery) & ~isempty(self.saveFold)
					r = self;
					if ~exist(r.saveFold,'dir')
						mkdir(r.saveFold);
					end
					save(fullfile(r.saveFold,sprintf('Epoch_%d.mat',iE)),'r'); clear r;
				end
			end

			% CLEAN UP IF USING INTERACTIVE TRAINING
			if iE >= self.nEpoch
				if self.interactive
					clear global r
				end
				break
			else % STORE GLOBAL COPY FOR INTERACTIVE TRAINING
				if self.interactive
					global r
					r = self;
				end
			end
			iE = iE + 1;
		end

		% PULL DATA FROM GPU, IF NEEDED
		% USER WILL NEED TO IMPLEMENT gpuGather.m
		if self.useGPU
			self = gpuGather(self);
			reset(self.gpuDevice);
			self.gpuDevice = [];
		end
		fprintf('\n');
	end

	function self = runGibbs(self,X,targets)
	% r = runGibbs(X,targets)
	%--------------------------------------------------------------------------
	% Draw MCMC samples from the current model via Gibbs sampling.
	%--------------------------------------------------------------------------
	% INPUT:
	%       <X>:  - minibatch data.
	% <targets>:  - possible categorical targets. if no categorization,
	%               <targets> should be empty ([]).
	%
	% OUTPUT:
	%    <r>:  - RBM object with updated states
	%--------------------------------------------------------------------------
		nObs = size(X,1);
		iC = 1;
		% GO UP
		self = self.hidGivVis(X,targets,1);
		% LOG INITIAL STATES FOR GRADIENT CALCULATION
		self.pHid0 = self.pHid;
		self.aHid0 = self.aHid;

		while 1
			% GO DOWN
			self = self.visGivHid(self.aHid,self.sampleVis);
			X = self.aVis;

			% GO BACK UP
			if iC >= self.nGibbs
				self = self.hidGivVis(self.aVis,targets,0);
				break
			else
				self = self.hidGivVis(self.aVis,targets,1);
			end
			iC = iC + 1;
		end
	end

	function self = hidGivVis(self,X,targets,sampleHid)
	% r = hidGivVis(X,targets,[sampleHid])
	%--------------------------------------------------------------------------
	% Update hidden unit probabilities and states conditioned on the current
	% states of the visible units.
	%--------------------------------------------------------------------------
	% INPUT:
	%         <X>:  - batch data.
	%   <targets>:  - possible target variables.
	% <sampleHid>:  - flag indicating to sample the states of the hidden units.
	%
	% OUTPUT:
	%      <r>:  - RBM object with updated hidden unit probabilities/states.
	%--------------------------------------------------------------------------
		hidBias = self.c;
		if strcmp(self.inputType,'multinomial')
			% WEIGHT BIASES BY DOCUMENT LENGTH
			hidBias = bsxfun(@times,self.docLen,hidBias);
		end

		if self.classifier
			% JOINTLY MODEL MULTINOMIAL OVER INPUT CLASSES
			pHid = self.sigmoid(bsxfun(@plus,X*self.W + targets*self.classW ,hidBias));
		else
			pHid = self.sigmoid(bsxfun(@plus,X*self.W, hidBias));
		end

		if self.rlu % RECTIFIED LINEAR UNITS
			self.aHid = max(0,pHid + randn(size(pHid)).*sqrt(self.sigmoid(pHid)));
		else
			if sampleHid
				self.aHid = single(pHid>rand(size(X,1),self.nHid));
			else
				self.aHid = pHid;
			end
		end
		self.pHid = pHid;

		% ENDUCE TOPOGRAPHY?
		if ~isempty(self.topoMask)
			for iH = 1:size(self.aHid,1)
				self.aHid(iH,:) = sum(bsxfun(@times,self.topoMask,self.aHid(iH,:)),2);
			end
		end
		% DEAL WITH DROPOUT
		self.aHid = self.aHid.*self.doMask;
	end

	function self = visGivHid(self,aHid,sampleVis)
	% r = hidGivVis(aHid,[sampleVis])
	%--------------------------------------------------------------------------
	% Update visible unit states conditioned on the current states of the hidden
	% units.
	%--------------------------------------------------------------------------
	% INPUT:
	%      <aHid>:  - current hidden unit states (activations)
	% <sampleVis>:  - flag indicating to sample the states of the visible units.
	%
	% OUTPUT:
	%      <r>:  - RBM object with updated visible unit probabilities/states.
	%--------------------------------------------------------------------------
		nObs = size(aHid,1);
		switch self.inputType
			case 'binary'
				pVis = self.sigmoid(bsxfun(@plus,aHid*self.W',self.b));
				if sampleVis
					self.aVis = pVis>rand(nObs,self.nVis);
				else
					self.aVis = pVis;
				end

			case 'gaussian'
				mu = bsxfun(@plus,aHid*self.W',self.b);

				if sampleVis
					self.aVis = self.drawNormal(mu);
				else
					self.aVis = mu;
				end

			case 'multinomial'
				pVis = self.softMax(bsxfun(@plus,aHid*self.W',self.b));
				self.aVis = zeros(size(pVis));
				for iO  = 1:nObs
					% DRAW D SEPARATE MULTINOMIALS FOR EACH INPUT
					self.aVis(iO,:) = mnrnd(self.docLen(iO),pVis(iO,:));
				end
		end

		if self.classifier
			self.pClass = self.softMax(bsxfun(@plus,self.aHid*self.classW',self.d));
			self.aClass = self.sampleClasses(self.pClass);
		end
	end

	function self = updateParams(self,X,targets);
	% self = updateParams(X,targets)
	%--------------------------------------------------------------------------
	% Update current model parameters based on the states of hidden and visible
	% units. Weight decay is applied here.
	%--------------------------------------------------------------------------
	% INPUT:
	%       <X>:  - minibatch data.
	% <targets>:  - possible categorical targets. if no categorization,
	%               <targets> should be empty ([]).
	%
	% OUTPUT:
	%    <self>:  - RBM object with updated states
	%--------------------------------------------------------------------------
		nObs = size(X,1);

		dW = (X'*self.pHid0 - self.aVis'*self.pHid)/nObs;
		self.dW = self.momentum*self.dW + ... % MOMENTUM
			          (1-self.momentum)*dW;         % NEW GRADIENT

		self.W = self.W + self.lRate*self.dW;

		% WEIGHT DECAY
		if self.wPenalty > 0 % L2
			self.W = self.W - self.lRate*self.wPenalty*self.W;
		elseif self.wPenalty < 0 % L1 SUBGRADIENT AT 0
			self.W = self.W + self.lRate*self.wPenalty*sign(self.W);
		end

		db = mean(X) - mean(self.aVis);
		dc = mean(self.pHid0) - mean(self.pHid);

		self.db = self.momentum*self.db + self.lRate*db;
		self.b = self.b + self.db;

		self.dc = self.momentum*self.dc + self.lRate*dc;
		self.c = self.c + self.dc;

		if self.classifier
			% CLASSIFIER WEIGHTS
			dClassW=(targets'*self.pHid0 - self.aClass'*self.pHid)/nObs;
			self.dClassW=self.momentum*self.dClassW+self.lRate*(dClassW-self.wPenalty*self.classW);
			self.classW = self.classW + self.dClassW;

			% CLASSIFIER BIASES
			dd = (sum(targets) - sum(self.aClass))/nObs;
			self.dd = self.momentum*self.dd + self.lRate*dd;
			self.d = self.d + self.dd;
		end
	end

	function err = accumErr(self,X,err0);
	% err = updateParams(X,err0)
	%--------------------------------------------------------------------------
	% Add reconstruction error (squared difference) for the current batch to
	% the total error.
	%--------------------------------------------------------------------------
	% INPUT:
	%       <X>:  - minibatch data.
	%    <err0>:  - current resevoir of error
	%
	% OUTPUT:
	%     <err>:  - updated error resevoir
	%--------------------------------------------------------------------------
		err = sum(sum((X-self.aVis).^2));
		err = err + err0;
	end

	function self = init(self,arch)
	% r = init(arch)
	%--------------------------------------------------------------------------
	% Initialize an rbm object based on provided architecture, <arch>.
	%--------------------------------------------------------------------------
	% INPUT:
	%    <arch>:  - a structure of architecture options. Possible fields are:
	%               .size       --> [#Visible x #Hidden] units
	%               .inputType  --> string indicating input type (i.e. 'binary',
	%                              'gaussian','multinomial')
	%               .classifyer --> flag indicating whether to train a class-
	%                               ifier model in parallel.
	%               .opts       --> additional cell array of options, defined
	%                               in argument-value pairs.
	%
	% OUTPUT:
	%     <r>:  - an initialized RBM object.
	%--------------------------------------------------------------------------
		arch = self.ensureArchitecture(arch);

		self.nVis = arch.size(1);
		self.nHid = arch.size(2);
		self.inputType = arch.inputType;
		self.classifier = arch.classifier;

		% PARSE ANY ADDITIONAL OPTIONS
		if isfield(arch,'opts');
			opts = arch.opts;
			fn = fieldnames(self);
			for iA = 1:2:numel(opts)
				if ~isstr(opts{iA})
					error('<opts> must be a cell array string-value pairs.');
				elseif sum(strcmp(fn,opts{iA}))
					self.(opts{iA})=opts{iA+1};
				end
			end
		end

		% INIT. WEIGHTS (A' LA BENGIO)
		range = sqrt(6/(2*self.nVis));
		self.W = single(2*range*(rand(self.nVis,self.nHid)-.5));

		self.dW = zeros(size(self.W),'single');
		self.b = zeros(1,self.nVis,'single');
		self.db = zeros(size(self.b),'single');
		self.c = zeros(1,self.nHid,'single');
		self.dc = zeros(size(self.c),'single');
	end

	function arch = ensureArchitecture(self,arch)
	% arch = ensureArchitecture(self,arch)
	%--------------------------------------------------------------------------
	% Preprocess the provided architecture structure <arch>.
	%--------------------------------------------------------------------------
	% INPUT:
	% <arch>:  - is either a [2 x 1] vector giving the [#vis x # hid], in which
	%            case we use the default model parameters, or it is a strucure
	%            with the fields:
	%             .size                  --> Network size; [#Vis x # Hid]
	%             .inputType (optional)  --> ['binary'] or 'gaussian'
	%             .classifier (optional) --> true or [false]
	%             .opt (optional)        --> a cell array of {'parameter',paramValue}
	%                                        of global options
	%--------------------------------------------------------------------------
		% IF arch IS GIVEN AS A VECTOR
		if ~isstruct(arch),arch.size = arch; end

		if ~isfield(arch,'size');
			error('need to supply the # of Visible and Hidden units')
		end

		if ~isfield(arch,'inputType');
			arch.inputType = self.inputType;
		end

		if ~isfield(arch,'classifier');
			arch.classifier = self.classifier;
		end

		if isfield(arch,'opts');
			opts = arch.opts;
			if ~iscell(opts) || mod(numel(opts),2)
				error('arch.opts must be a cell array of string-value pairs.')
			end
		end
	end

	function [self,targets] = initClassifer(self,targets);
	% [self,targets] = initClassifer(targets);
	%--------------------------------------------------------------------------
	% Initialize classifier units based on form of <targets>. Can also be used
	% to preprocess targets to be 1-of-K.
	%--------------------------------------------------------------------------

		% IF SUPPLIED TARGETS ARE A LIST OF LABELS
		if isvector(targets)
			targets = self.oneOfK(targets);
		end
		self.nClasses = size(targets,2);
		self.classW = single(0.1*randn(self.nClasses,self.nHid));
		self.dClassW = zeros(size(self.classW),'single');
		self.d = zeros(1,self.nClasses,'single');
		self.dd = self.d;
	end

	function batchIdx = createBatches(self,X)
	% batchIdx = createBatches(X)
	%--------------------------------------------------------------------------
	% Create minibatches based on dimensions of inputs <X>. Returns a cell
	% array with each entry giving the indices in to the rows of <X> for a
	% single batch.
	%--------------------------------------------------------------------------
		nObs = size(X,1);
		nBatches = ceil(nObs/self.batchSz);
		tmp = repmat(1:nBatches, 1, self.batchSz);
		tmp = tmp(1:nObs);
		randIdx=randperm(nObs);
		tmp = tmp(randIdx);
		for iB=1:nBatches
		    batchIdx{iB} = find(tmp==iB);
		end
	end

	function visLearning(self);
	% visLearning(self);
	%--------------------------------------------------------------------------
	% Deal with any visualiztions. Note, must set self.visFun to appropriate
	% visualization function handle.
	%--------------------------------------------------------------------------
		if ~isempty(self.visFun)
			try
				self.visFun(self);
			catch
				fprintf('\nVisualization failed...')
			end
		end
	end

	function printProgress(self,sumErr,iE,jB)
	% printProgress(sumErr,iE,jB)
	%--------------------------------------------------------------------------
	% Utility function to display std out.
	%--------------------------------------------------------------------------
			if iE > 1
			if self.log.err(iE) > self.log.err(iE-1) & iE > 1
				indStr = '(UP)    ';
			else
				indStr = '(DOWN)  ';
			end
		else
			indStr = '';
		end
		fprintf('Epoch %d/%d --> Recon. error: %f %s\r', ...
		iE,self.nEpoch,sumErr,indStr);
	end

	function E = hidExpect(self,X);
	% E = hidExpect(X);
	%--------------------------------------------------------------------------
	% Calculate hidden unit expectations for network input <X>
	%--------------------------------------------------------------------------
		switch self.inputType
		case 'multinomial'
			docLen = sum(X,2);
			E = self.sigmoid(bsxfun(@plus,X*self.W,bsxfun(@times,docLen,self.c)));
		otherwise
			if self.rlu
 				% E = max(0,bsxfun(@plus,X*self.W,self.c));
				E = max(0,X*self.W);
				E = bsxfun(@minus,E,mean(E));
				E = bsxfun(@rdivide,E,std(E));
			else
				E = self.sigmoid(bsxfun(@plus,X*self.W,self.c));
			end
		end
	end

	function samps = sample(self,X0,nSamples,nSteps)
	% samps = sample(X0,[nSamples],[nSteps])
	%--------------------------------------------------------------------------
	% Draw sample(s) from model using a Markov chain.
	%--------------------------------------------------------------------------
	% INPUT:
	%       <X0>:  - initial state from which to begin the Markov chain
	% <nSamples>:  - the number of individual samples to generate. default is
	%                to draw a single sample.
	%   <nSteps>:  - the number of transitions/steps to take in the Markov
	%                chain. default is to take 50 steps.
	%--------------------------------------------------------------------------

		self.sampleVis = 0;
		self.sampleHid = 0;
		if notDefined('nSamples');nSamples = 1;end
		if notDefined('nSteps'),nSteps = 50; end

		[nObs,nVis] = size(X0);
		samps = zeros(nObs,nVis,nSamples);

		if self.useGPU
			samps = gpuArray(single(samps));
			self = gpuDistribute(self);
		end

		for iS = 1:nSamples
			vis = X0;
			for iI = 1:nSteps
				hid = self.sigmoid(bsxfun(@plus,binornd(1,vis)* ...
									self.W,self.c));
				switch self.inputType
				case 'binary'
					vis = self.sigmoid(bsxfun(@plus,binornd(1,hid)* ...
					self.W',self.b));
				case 'gaussian'
					vis = bsxfun(@plus,hid*self.W',self.b);

				case 'multinomial'
					vis = bsxfun(@plus,hid*self.W',self.b)
					pVis = softMax(vis);
					% ENSURE PDF
					pVis = bsxfun(@rdivide,eVis,sum(eVis,2));
					vis = zeros(size(pVis));
					docLen = sum((find(pVis)),2);
					for iO  = 1:nObs
						% DRAW D SEPARATE MULTINOMIALS FOR EACH INPUT
						vis(iO,:) = mnrnd(docLen(iO),pVis(iO,:));
					end
				end
			end
			samps(:,:,iS) = vis;
		end

		if self.useGPU
			samps = gather(samps);
		end
	end

	function F = freeEnergy(self,X)
	% F = freeEnergy(X)
	%--------------------------------------------------------------------------
	% Calculate model free energy for an input <X>. Currently only available for
	% binary and gaussian inputs and binary hidden units.
	%--------------------------------------------------------------------------
	% INPUT:
	%  <X>:  - network input.
	%
	% OUTPUT:
	%  <F>:  - free energy, summing over all binary hidden units.
	%--------------------------------------------------------------------------

		nSamps = size(X,1);
		upBound = 50; loBound = -50; % FOR POSSIBLE OVERFLOW
		switch self.inputType
			case 'binary'
				H = ones(nSamps,1)*self.c + X*self.W;
				H = max(min(H,upBound),loBound);
				% SAMPLE ENERGIES
				sampE = -X*self.b' - sum(-log(1./exp(H)),2);
				F = mean(sampE);
			case 'gaussian'
				H = ones(nSamps,1)*self.c + X*self.W;
				H = max(min(H,upBound),loBound);
				% SAMPLE ENERGIES
				sampE = bsxfun(@minus,X,self.b);
				sampE = sum(sampE.^2,2)/2;
				sampE = sampE - sum(-log(1./(1+exp(H))),2);
				F = mean(sampE);
			case 'multinomial'
				error('need to implement multinomial free energy')
		end
	end

	function targets = oneOfK(self,labels)
	% targets = oneOfK(labels)
	%--------------------------------------------------------------------------
	% Create a 1-of-k representation of a set of labels, where <labels> is a
	% vector of integer class labels.
	%--------------------------------------------------------------------------
		classes = unique(labels);
		targets = zeros(numel(labels),max(classes));
		for iL = 1:numel(classes)
			targets(labels==classes(iL),iL)=1;
		end
	end

	function p = sigmoid(self,X)
	% p = sigmoid(X)
	%--------------------------------------------------------------------------
	% Sigmoid activation function
	%--------------------------------------------------------------------------
		if self.useGPU
			p = arrayfun(@(x)(1./(1 + exp(-x))),X);
		else
			p = 1./(1 + exp(-X));
		end
	end

	function p = drawNormal(self,mu);
	% p = drawNormal(mu);
	%--------------------------------------------------------------------------
	% Draw samples from a multivariate normal  with mean <mu> and identity
	% covariance.
	%--------------------------------------------------------------------------
		% ASSUMES UNIT VARIANCE OF ALL VISIBLES
		% (I.E. YOU SHOULD STANDARDIZE INPUTS)
		p = mvnrnd(mu,ones(1,self.nVis));
	end

	function c = softMax(self,X)
	% c = softMax(X)
	%--------------------------------------------------------------------------
	% Siftmax activation function for input X. Returns a vector of category
	% probabilities.
	%--------------------------------------------------------------------------
		c = bsxfun(@rdivide,exp(X),sum(exp(X),2));
	end

	function classes = sampleClasses(self,pClass)
	%--------------------------------------------------------------------------
	% classes = sampleClasses(pClass)
	%--------------------------------------------------------------------------
	% Sample class labels <classes> given a set of class probabilities, <pClass>
	%--------------------------------------------------------------------------
		[nObs,nClass]=size(pClass);
		classes = zeros(size(pClass));
		% ENSURE NORMALIZED
		pClass = bsxfun(@rdivide,pClass,sum(pClass,2));
		for iC = 1:nObs
			probs = pClass(iC,:);
			samp = cumsum(probs)>rand;
			idx = min(find(max(samp)==samp));
			classSamp = zeros(size(probs));
			classSamp(idx) = 1;
			classes(iC,:) = classSamp;
		end
	end

	function [pred,error,misClass] = classify(self,X,targets)
	% [pred,error,misClass] = classify(X,[targets])
	%--------------------------------------------------------------------------
	% Classify inputs <X> and calculate misclassification and error when comp-
	% ared to <targets>.
	%--------------------------------------------------------------------------
	% INPUT:
	%        <X>:  - a set of inputs to the network.
	%  <targets>:  - (optional). a set of target classes. Can be a 1-of-K vector
	%                or can a vector with equal length to the number of inputs
	%                where each entry is an interger class label.
	% OUTPUT:
	%     <pred>:  - predicted class label.
	%    <error>:  - the classification error, based on provided <targets>
	% <misClass>:  - the indices of the inputs that were misclassified.
	%--------------------------------------------------------------------------

		if notDefined('targets'),
			targets = [];
		else
			if isvector(targets);
				targets = self.oneOfK(targets);
			end
		end

		nObs = size(X,1);

		% ACTIVATE HIDDEN UNITS USING INPUT ONLY
		pHid = self.sigmoid(bsxfun(@plus,X*self.W,self.c));

		% CALCULATE CLASS PROBABILITY
		pClass = self.softMax(bsxfun(@plus,pHid*self.classW',self.d));
		% WINNER-TAKE-ALL CLASSIFICATION
		[~, pred] = max(pClass,[],2);
		if ~notDefined('targets') && nargout > 1
			[~,targets] = max(targets,[],2);

			% CALCULATE MISSCLASSIFICATION RATE
			misClass = find(pred~=targets);
			error = numel(misClass)/nObs;
		end
	end
end % END METHODS
end % END CLASSDEF


function [ DCM ] = tapas_ceode_synData_erp()
% [ DCM ] = tapas_ceode_synData_erp()
%
% Sets parameters and function handles to create a synthetic DCM
% structure. The resulting structure can then be used to generate
% artificial data with tapas_ceode_gen_erp.m
%
% INPUT
%
% OUTPUT
%   DCM         struct          DCM structure with all necessary fields to
%                               generate synthetic data.
%
% -------------------------------------------------------------------------
%
% Author: Dario Schöbi
% Created: 2020-08-10
% Copyright (C) 2020 TNU, Institute for Biomedical Engineering, University of Zurich and ETH Zurich.
%
% This file is part of the TAPAS ceode Toolbox, which is released under the terms of the GNU General Public
% Licence (GPL), version 3. You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version). For further details, see the file
% COPYING or <http://www.gnu.org/licenses/>.
% -------------------------------------------------------------------------

% ---------------------- MODEL SPECIFICATION ------------------------------
M = struct();

% Handles to specify integration scheme, dynamical equation, forward model
% and input
M.IS = 'tapas_ceode_gen_erp';
M.f = 'spm_fx_cmc';
M.int = 'spm_int_L';
M.G = 'spm_lx_erp';
M.FS = 'spm_fy_erp';
M.fu = 'spm_erp_u';

% Design/Parameter values of the driving input (see spm_erp_u.m)
M.dur = 16;
M.ons = 64;
M.ns = 500;
M.x = zeros(2, 9);

% ---------------------- DESIGN SPECIFICATION -----------------------------
xU = struct();

% No condition specific effec
xU.X = [0]';
xU.name = {'std'};

% Sampling rate of the artificial signal
xU.dt = 1e-03;

% ---------------------- PARAMETER VALUES ---------------------------------
% Neuronal parameters (also see spm_fx_erp.m / tapas_ceode_fx_erp.m)
Ep = struct();

Ep.T = [0, 0; 0 0];
Ep.G = [0, 0; 0 0];
Ep.S = [0, 0];
Ep.A{1} = [-4, -4; 1, -4];
Ep.A{2} = [-4, 0; -4, -4];
Ep.A{3} = -4 * ones(2, 2);
Ep.B{1} = zeros(2, 2);
Ep.C = [0; -4];
Ep.H = [0 0 0 0];
Ep.D = -10 * ones(2, 2);
Ep.R = [0 0];

% Leadfield parameters (also see spm_lx_erp.m)
Eg.L = [1, 2];
Eg.J = [1, zeros(1, 5), 1, 0, 1];

% ---------------------- CREATE OUTPUT ------------------------------------
% Combine all structures into single DCM structure
DCM.Ep = Ep;
DCM.Eg = Eg;
DCM.M = M;
DCM.xU = xU;

end


function [dist,score,points] = getNormGTJointDistRP_inference(keypointsAll,gt_annolist,jidx)

dist = cell(length(gt_annolist),1);
score = cell(length(gt_annolist),1);
points = cell(length(gt_annolist),1);

for imgidx = 1:length(gt_annolist)
    assert(strcmp(keypointsAll(imgidx).imgname,gt_annolist(imgidx).image.name) > 0);
    dist{imgidx} = inf(0,length(gt_annolist(imgidx).annorect));
end

for imgidx = 1:length(gt_annolist)

    figure(200); clf; imagesc(imread(gt_annolist(imgidx).image.name));
    hold on; axis equal;
    det = keypointsAll(imgidx).det{jidx+1,1};

    for detidx = 1:2
        [val,idx] = max(det(:,end));
        sc = det(idx,3);
        pp = det(idx,1:2);
        %             plot(pp(1,1),pp(1,2),'r*','Markersize',15);
        for ridx = 1:length(gt_annolist(imgidx).annorect)
            rect = gt_annolist(imgidx).annorect(ridx);
            assert(length(rect) == 1);
            refDist = util_get_head_size(rect);
            if (isfield(rect, 'annopoints') && isfield(rect.annopoints, 'point'))
                p = util_get_annopoint_by_id(rect.annopoints.point, jidx);
                if (~isempty(p))
                    if (p.x>=x1 && p.x<= x2 && p.y >= y1 && p.y <= y2)
                        d(1,ridx) = norm([p.x p.y] - pp)/refDist;
                    end
                    %                         plot(p.x,p.y,'y+','Markersize',15);
                end
            end
        end
        score{imgidx} = [score{imgidx};sc];
        points{imgidx} = [points{imgidx};pp];
        dist{imgidx} = [dist{imgidx};d];
    end
end


function Y = TT_weingarten(V, Z, ind)
% Weingarten map computation for the fixed TT-rank manifold.
%
% NOTE: this manifold requires the use of a modified version of TTeMPS_1.1,
% which is packaced with Manopt and can be found in
% manopt/manopt/manifolds/ttfixedrank/TTeMPS_1.1
%
% Y = TT_weingarten(V, Z, ind)
%
% This function implements the efficient way of computing the Weingarten
% map for the Riemannian submanifold of fixed TT-rank tensors embedded in
% its natural embedding Euclidean space, as described in the paper:
%
%   Psenka and Boumal,
%   Second-order optimization for tensors with fixed tensor-train rank,
%   Optimization workshop at NeurIPS 2020.
%
% Y is the output tangent vector, V is a tangent vector (which contains
% needed information of base point X), Z is a tensor (embedding space).
%
% TT_weingarten supports the following formats for Z:
% 1) Full
% 2) TT-format (any rank)
% 3) sparse, with non-zero indices indexed by ind (see fixedTTrankfactory).
%
% See also: fixedTTrankfactory

% This file is part of Manopt: www.manopt.org.
% Original author: Michael Psenka, Nov. 24, 2020.
% Contributors: Nicolas Boumal
% Change log:

    % Preliminary tangent vector set-up for Y
    d = V.order;
    r = V.rank;
    n = V.size;

    Y = V; % all properties except for dU cores inherited from V
    normV = norm(V);
    V = (1 / normV) * V;
    Y.dU = cell(1, d);

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Begin calculating variational components
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    % Pre-calculate all R-components as needed for tangent space conversion
    R = cell(1, d-1);
    % Intermediary used to calculate R-terms for re-orthogonalization
    Xr = V.U;

    for k = d:-1:2

        sz = size(Xr{k});

        if length(sz) == 2
            sz = [sz, 1]; %#ok<AGROW>
        end

        [Q, R{k - 1}] = qr_unique(unfold(Xr{k}, 'right')');
        Xr{k} = reshape(Q', [size(Q, 2), sz(2), sz(3)]);

        Xr{k - 1} = tensorprod_ttemps(Xr{k - 1}, R{k - 1}, 3);
    end

    % Calculate V.dU under the original parametrization of tangent space

    dUR = cell(1, d);

    for k = 1:(d - 1)
        dUR{k} = unfold(V.dU{k}, 'left') / R{k}';
        dUR{k} = reshape(dUR{k}, [r(k), n(k), r(k + 1)]);
    end

    dUR{d} = V.dU{d};

    % Calculate ~X^tV_{\ge k} efficiently
    XtVg = cell(1, d);

    XtVg{d} = conj(unfold(V.V{d}, 'right')) * unfold(V.dU{d}, 'right').';
    XtVgTmp = conj(unfold(V.V{d}, 'right')) * unfold(V.U{d}, 'right').';

    for k = (d - 1):-1:2
        tmp = tensorprod_ttemps(V.V{k}, XtVg{k + 1}', 3);
        XtVg{k} = conj(unfold(tmp, 'right')) * unfold(V.U{k}, 'right').';

        tmp2 = tensorprod_ttemps(V.V{k}, XtVgTmp', 3);
        XtVg{k} = XtVg{k} + conj(unfold(tmp2, 'right')) * unfold(dUR{k}, 'right').';
        XtVgTmp = conj(unfold(tmp2, 'right')) * unfold(V.U{k}, 'right').';
    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%% CASES FOR TYPE OF EUCLIDEAN GRADIENT Z %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    if isa(Z, 'TTeMPS') || isa(Z, 'TTeMPS_tangent_orth')% Z either TT-tensor or tangent vec

        if isa(Z, 'TTeMPS_tangent_orth')
            Z = tangent_to_TTeMPS(Z); % efficient to treat both as TTeMPS case
        end

        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%               DIAGONAL TERMS                 %%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        ZVr = cell(1, d); % stores values of V_<^T(Z<k>)
        Zr = cell(1, d);  % stores values of X_<^T(Z<k>)
        ZVl = cell(1, d); % stores values of (Z<k>)^T(V_>)
        Zl = cell(1, d);  % stores values of (Z<k>)^T(X_>)

        ZVr{d}  = conj(unfold(Z.U{d}, 'right')) * unfold(V.dU{d}, 'right').';
        XtVgTmp = conj(unfold(Z.U{d}, 'right')) * unfold(V.U{d},  'right').';

        for k = (d - 1):-1:2
            tmp = tensorprod_ttemps(Z.U{k}, ZVr{k + 1}', 3);
            ZVr{k} = conj(unfold(tmp, 'right')) * unfold(V.U{k}, 'right').';

            tmp2 = tensorprod_ttemps(Z.U{k}, XtVgTmp', 3);
            ZVr{k} = ZVr{k} + conj(unfold(tmp2, 'right')) * unfold(dUR{k}, 'right').';
            XtVgTmp = conj(unfold(tmp2, 'right')) * unfold(V.U{k}, 'right').';
        end

        for k=1:d
            ZVr{k} = ZVr{k}';
        end

        Zr{d} = conj(unfold(V.V{d}, 'right')) * unfold(Z.U{d}, 'right').';

        for k = (d - 1):-1:2
            tmp = tensorprod_ttemps(V.V{k}, Zr{k + 1}', 3);
            Zr{k} = conj(unfold(tmp, 'right')) * unfold(Z.U{k}, 'right').';
        end

        % Computation of ZVl and Zl

        ZVl{1} = unfold(dUR{1}, 'left')' * unfold(Z.U{1}, 'left');
        Zl{1}  = unfold(V.U{1}, 'left')' * unfold(Z.U{1}, 'left');

        for k = 2:(d - 1)
            % (V_k-1)(U_k)
            tmp = tensorprod_ttemps(V.U{k}, ZVl{k - 1}', 1);
            ZVl{k} = unfold(tmp, 'left')' * unfold(Z.U{k}, 'left');
            % + (X_k-1)(dU_k)
            tmp = tensorprod_ttemps(dUR{k}, Zl{k - 1}', 1);
            ZVl{k} = ZVl{k} + unfold(tmp, 'left')' * unfold(Z.U{k}, 'left');
            % update Zr to keep up w/ recursive definition
            tmp = tensorprod_ttemps(V.U{k}, Zl{k - 1}', 1);
            Zl{k} = unfold(tmp, 'left')' * unfold(Z.U{k}, 'left');
        end

        ZZ = cell(1, d); % final cores for normal (I \otimes X)Z(X^T)
        Zv = cell(1, d); % final cores for (I \otimes X)Z(V^T)
        vZ = cell(1, d); % final cores for (I \otimes V)Z(X^T)

        % contract to first core
        ZZ{1} = tensorprod_ttemps(Z.U{1}, Zr{2}, 3);
        % contract to inner cores
        for k = 2:(d - 1)
            res = tensorprod_ttemps(Z.U{k}, Zl{k - 1}, 1);
            ZZ{k} = tensorprod_ttemps(res, Zr{k + 1}, 3);
        end

        % contract to last core
        ZZ{d} = tensorprod_ttemps(Z.U{d}, Zl{d - 1}, 1);

        Zv{1} = tensorprod_ttemps(Z.U{1}, ZVr{2}, 3);

        for k = 2:(d - 1)
            res = tensorprod_ttemps(Z.U{k}, Zl{k - 1}, 1);
            Zv{k} = tensorprod_ttemps(res, ZVr{k + 1}, 3);
        end

        Zv{d} = tensorprod_ttemps(Z.U{d}, Zl{d - 1}, 1);

        vZ{1} = tensorprod_ttemps(Z.U{1}, Zr{2}, 3);

        for k = 2:(d - 1)
            res = tensorprod_ttemps(Z.U{k}, ZVl{k - 1}, 1);
            vZ{k} = tensorprod_ttemps(res, Zr{k + 1}, 3);
        end

        vZ{d} = tensorprod_ttemps(Z.U{d}, ZVl{d - 1}, 1);

        % Left unfold everything to apply additional operations
        for k = 1:d
            ZZ{k} = unfold(ZZ{k}, 'left');
            Zv{k} = unfold(Zv{k}, 'left');
            vZ{k} = unfold(vZ{k}, 'left');
        end
        % %%%%%%%%%%%%%%%%%%%%%%%%% TESTING %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        % 1st and last cases special, so they're computed outside the loop
        UL  = unfold(V.U{1}, 'left');
        dUL = unfold(dUR{1}, 'left');

        % right variational term without (I - UU^T) projection
        rightV = (Zv{1} - ZZ{1} * XtVg{2}) / R{1};

        Y.dU{1} = -dUL * UL' * ZZ{1} + rightV - UL * (UL' * rightV);

        for k = 2:(d - 1)
            UL  = unfold(V.U{k}, 'left');
            dUL = unfold(dUR{k}, 'left');

            % right variational term without (I - UU^T) projection
            rightV = (Zv{k} - ZZ{k} * XtVg{k + 1}) / R{k};

            Y.dU{k} = vZ{k} - UL * (UL' * vZ{k}) - dUL * UL' * ZZ{k} ...
                       + rightV - UL * (UL' * rightV);
        end

        Y.dU{d} = vZ{d};

        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%                  CROSS TERMS                 %%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        for k = 1:(d - 1)
            U = unfold(V.U{k}, 'left');
            ZZ{k} = ZZ{k} - U * (U' * ZZ{k});
            ZZ{k} = reshape(ZZ{k}, [r(k), n(k), r(k + 1)]);
        end

        ZZ{d} = reshape(ZZ{d}, [r(d), n(d), 1]);

        % Double loop to represent P_k DP_m, 1 <= k < d
        for k = 1:(d - 1)

            UL = unfold(V.U{k}, 'left');
            dUL = unfold(dUR{k}, 'left');

            for m = 1:(k - 1)
                VtZ = crossTermVariational(k, m, ZZ, dUR{m}, V);
                projUVtZ = VtZ - UL * (UL' * VtZ);

                Y.dU{k} = Y.dU{k} - projUVtZ;
            end

            for m = (k + 1):d
                ZtX = crossTermMatrixRight(k + 1, m, ZZ, V);
                Y.dU{k} = Y.dU{k} + dUL * ZtX;
            end

        end

        % Final terms for k = d
        for m = 1:(d - 1)
            VtZ = crossTermVariational(d, m, ZZ, dUR{m}, V);
            Y.dU{d} = Y.dU{d} - VtZ;
        end

        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%FINAL RESHAPE%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        for k = 1:d
            Y.dU{k} = reshape(Y.dU{k}, [r(k), n(k), r(k + 1)]);
        end

    elseif ~exist('ind', 'var')% Z is a full array

        %{
        Note that you can split up the full expression for the Weingarten map in
        the following way:

        1) Diagonal terms(P_i DP_i terms, or non - cross terms)
        a) This can be split into(left variational) + (right variational),
        which correspond to two terms in product rule expansion
        2) Cross terms(P_i DP_j, we show mathematically equivalent expression
        in companion paper.)
        a) This likewise can be split into(i < j) + (i > j)
        %}

        % Cell that represents the LEFT VARIATIONAL SIDE
        Zv = cell(1, d);
        % Cell that represents the RIGHT VARIATIONAL SIDE
        vZ = cell(1, d);

        % Initialization step
        Zv{d} = Z(:);
        vZ{d} = Z(:);

        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%               DIAGONAL TERMS                 %%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        %%%%%%%%%%%%%%%               LEFT VARIATIONAL               %%%%%%%%%%%%%%%%%%

        % First, calculate where the right side is the variational matrix
        % Note that the calculation here is split between VR^-1 and XX^tVR^-1
        % in (I - XX^t)VR^{-1} through xx and xx2 terms respectively

        % (d-1) term done separately to initialize the temp variable handoff
        zz = reshape(Z, [prod(n(1:(d - 1))), n(d)]);
        xx = transpose(unfold(V.dU{d}, 'right'));
        xxTmp = transpose(unfold(V.U{d}, 'right')); % temp var to help calc xx terms
        xx2 = transpose(unfold(V.V{d}, 'right'));

        % Z-matrix-k-variational, represents the xx calculation for Zv{k}
        Zmkv = zz * xx;
        vZ{d - 1} = zz * xx2;
        Zv{d - 1} = (Zmkv - vZ{d - 1} * XtVg{d}) / R{d - 1};

        % auxillery term for computing anything with variational matrix
        ZZtmp = zz * xxTmp;

        % Main calcualtion for right size of Zv
        for k = (d - 2):-1:1
            zz = reshape(Zmkv, [prod(n(1:k)), n(k + 1) * r(k + 2)]);
            xx = transpose(unfold(V.U{k + 1}, 'right'));
            Zmkv = zz * xx;

            zzTmp = reshape(ZZtmp, [prod(n(1:k)), n(k + 1) * r(k + 2)]);
            xxTmp = transpose(unfold(dUR{k + 1}, 'right'));
            Zmkv = Zmkv + zzTmp * xxTmp;
            ZZtmp = zzTmp * xx;

            % NOTE: vZ is only used here to store these values for later use
            % It stores the standard right side calc for the orthogonal projector
            zz2 = reshape(vZ{k + 1}, [prod(n(1:k)), n(k + 1) * r(k + 2)]);
            xx2 = transpose(unfold(V.V{k + 1}, 'right'));
            vZ{k} = zz2 * xx2;

            Zv{k} = (Zmkv - vZ{k} * XtVg{k + 1}) / R{k};
        end

        % Standard left side calculations for Zv
        for k = 2:d

            for i = 1:(k - 1)
                Z_i = reshape(Zv{k}, [r(i) * n(i), prod(n(i + 1:k)) * r(k + 1)]);
                X_i = unfold(V.U{i}, 'left');
                Zm = X_i' * Z_i;
                Zv{k} = Zm;
            end

            Zv{k} = reshape(Zv{k}, [r(k) * n(k), r(k + 1)]);
        end

        % Final U core projector mult for Zv
        for k = 1:(d - 1)
            U = unfold(V.U{k}, 'left');
            Zv{k} = Zv{k} - U * (U' * Zv{k});
        end

        %%%%%%%%%%%%%%%               RIGHT VARIATIONAL               %%%%%%%%%%%%%%%%%%

        % represents standard projection, also needed as intermediary for this section
        ZZ = vZ;
        % Start left side calculation for vZ
        for k = 2:d

            % Do first in loop separately to initialize intermediary variable
            Z_i = reshape(vZ{k}, [n(1), prod(n(2:k)) * r(k + 1)]);
            dU_i = unfold(dUR{1}, 'left');
            Zm = dU_i' * Z_i;
            vZ{k} = Zm;

            X_i = unfold(V.U{1}, 'left');
            ZZ{k} = X_i' * Z_i;

            for m = 2:(k - 1)
                Z_i = reshape(vZ{k}, [r(m) * n(m), prod(n(m + 1:k)) * r(k + 1)]);
                X_i = unfold(V.U{m}, 'left');
                Zm = X_i' * Z_i;

                Z_tmp = reshape(ZZ{k}, [r(m) * prod(n(m)), prod(n(m + 1:k)) * r(k + 1)]);
                dU_i = unfold(dUR{m}, 'left');

                vZ{k} = Zm + dU_i' * Z_tmp;

                ZZ{k} = X_i' * Z_tmp;
            end

            vZ{k} = reshape(vZ{k}, [r(k) * n(k), r(k + 1)]);
            ZZ{k} = reshape(ZZ{k}, [r(k) * n(k), r(k + 1)]);
        end

        % Final U core projector mult for vZ

        % 1st core separate since vZ{1} = 0 up until now. Purely for efficiency
        U  = unfold(V.U{1},  'left');
        dU = unfold(V.dU{1}, 'left');
        vZ{1} = -dU * U' * ZZ{1};

        for k = 2:(d - 1)
            U  = unfold(V.U{k},  'left');
            dU = unfold(V.dU{k}, 'left');
            vZ{k} = vZ{k} - U * (U' * vZ{k});

            vZ{k} = vZ{k} - dU * U' * ZZ{k};

        end

        for k = 1:d - 1
            Y.dU{k} = Zv{k} + vZ{k};
        end

        Y.dU{d} = vZ{d};

        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%                  CROSS TERMS                 %%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        for k = 1:(d - 1)
            % now only need ZZ as dU cores of normal projection of V
            U = unfold(V.U{k}, 'left');
            ZZ{k} = ZZ{k} - U * (U' * ZZ{k});
            ZZ{k} = reshape(ZZ{k}, [r(k), n(k), r(k + 1)]);
        end

        ZZ{d} = reshape(ZZ{d}, [r(d), n(d), 1]);

        % Double loop to represent P_k DP_m, 1 <= k < d
        for k = 1:(d - 1)

            UL  = unfold(V.U{k},  'left');
            dUL = unfold(V.dU{k}, 'left');

            for m = 1:(k - 1)
                VtZ = crossTermVariational(k, m, ZZ, dUR{m}, V);

                projUVtZ = VtZ - UL * (UL' * VtZ);

                Y.dU{k} = Y.dU{k} - projUVtZ;
            end

            for m = (k + 1):d
                ZtX = crossTermMatrixRight(k + 1, m, ZZ, V);
                Y.dU{k} = Y.dU{k} + dUL * ZtX;
            end

        end

        % Final terms for k = d
        for m = 1:(d - 1)
            VtZ = crossTermVariational(d, m, ZZ, dUR{m}, V);

            Y.dU{d} = Y.dU{d} - VtZ;
        end

        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% FINAL RESHAPE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        for k = 1:d
            Y.dU{k} = reshape(Y.dU{k}, [r(k), n(k), r(k + 1)]);
        end

    else
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% SPARSE CASE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        % permuted U, V, and dU cells for the efficient computation in C
        CU = cell(1, d);
        CV = cell(1, d);
        CdUR = cell(1, d);

        for k = 1:d
            CU{k} = permute(V.U{k}, [1 3 2]);
            CV{k} = permute(V.V{k}, [1 3 2]);
            CdUR{k} = permute(dUR{k}, [1 3 2]);
        end

        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%               DIAGONAL TERMS                 %%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        [ZZ, vZ, Zv] = weingarten_omega(n, r, CU, CV, CdUR, ind.', Z);

        for k = 1:d

            ZZ{k} = reshape(ZZ{k}, [r(k), r(k + 1), n(k)]);
            ZZ{k} = unfold(permute(ZZ{k}, [1 3 2]), 'left');

            vZ{k} = reshape(vZ{k}, [r(k), r(k + 1), n(k)]);
            vZ{k} = unfold(permute(vZ{k}, [1 3 2]), 'left');

            Zv{k} = reshape(Zv{k}, [r(k), r(k + 1), n(k)]);
            Zv{k} = unfold(permute(Zv{k}, [1 3 2]), 'left');
        end

        % 1st and last cases special, so they're computed outside the loop
        UL  = unfold(V.U{1}, 'left');
        dUL = unfold(dUR{1}, 'left');

        % right variational term without (I - UU^T) projection
        rightV = (Zv{1} - ZZ{1} * XtVg{2}) / R{1};
        Y.dU{1} = -dUL * UL' * ZZ{1} + rightV - UL * (UL' * rightV);

        for k = 2:(d - 1)
            UL  = unfold(V.U{k}, 'left');
            dUL = unfold(dUR{k}, 'left');

            % right variational term without (I - UU^T) projection
            rightV = (Zv{k} - ZZ{k} * XtVg{k + 1}) / R{k};
            Y.dU{k} = vZ{k} - UL * (UL' * vZ{k}) - dUL * UL' * ZZ{k} + rightV - UL * (UL' * rightV);
            % norm(vZ{k} - UL * (UL' * vZ{k}) + (Zv{k} - UL * (UL' * Zv{k})) / R{k}) / norm(V)
            % norm(V)
        end

        Y.dU{d} = vZ{d};

        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%                  CROSS TERMS                 %%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        for k = 1:(d - 1)
            U = unfold(V.U{k}, 'left');
            ZZ{k} = ZZ{k} - U * (U' * ZZ{k});
            ZZ{k} = reshape(ZZ{k}, [r(k), n(k), r(k + 1)]);
        end

        ZZ{d} = reshape(ZZ{d}, [r(d), n(d), 1]);

        % Double loop to represent P_k DP_m, 1 <= k < d
        for k = 1:(d - 1)

            UL  = unfold(V.U{k}, 'left');
            dUL = unfold(dUR{k}, 'left');

            for m = 1:(k - 1)
                % XtZ = crossTermMatrixLeft(k, m, ZZ, V);
                VtZ = crossTermVariational(k, m, ZZ, dUR{m}, V);
                projUVtZ = VtZ - UL * (UL' * VtZ);

                Y.dU{k} = Y.dU{k} - projUVtZ; %+ dUL * XtZ;

                % Y.dU{k} = Y.dU{k} - (projUk * kron(eye(n(k)), Vllk') - dUkL * Xlek') * Zkm;
            end

            for m = (k + 1):d
                ZtX = crossTermMatrixRight(k + 1, m, ZZ, V);
                Y.dU{k} = Y.dU{k} + dUL * ZtX;

                %         Y.dU{k} = Y.dU{k} + dUkL * Zkm' * Xg{k+1};
            end

        end

        % Final terms for k = d
        for m = 1:(d - 1)
            VtZ = crossTermVariational(d, m, ZZ, dUR{m}, V);

            Y.dU{d} = Y.dU{d} - VtZ;

            %     Y.dU{d} = Y.dU{d} - kron(eye(n(d)), Vlld') * Zkm;
        end

        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%FINAL RESHAPE%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        for k = 1:d
            Y.dU{k} = reshape(Y.dU{k}, [r(k), n(k), r(k + 1)]);
        end

        Y = (normV) * Y;
    end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Helper methods
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Efficient ZtX term for P_k DP_m, m > k
% Zp here is the projection of Z (just dU cores)
% V is only passed for access to U and V cores
function ZtX = crossTermMatrixRight(k, m, Zp, V)
    ZtX = conj(unfold(Zp{m}, 'right')) * unfold(V.V{m}, 'right').';

    for p = (m - 1):-1:k
        tmp = tensorprod_ttemps(V.U{p}, (ZtX)', 3);
        ZtX = conj(unfold(tmp, 'right')) * unfold(V.V{p}, 'right').';
    end

end

% Efficient XtZ term for P_k DP_m, m < k
% Zp here is the projection of Z
% V is only passed for access to U and V cores
function XtZ = crossTermMatrixLeft(k, m, Zp, V) %#ok<DEFNU>

    XtZ = unfold(V.U{m}, 'left')' * unfold(Zp{m}, 'left');

    for p = (m + 1):k
        XtZ = tensorprod_ttemps(V.U{p}, (XtZ)', 1);
        XtZ = unfold(XtZ, 'left')' * unfold(V.V{p}, 'left');
    end

end

% Efficient VtZ (more accurately kron(eye(n(k)), V') * Z) term for P_k DP_m, m < k
% Zp here is the projection of Z, dURm is normally parametrized dU{m}
% V is only passed for access to U and V cores
function VtZ = crossTermVariational(k, m, Zp, dURm, V)

    VtZ = unfold(dURm, 'left')' * unfold(Zp{m}, 'left');

    for p = (m + 1):(k - 1)
        VtZ = tensorprod_ttemps(V.U{p}, (VtZ)', 1);
        VtZ = unfold(VtZ, 'left')' * unfold(V.V{p}, 'left');
    end

    VtZ = tensorprod_ttemps(V.V{k}, VtZ, 1);
    VtZ = unfold(VtZ, 'left');

end


function [err_N, sG] = ptv_local_nuclear_metric(volfix, voldef, pix_resolution, mask, singular_coefs, P_SZ, norm_type)
%% todo:
% * volfix
% * zero mean, choose std???
% * making zero mean changes gradient!

%     norm_type = 3;
    abs_type = 0;
    deps = 1e-3;

    volsz = [size(voldef, 1), size(voldef, 2), size(voldef, 3)];
    Nd = 3;
    if volsz(3) == 1
        Nd = 2;
    end

    P_SZ = round(P_SZ);
    Nimgs = size(voldef, 5);
    if Nd == 2
        P_SZ = [P_SZ, 1];
    end

    err_N = 0;
    sG = zeros([volsz, Nimgs], 'like', voldef);
    if Nd == 2
        for i1 = 1 : P_SZ(1) : volsz(1)
        for i2 = 1 : P_SZ(2) : volsz(2)
            i11 = min(i1 + P_SZ(1) - 1, volsz(1));
            i22 = min(i2 + P_SZ(2) - 1, volsz(2));
            if i11-i1 < 2 || i22 - i2 < 2
                continue;
            end
            patch = voldef(i1:i11, i2:i22, 1, :, :);
            if norm_type == 1
                patch = patch - sum(sum(sum(patch,1),2),3) / (size(patch,1)*size(patch,2)*size(patch,3));
            elseif norm_type == 2
                patch = patch - mean(patch(:));
            elseif norm_type == 3
                patch = patch - sum(sum( patch, 4), 5) / (size(patch,4)*size(patch,5));
            elseif norm_type == 4
                patch = patch - sum(sum(sum(patch,1),2),3) / (size(patch,1)*size(patch,2)*size(patch,3));
                patch = patch - sum(sum( patch, 4), 5) / (size(patch,4)*size(patch,5));
            end

            patch0 = reshape(patch, [size(patch, 1), size(patch, 2), size(patch, 3), Nimgs]);
            if abs_type == 1
                patch = abs(patch);
            elseif abs_type == 2
                patch = sqrt(patch.^2 + deps);
            end

            if ~isempty(mask)
                mask_cur = logical(mask(i1:i11, i2:i22));
            else
                mask_cur = [];
            end
            if isempty(mask_cur) || any(mask_cur(:))
                [terr, tgrad] = ptv_nuclear_metric([], patch, pix_resolution, mask_cur, singular_coefs);
                err_N = err_N + terr;

                if abs_type == 1
                    tgrad = tgrad.*sign(patch0);
                elseif abs_type == 2
                    tgrad = tgrad .* patch0 ./ sqrt(patch0.^2 + deps);
                end

                if norm_type == 1
                    tgrad = tgrad - sum(sum(sum(tgrad, 1), 2), 3) / (size(patch,1)*size(patch,2)*size(patch,3));
                elseif norm_type == 2
                    tgrad = tgrad - mean(tgrad(:));
                elseif norm_type == 3
                    tgrad = tgrad - sum(sum( tgrad, 4), 5) / (size(patch,4)*size(patch,5));
                elseif norm_type == 4
                    tgrad = tgrad - sum(sum( tgrad, 4), 5) / (size(patch,4)*size(patch,5));
                    tgrad = tgrad - sum(sum(sum(tgrad, 1), 2), 3) / (size(patch,1)*size(patch,2)*size(patch,3));
                end

                sG(i1:i11, i2:i22, 1, :) = tgrad;
            end
        end
        end
    else %3d
        for i1 = 1 : P_SZ(1) : volsz(1)
        for i2 = 1 : P_SZ(2) : volsz(2)
        for i3 = 1 : P_SZ(3) : volsz(3)
            i11 = min(i1 + P_SZ(1) - 1, volsz(1));
            i22 = min(i2 + P_SZ(2) - 1, volsz(2));
            i33 = min(i3 + P_SZ(3) - 1, volsz(3));
            if i11-i1 < 2 || i22 - i2 < 2 || i33 - i3 < 2
                continue;
            end
            patch = voldef(i1:i11, i2:i22, i3:i33, :, :);
            if norm_type == 1
                patch = patch - sum(sum(sum(patch,1),2),3) / (size(patch,1)*size(patch,2)*size(patch,3));
            elseif norm_type == 2
                patch = patch - mean(patch(:));
            elseif norm_type == 3
                patch = patch - sum(sum( patch, 4), 5) / (size(patch,4)*size(patch,5));
            elseif norm_type == 4
                patch = patch - sum(sum(sum(patch,1),2),3) / (size(patch,1)*size(patch,2)*size(patch,3));
                patch = patch - sum(sum( patch, 4), 5) / (size(patch,4)*size(patch,5));
            end

            patch0 = reshape(patch, [size(patch, 1), size(patch, 2), size(patch, 3), Nimgs]);
            if abs_type == 1
                patch = abs(patch);
            elseif abs_type == 2
                patch = sqrt(patch.^2 + deps);
            end

            if ~isempty(mask)
                mask_cur = logical(mask(i1:i11, i2:i22, i3:i33));
            else
                mask_cur = [];
            end
            if isempty(mask_cur) || any(mask_cur(:))
                [terr, tgrad] = ptv_nuclear_metric([], patch, pix_resolution, mask_cur, singular_coefs);
                err_N = err_N + terr;
                if abs_type == 1
                    tgrad = tgrad.*sign(patch0);
                elseif abs_type == 2
                    tgrad = tgrad .* patch0 ./ sqrt(patch0.^2 + deps);
                end
                if norm_type == 1
                    tgrad = tgrad - sum(sum(sum(tgrad, 1), 2), 3) / (size(patch,1)*size(patch,2)*size(patch,3));
                elseif norm_type == 2
                    tgrad = tgrad - mean(tgrad(:));
                elseif norm_type == 3
                    tgrad = tgrad - sum(sum( tgrad, 4), 5) / (size(patch,4)*size(patch,5));
                elseif norm_type == 4
                    tgrad = tgrad - sum(sum( tgrad, 4), 5) / (size(patch,4)*size(patch,5));
                    tgrad = tgrad - sum(sum(sum(tgrad, 1), 2), 3) / (size(patch,1)*size(patch,2)*size(patch,3));
                end
                sG(i1:i11, i2:i22, i3:i33, :) = tgrad;
            end
        end
        end
        end
    end
    err_N = err_N * prod(pix_resolution);
    sG = sG(1:volsz(1), 1:volsz(2), 1:volsz(3), :, :) * prod(pix_resolution);
end

% function [err_N, sG] = ptv_local_nuclear_metric(volfix, voldef, pix_resolution, mask, singular_coefs, P_SZ)
% %% todo:
% % * volfix
% % * zero mean, choose std???
% % * making zero mean changes gradient!
%
% %     P_SZ = [15,15,15];
%     volsz = [size(voldef, 1), size(voldef, 2), size(voldef, 3)];
%     Nd = 3;
%     if volsz(3) == 1
%         Nd = 2;
%     end
%
%     P_SZ = round(P_SZ);
%     Nimgs = size(voldef, 5);
%     if Nd == 2
%         P_SZ = [P_SZ, 1];
%     end
%
%     volsz_p = ceil(volsz./P_SZ) .* P_SZ;
%
%     if Nd == 2
%         volsz_p(3) = 1;
%     end
%
%     voldef_p = zeros([volsz_p, 1, Nimgs]);
%     voldef_p(1:volsz(1), 1:volsz(2), 1:volsz(3), :, :) = voldef;
%
%     if ~isempty(mask)
%         if Nd == 3
%             mask_p = zeros([volsz_p]);
%             mask_p(1:volsz(1), 1:volsz(2), 1:volsz(3)) = mask;
%         else
%             mask_p = zeros([volsz_p]);
%             mask_p(1:volsz(1), 1:volsz(2), 1) = mask;
%         end
%     end
%
%     err_N = 0;
%     sG = zeros([volsz, Nimgs], 'like', voldef);
%     if Nd == 2
%         for i1 = 1 : P_SZ(1) : volsz(1)
%         for i2 = 1 : P_SZ(2) : volsz(2)
%             patch = voldef_p(i1:i1+P_SZ(1)-1, i2:i2+P_SZ(2)-1, 1, :, :);
%             patch = patch - sum(sum(sum(patch,1),2),3) / numel(patch);
% %             patch = patch ./ std(std(std(patch,[],1),[],2),[],3);
%             if ~isempty(mask)
%                 mask_cur = logical(mask_p(i1:i1+P_SZ(1)-1, i2:i2+P_SZ(2)-1));
%             else
%                 mask_cur = [];
%             end
%             if isempty(mask_cur) || any(mask_cur(:))
%                 [terr, tgrad] = ptv_nuclear_metric([], patch, pix_resolution, mask_cur, singular_coefs);
%                 err_N = err_N + terr;
%                 tgrad = tgrad - sum(sum(sum(tgrad, 1), 2), 3) / numel(patch);
%                 sG(i1:i1+P_SZ(1)-1, i2:i2+P_SZ(2)-1, 1, :) = tgrad;
%             end
%         end
%         end
%     else %3d
%         for i1 = 1 : P_SZ(1) : volsz(1)
%         for i2 = 1 : P_SZ(2) : volsz(2)
%         for i3 = 1 : P_SZ(3) : volsz(3)
%             patch = voldef_p(i1:i1+P_SZ(1)-1, i2:i2+P_SZ(2)-1, i3:i3+P_SZ(3)-1, :, :);
%             patch = patch - sum(sum(sum(patch,1),2),3) / numel(patch);
%             if ~isempty(mask)
%                 mask_cur = logical(mask_p(i1:i1+P_SZ(1)-1, i2:i2+P_SZ(2)-1, i3:i3+P_SZ(3)-1));
%             else
%                 mask_cur = [];
%             end
%             if isempty(mask_cur) || any(mask_cur(:))
%                 [terr, tgrad] = ptv_nuclear_metric([], patch, pix_resolution, mask_cur, singular_coefs);
%                 err_N = err_N + terr;
%                 sG(i1:i1+P_SZ(1)-1, i2:i2+P_SZ(2)-1, i3:i3+P_SZ(3)-1, :) = tgrad;
%             end
%         end
%         end
%         end
%     end
%     err_N = err_N * prod(pix_resolution);
%     sG = sG(1:volsz(1), 1:volsz(2), 1:volsz(3), :, :) * prod(pix_resolution);
% end


function tests = test_ft_preproc_baselinecorrect

% MEM 1gb
% WALLTIME 00:10:00
% DEPENDENCY ft_preproc_baselinecorrect

if nargout
  % assume that this is called by RUNTESTS
  tests = functiontests(localfunctions);
else
  % assume that this is called from the command line
  fn = localfunctions;
  for i=1:numel(fn)
    feval(fn{i});
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function testOptions(testCase)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

nchan   = 8;
nsample = 1000;
dat     = randn(nchan, nsample) + 1;

result = [];
result{end+1} = ft_preproc_baselinecorrect(dat, 1, 1000);
result{end+1} = ft_preproc_baselinecorrect(dat, 1, 900);
result{end+1} = ft_preproc_baselinecorrect(dat, 101, 1000);
result{end+1} = ft_preproc_baselinecorrect(dat, 101, 900);

% all iterations were done with (slightly) different options, hence the results should not be equal
for i=1:numel(result)
  for j=(i+1):numel(result)
    assert(~isequal(result{i}, result{j}), 'the results %d and %d should not be equal', i, j);
  end
end


%%*******************************************************************
%%  Read in a problem in SDPA sparse format.
%%
%%  [blk,At,C,b] = read_sdpa(fname)
%%
%%  Input: fname = name of the file containing SDP data in
%%                 SDPA foramt.
%%  Important: the data is assumed to contain only
%%             semidefinite and linear blocks.
%%*****************************************************************
%% SDPT3: version 4.0
%% Copyright (c) 1997 by
%% Kim-Chuan Toh, Michael J. Todd, Reha H. Tutuncu
%% Last Modified: 16 Sep 2004
%%*****************************************************************

   function [blk,At,C,b] = read_sdpa(fname);

%%
%%  Open the file for input
%%
   compressed = 0;
   if exist(fname)
      fid = fopen(fname,'r');
   elseif exist([fname,'.Z']);
      compressed = 1;
      unix(['uncompress ',fname,'.Z']);
      fid = fopen(fname,'r');
   elseif exist([fname,'.gz']);
      compressed = 2;
      unix(['gunzip ',fname,'.gz']);
      fid = fopen(fname,'r');
   else
      fprintf('*** Problem not found, please specify the correct path or problem name. \n');
      blk = []; At = []; C = []; b = [];
      return;
   end
%%
%%  Clean up special characters and comments from the file
%%
   [datavec,count] = fscanf(fid,'%c');
   linefeeds = findstr(datavec,char(10));
   comment_chars = '*"=';
   cumidx = [];
   for i=1:length(comment_chars)
      idx = findstr(datavec,comment_chars(i));
      cumidx = [cumidx,idx];
   end
   for j=length(cumidx):-1:1
      if (cumidx(j)==1) | (strcmp(datavec(cumidx(j)-1),char(10)))
         datavec(cumidx(j):linefeeds(min(find(cumidx(j)<linefeeds))))='';
      else
         datavec(cumidx(j):linefeeds(min(find(cumidx(j)<linefeeds)))-1)='';
      end
   end
   special_chars = ',{}()';
   cumidx=[];
   for i=1:length(special_chars)
      idx = findstr(datavec,special_chars(i));
      cumidx = [cumidx,idx];
   end
   datavec(cumidx) = blanks(length(cumidx));
   clear linefeeds;
%%
%% Close the file
%%
   fclose('all');
   if compressed==1; unix(['compress ',fname]); end;
   if compressed==2; unix(['gzip ',fname]); end;
%%
%%  Next, read in basic problem size parameters.
%%
   datavec = sscanf(datavec,'%f');
   if size(datavec,1) < size(datavec,2); datavec = datavec'; end;
   m = datavec(1);
   numblk  = datavec(2);
   blksize = datavec(2+[1:numblk]);
   if size(blksize,1) > size(blksize,2); blksize = blksize'; end
%%
%% Get input  b.
%%
   idxstrt = 2+numblk;
   b = datavec(idxstrt+[1:m]);
   idxstrt = idxstrt+m;
   b = -b;
%%
%% Construct blk
%%
   deblksize = 100;
   spblkidxtmp = find( (blksize>1) & (blksize < deblksize) );
   spblkidxtmp = sort(spblkidxtmp);
   deblkidx = find( (blksize<=1) | (blksize >= deblksize) );
   denumblk = length(deblkidx);
   linblkidx = zeros(1,denumblk);
   for p = 1:denumblk
      n = blksize(deblkidx(p));
      if (n > 1);
         blk{p,1} = 's'; blk{p,2} = n;
         n2 = n*(n+1)/2;
         At{p,1} = sparse(n2,m);
         C{p,1} = sparse(n,n);
      else
         linblkidx(p) = p;
         blk{p,1} = 'l'; blk{p,2} = abs(n);
         At{p,1} = sparse(abs(n),m);
         C{p,1} = sparse(abs(n),1);
      end
   end
   if ~isempty(spblkidxtmp)
      maxnumblk = 200;
      spnumblk = ceil(length(spblkidxtmp)/maxnumblk);
      for q = 1:spnumblk
         if (q < spnumblk)
            spblkidxall{q} = spblkidxtmp([(q-1)*maxnumblk+1: q*maxnumblk]);
         else
            spblkidxall{q} = spblkidxtmp([(q-1)*maxnumblk+1: length(spblkidxtmp)]);
         end
         tmp = blksize(spblkidxall{q});
         blk{denumblk+q,1} = 's';
         blk{denumblk+q,2} = tmp;
         n2 = sum(tmp.*(tmp+1))/2;
         At{denumblk+q,1} = sparse(n2,m);
         C{denumblk+q,1} = sparse(sum(tmp),sum(tmp));
      end
   else
      spnumblk = 0;
   end
   linblkidx(denumblk+[1:spnumblk]) = zeros(1,spnumblk);
%%
%% Construct single blocks of A,C
%%
   len = length(datavec);
   Y = reshape(datavec(idxstrt+1:len),5,(len-idxstrt)/5)';
   clear datavec;
   Y = sortrows(Y,[1 2]);
   matidx = [0; find(diff(Y(:,1)) ~= 0); size(Y,1)];
%%
   for k = 1:length(matidx)-1
      idx = [matidx(k)+1 : matidx(k+1)];
      Ytmp  = Y(idx,1:5);
      matno = Ytmp(1,1);
      Ytmp2 = Ytmp(:,2);
      for p = 1:denumblk
         n  = blksize(deblkidx(p));
         idx = find(Ytmp2 == deblkidx(p));
         ii = Ytmp(idx,3); jj = Ytmp(idx,4); vv =Ytmp(idx,5);
         len = length(idx);
         if (n > 1)
            idxtmp = find(ii > jj);
            if ~isempty(idxtmp);
               tmp = jj(idxtmp);
               jj(idxtmp) = ii(idxtmp); ii(idxtmp) = tmp;
            end
            tmp = -sparse(ii,jj,vv,n,n);
            tmp = tmp + triu(tmp,1)';
         else
            tmp = -sparse(ii,ones(len,1),vv,abs(n),1);
         end
         if (matno == 0)
            C{p,1} = tmp;
         else
            if (n > 1)
               At{p,1}(:,matno) = svec(blk(p,:),tmp,1);
            else
               At{p,1}(:,matno) = tmp;
            end
         end
      end
   end
%%
%% Construct big sparse block of A,C
%%
if (spnumblk > 0)
   Y1 = Y(:,1);
   diffY1 = find(diff([-1; Y1; inf]));
   for kk = 1:length(diffY1)-1
      idx = [diffY1(kk) : diffY1(kk+1)-1];
      matno = Y1(diffY1(kk));
      Ytmp  = Y(idx,1:5);
      Ytmp2 = Ytmp(:,2);
      maxYtmp2  = Ytmp2(length(Ytmp2));
      minYtmp2  = Ytmp2(1);
      diffYtmp2 = Ytmp2(find(diff([-1; Ytmp2])));
      for q = 1:spnumblk
         spblkidx    = spblkidxall{q};
         maxspblkidx = spblkidx(length(spblkidx));
         minspblkidx = spblkidx(1);
         count = 0;
         if (minYtmp2 <= maxspblkidx) & (maxYtmp2 >= minspblkidx)
            tmpblksize = blksize(spblkidx);
            n = sum(tmpblksize);
            cumspblksize = [0 cumsum(tmpblksize)];
            n2 = sum(tmpblksize.*(tmpblksize+1))/2;
            idx = zeros(n2,1); offset = zeros(n2,1);
            for t = [1:length(diffYtmp2)]
  	       p = find(spblkidx == diffYtmp2(t));
               if ~isempty(p)
	          idxtmp = find(Ytmp2 == spblkidx(p));
                  len = length(idxtmp);
     	          idx(count+[1:len]) = idxtmp;
                  offset(count+[1:len]) = cumspblksize(p);
                  count = count + len;
               end
            end
            idx = idx(1:count); offset = offset(1:count);
            ii = Ytmp(idx,3)+offset; jj = Ytmp(idx,4)+offset; vv = Ytmp(idx,5);
            idxtmp = find(ii > jj);
            if ~isempty(idxtmp);
               tmp = jj(idxtmp);
               jj(idxtmp) = ii(idxtmp); ii(idxtmp) = tmp;
            end
	    idxeq = find(ii==jj);
            tmp = spconvert([ii jj -vv; jj ii -vv; n n 0]) ...
                  + spconvert([ii(idxeq) jj(idxeq) vv(idxeq); n n 0]);
            if (matno == 0)
               C{denumblk+q,1} = tmp;
            else
               At{denumblk+q,1}(:,matno) = svec(blk(denumblk+q,:),tmp,1);
            end
         end
      end
   end
end
%%
%% put all linear blocks together as a single linear block
%%
   idx = find(linblkidx);
   if (length(idx) > 1)
      sdpidx = find(linblkidx==0);
      blktmp = 0; Atmp = []; Ctmp = [];
      for k = 1:length(idx)
          tmp = linblkidx(idx(k));
          blktmp = blktmp+blk{tmp,2};
          Atmp = [Atmp; At{tmp}];
          Ctmp = [Ctmp; C{tmp}];
      end
      At = At(sdpidx); C = C(sdpidx); blk = blk(sdpidx,:);
      len = length(sdpidx);
      blk(2:len+1,:) = blk;
      blk{1,1} = 'l'; blk{1,2} = blktmp;
      At(2:len+1,1) = At; C(2:len+1,1) = C;
      At{1,1} = Atmp; C{1,1} = Ctmp;
   end
%%******************************************************************


function [Dsubj, nf, r, thdemean, M] = surf_registration_stats(dirname, arg2, arg3)

%
% surf_registration_stats.m
%
% Original Author: Laurence Wastiaux
% CVS Revision Info:
%    $Author: nicks $
%    $Date: 2011/03/02 00:04:13 $
%    $Revision: 1.3 $
%
% Copyright © 2011 The General Hospital Corporation (Boston, MA) "MGH"
%
% Terms and conditions for use, reproduction, distribution and contribution
% are found in the 'FreeSurfer Software License Agreement' contained
% in the file 'LICENSE' found in the FreeSurfer distribution, and here:
%
% https://surfer.nmr.mgh.harvard.edu/fswiki/FreeSurferSoftwareLicense
%
% Reporting: freesurfer@nmr.mgh.harvard.edu
%

LoadTHMat=1;
D=[];
th=90;
if (nargin==3)
    D=arg2;
    th=arg3;
    LoadTHMat=0;
end
if (nargin==2)
    D=arg2;
    th=0.90;
    LoadTHMat=0;
end
files=dir(dirname);
nf=files;
length(files)
nv = 163842;
%D=zeros(length(files), nv);

%% 1- Load the thickness matrix (N_vertices x N_subjects) %%
if(LoadTHMat==1);
    for i_sub=5:300
        subject_name=files(i_sub).name;
        disp(subject_name)
        SubjectDir=strcat(dirname, '/', subject_name);
        SurfDir=strcat(SubjectDir, '/surf');

        % a- Ressample the thickness curv file to sphere %
        trglh_file=sprintf('~/lh.thickness.average7.mgh');
        trgrh_file=sprintf('~/rh.thickness.average7.mgh');

        if(exist(trglh_file))
            cmdrm=sprintf('rm %s', trglh_file);
            u=unix(cmdrm);
        end
        if(exist(trglh_file))
            cmdrm=sprintf('rm %s', trglh_file);
            u=unix(cmdrm);
        end

        lhthickness_file=strcat(SurfDir, '/lh.thickness');
        rhthickness_file=strcat(SurfDir, '/rh.thickness');
        if (isempty(SurfDir) | ~exist(lhthickness_file) | ~exist(rhthickness_file) )
            fprintf('thickness files do not exist\n');
            i_sub=i_sub+1;
        else
            %cmd_lh=sprintf('mri_surf2surf --srcsubject %s --srcsurfval thickness --src_type curv --trgsubject average7 --trgsurfval %s --trg_type mgh --hemi lh --nsmooth-in 100 --noreshape',subject_name, trglh_file);
            %cmd_rh=sprintf('mri_surf2surf --srcsubject %s --srcsurfval thickness --src_type curv --trgsubject average7 --trgsurfval %s --trg_type mgh --hemi rh --nsmooth-in 100 --noreshape',subject_name, trgrh_file);
            cmd_lh=sprintf('~/work/dev/mris_average_curvature/mris_average_curvature -a 100 -o average7 thickness lh sphere.reg %s %s', subject_name, trglh_file);
            u1=unix(cmd_lh);
            %u2=unix(cmd_rh);

            % b- Load the ressampled surface %
            if (exist(trglh_file)==0)
                fprintf('could not create the ressampled surface\n');
                i_sub=i_sub+1;
            else
                %[vol]=load_mgh(trglh_file);
                vol=read_curv(trglh_file);
                sz=size(vol)
                if(sz(1)~= nv)
                    msgerr=sprintf('Wrong ressampled surface');
                    error(msgerr)
                end
                D= [D ; vol'];
                nf(size(D,1)).name=subject_name;
            end
        end
    end
end
Dsubj=D;
%save('/space/okapi/3/data/laurence/surf_registration/thickness_avg100.mat', 'Dsubj');
%save('/space/okapi/3/data/laurence/surf_registration/Subj_Names.mat', 'nf');
sd=size(D);

nsubjs=sd(1);
nns=1:nsubjs;

%% 2- compute stats %%

% demean
thdemean = Dsubj - repmat(mean(Dsubj,2),[1 nv]);

% Covariance
M = thdemean*thdemean';

% % Jackknife
for jksubj = 1:nsubjs
  fprintf('%d *\n',jksubj);
  indjk = find(nns ~= jksubj);

  % SVD
  [u s v] = fast_svd(thdemean(indjk,:),M(indjk,indjk));
  fcvs(:,jksubj) = cumsum((diag(s.^2))/(sum(diag(s.^2))));

  % keep enough to explain 85% of the data. The fcvs does not
  % change that much regardless of which data set is jked
  nkeep(jksubj) = max(find(fcvs(:,jksubj)<th));
  v = v(:,1:nkeep(jksubj));

  % Extract the jkth subjects thickness and compute var
  thsubj = thdemean(jksubj,:);
  %thsubj = randn(size(thsubj));
  d0(jksubj) = var(thsubj);

  % Project out the first nkeep EVs and recompute var
  thsubjproj = thsubj - (thsubj*v)*v';
  d1(jksubj) = var(thsubjproj);

  fprintf('  nkeep = %3d, d0=%g, d1=%g, r=%g, rwhite = %g\n',...
	  nkeep(jksubj),d0(jksubj),d1(jksubj),d1(jksubj)/d0(jksubj),1-nkeep(jksubj)/size(thdemean,1));

end

% Compute percent residual variance
r = 100*d1./d0;
%save('/space/okapi/3/data/laurence/ADF/surf_registration/residual_var80.mat', 'r');
% Plot the histogram
% indr = find(r<25);
% rr = r(indr);
 [h x] = hist(r);
 p = h/sum(h);
 ph = plot(x,p,'r-');
% set(ph,'Linewidth',3);
% xlabel('Percent Residual Variance');
% title('Distribution of Percent Residual Variance in Thickness')
% set(gcf,'color',[1 1 1]);


% plot using mapping toolbox from shapefile
% download the shapefile from http://www.gadm.org (recommende is the one with 6 dissolved layers
%S=shaperead('/Users/reyesc/Downloads/gadm28_levels/gadm28_adm1.shp','UseGeoCoords',true); %1st administrative level
S=shaperead('/Users/reyesc/Downloads/gadm28_levels/gadm28_adm0.shp','UseGeoCoords',true); %country administrative level
figure
axesm lambert
framem
plotm([S.Lat],[S.Lon]);

%plot(ax,[S.Lon],[S.Lat],'color',[.5 .5 .5],'Tag','borders')


function[inds] = indicesOfAInB(A, B)
% [inds] = indicesOfAInB(A, B)
%
% Get the indices of a list B such that B(inds) == A.
% This assumes that each element of A is in B (but not the other way
% around).
% Note: % B need not be unique, but A does!
% Afterwards: B(indicesOfAInB(A, B)) == A
%
% Copyright by Holger Caesar, 2014

% Make column vectors
A = A(:)';
B = B(:)';

% Check for duplicates in A
Aun = unique(A, 'stable');
assert(isequal(A, Aun), 'Error: This function only works for unique elements in A (but not in B)!');

% Intersect A and B
[~, indsIntoB] = intersect(B, A);

% Since inter is sorted, we need to sort A as well
[~, AunSorting] = sort(A);

% Additional assertions to understand what's going on
% assert(isequal(A(Asorting), inter));
% assert(isequal(inter, B(indsIntoB)));

% Check if A is really included in B
checkIncluded = ismember(A, B);
if ~all(checkIncluded),
    notIncludedList = strjoin(A(find(~checkIncluded, 5)), ', ');
    error('Error: Some elements of A are not included in B! Examples are %s', notIncludedList);
end;

% Apply mappings from B to inter and then from inter to A
inds = indsIntoB(invertPermutation(AunSorting));

% Consistency check
assert(isequal(A, B(inds)));


function union2tet(surface_name,cage_name,union_name,tet_name)
  % UNION2TET Script to take 3 meshes, a surface, a partial cage that intersects the
  % surface and their volume-union's surface (probably from Blender), and use
  % tetgen to generate a tet mesh that has tets in the volume-union with faces
  % of the original surface .
  %
  % union2tet(surface_name,cage_name,union_name,tet_name)
  %
  % Inputs:
  %   surface_name  file containing original surface
  %   cage_name  file containing (partial) cage
  %   union_name  file containing union surface
  % Output:
  %   tet_name  file to be written with .mesh tet mesh
  %
  [SV,SF] = load_mesh(surface_name);
  [CV,CF] = load_mesh(cage_name);
  [UV,UF] = load_mesh(union_name);
  % combine union and surface so we have a list of faces for the union and the
  % original surface that look into the same vertex list
  [V,F] = combine(SV,SF,UV,UF);
  [T,V] = tetgen(V,F,setdiff(CV,V,'rows'),true);
  writeMESH(tet_name,V,T,SF);

  skeleton_name = strrep([tet_name '.tgf'],'.mesh','');
  % Find all edges in mesh, note internal edges are repeated
  CE = sort( ...
    [CF(:,1) CF(:,2); ...
    CF(:,2) CF(:,3); ...
    CF(:,3) CF(:,1)]')';
  % remove duplicates
  CE = unique(CE,'rows');
  writeTGF(skeleton_name,CV,CE);

end


% This is material illustrating the methods from the book
% Financial Modelling  - Theory, Implementation and Practice with Matlab
% source
% Wiley Finance Series
% ISBN 978-0-470-74489-5
%
% Date: 02.05.2012
%
% Authors:  Joerg Kienitz
%           Daniel Wetterau
%
% Please send comments, suggestions, bugs, code etc. to
% kienitzwetterau_FinModelling@gmx.de
%
% (C) Joerg Kienitz, Daniel Wetterau
%
% Since this piece of code is distributed via the mathworks file-exchange
% it is covered by the BSD license
%
% This code is being provided solely for information and general
% illustrative purposes. The authors will not be responsible for the
% consequences of reliance upon using the code or for numbers produced
% from using the code.

function optval = LookBackFixedStrike(S,K,C)
% S = NSim x Nt matrix of simulated prices
% K = Strike price
% C = 1 -> Call; C = 0 -> Put

    if(C == 1)
        optval = mean(max(S,2) - K, 0);
    else
        optval = mean(K - min(S,2) - K, 0);
    end
end


function ival = s_to_i4 ( s )

%*****************************************************************************80
%
%% S_TO_I4 reads an integer value from a string.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 November 2003
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string S, a string to be examined.
%
%    Output, integer IVAL, the integer value read from the string.
%
  sgn = 1;
  state = 0;
  ival = 0;

  i = 0;

  while ( i < s_len_trim ( s ) )

    i = i + 1;
    c = s(i);

    if ( state == 0 )

      if ( c == ' ' )

      elseif ( c == '-' )
        state = 1;
        sgn = -1;
      elseif ( c == '+' )
        state = 1;
        sgn = +1;
      elseif ( '0' <= c & c <= '9' )
        state = 2;
        ival = c - '0';
      else
        fprintf ( '\n' );
        fprintf ( 'S_TO_I4 - Fatal error!\n' );
        fprintf ( '  Illegal character %c while in state %d.\n', c, state );
        return;
      end
%
%  Have read the sign, now expecting the first digit.
%
    elseif ( state == 1 )

      if ( c == ' ' )

      elseif ( '0' <= c & c <= '9' )
        state = 2;
        ival = c - '0';
      else
        fprintf ( '\n' );
        fprintf ( 'S_TO_I4 - Fatal error!\n' );
        fprintf ( '  Illegal character %c while in state %d.\n', c, state );
        return
      end
%
%  Have read at least one digit, expecting more.
%
    elseif ( state == 2 )

      if ( '0' <= c & c <= '9' )
        ival = 10 * ival + c - '0';
      else
        ival = sgn * ival;
        return;
      end

    end

  end
%
%  If we read all the characters in the string, see if we're OK.
%
  if ( state ~= 2 )
    fprintf ( '\n' );
    fprintf ( 'S_TO_I4 - Fatal error!\n' );
    fprintf ( '  Did not read enough information to define an integer!\n' );
    return;
  end

  ival = sgn * ival;

  return
end


%% Description errorb(x,y,varargin)
% errorb(Y,E) plots Y and draws an error bar at each element of Y. The
% error bar is a distance of E(i) above and below the curve so that each
% bar is symmetric and 2*E(i) long.
% If Y and E are a matrices, errob groups the bars produced by the elements
% in each row and plots the error bars in their appropriate place above the
% bars.
%
% errorb(X,Y,E) plots Y versus X with
% symmetric error bars 2*E(i) long. X, Y, E must
% be the same size. When they are vectors, each error bar is a distance of E(i) above
% and below the point defined by (X(i),Y(i)).
%
% errorb(X,Y,'Parameter','Value',...) see below
%
%% Optional Parameters
%    horizontal: will plot the error bars horizontally rather than vertically
%    top: plot only the top half of the error bars (or right half for horizontal)
%    barwidth: the width of the little hats on the bars (default scales with the data!)
%              barwidth is a scale factor not an absolute value.
%    linewidth: the width of the lines the bars are made of (default is 2)
%    points: will plot the points as well, in the same colors.
%    color: specify a particular color for all the bars to be (default is black, this can be anything like 'blue' or [.5 .5 .5])
%    multicolor: will plot all the bars a different color (thanks to my linespecer function)
%    fill: this will plot error bounds in shaded color.
%                colormap: in the case that multicolor is specified, one
%                           may also specify a particular colormap to
%                           choose the colors from.
%% Examples
% y=rand(1,5)+1; e=rand(1,5)/4;
% hold off; bar(y,'facecolor',[.8 .8 .8]); hold on;
% errorb(y,e);
%
% defining x and y
% x=linspace(0,2*pi,8); y=sin(x); e=rand(1,8)/4;
% hold off; plot(x,y,'k','linewidth',2); hold on;
% errorb(x,y,e)
%
% group plot:
% values=abs(randn(2,3))+2; errors=abs(randn(2,3)/1.5+.5)/2;
% errorb(values,errors);
% errorb(values,errors,'top');
%
% % motivation for the function
% It is possible to plot nice error bars on top of a bar plot with Matlab's
% built in errorbar function by setting tons of different parameters to be
% various things.
% This function plots what I would consider to be nice error bars as the
% default, with no modifications necessary.
% It also plots, only the error bars, and in black. There are some very
% useful abilities that this function has over the matlab one, see below:
%
%% Acknowledgments
% Thank you to the AP-Lab at Boston University for funding me while I
% developed these functions. Thank you to the AP-Lab, Avi and Eli for help
% with designing and testing them.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Jonathan Lansey, last update Oct 2011,                                  %
%                   questions to Lansey at gmail.com                      %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function errorb(x,y,varargin)
%% first things first
%save the initial hold state of the figure.
hold_state = ishold;
if ~hold_state
    cla;
end

h=[];

%% If you are plotting errobars on Matlabs grouped bar plot
if size(x,1)>1 && size(x,2)>1 % if you need to do a group plot
% Plot bars
    num2Plot=size(x,2);
    e=y; y=x;
	handles.bars = bar(x, 'edgecolor','k', 'linewidth', 2);
	hold on
	for i = 1:num2Plot
		x =get(get(handles.bars(i),'children'), 'xdata');
		x = mean(x([1 3],:));
%       Now the recursive call!
		errorb(x,y(:,i), e(:,i),'barwidth',1/(num2Plot),varargin{:}); %errorb(x,y(:,i), e(:,i),'barwidth',1/(4*num2Plot),varargin{:});
    end
    if ~hold_state
        hold off;
    end
    return; % no need to see the rest of the function
else
    x=x(:)';
    y=y(:)';
    num2Plot=length(x);
end
%% Check if X and Y were passed or just X

if ~isempty(varargin)
    if ischar(varargin{1})
        justOneInputFlag=1;
        e=y; y=x; x=1:num2Plot;
    else
        justOneInputFlag=0;
        e=varargin{1}(:)';
    end
else % not text arguments, not even separate 'x' argument
    e=y; y=x; x=1:length(e);
    justOneInputFlag=0;
end

hold on; % axis is already cleared if hold was off
%% Check that your vectors are the proper length
if num2Plot~=length(e) || num2Plot~=length(y)
    error('your data must be vectors of all the same length')
end

%% Check that the errors are all positive
signCheck=min(0,min(e(:)));
if signCheck<0
    error('your error values must be greater than zero')
end

%% In case you don't specify color:
color2Plot = [ 0 0 0];
% set all the colors for each plot to be the same one ... hope you like black
for kk=1:num2Plot
    lineStyleOrder{kk}=color2Plot;
end

%% Initialize some things before accepting user parameters
horizontalFlag=0;
topFlag=0;
pointsFlag=0;
barFactor=1;
linewidth=2;
colormapper='jet';
multicolorFlag=0;
fillFlag=0;

%% User entered parameters
%  if there is just one input, then start at 1,
%  but if X and Y were passed then we need to start at 2
k = 1 + 1 - justOneInputFlag; %
%
while k <= length(varargin) && ischar(varargin{k})
    switch (lower(varargin{k}))
      case 'horizontal'
        horizontalFlag=1;
        if justOneInputFlag % need to switch x and y now
            x=y; y=1:num2Plot; % e is the same
        end
      case 'color' %
        color2Plot = varargin{k + 1};
%       set all the colors for each plot to be the same one
        for kk=1:num2Plot
            lineStyleOrder{kk}=color2Plot;
        end
        k = k + 1;
      case 'linewidth'
        linewidth = varargin{k + 1};
        k = k + 1;
      case {'barwidth','width','thickness'}
        barFactor = varargin{k + 1};
%         barWidthFlag=1;
        k = k + 1;
      case 'points'
        pointsFlag=1;
      case 'multicolor'
          multicolorFlag=1;
      case 'colormap' % used only if multicolor
        colormapper = varargin{k+1};
        k = k + 1;
      case 'top'
          topFlag=1;
        case 'fill'
            fillFlag=1;
      otherwise
        warning('Dude, you put in the wrong argument');
    end
    k = k + 1;
end

if ~fillFlag % plot errobars normally.

if multicolorFlag
    lineStyleOrder=linspecer(num2Plot,colormapper);
end

%% Set the bar's width if not set earlier
if num2Plot==1
%   defaultBarFactor=how much of the screen the default bar will take up if
%   there is only one number to work with.
    defaultBarFactor=20;
    p=axis;
    if horizontalFlag
        barWidth=barFactor*(p(4)-p(3))/defaultBarFactor;
    else
        barWidth=barFactor*(p(2)-p(1))/defaultBarFactor;
    end
else % is more than one datum
    if horizontalFlag
        barWidth=barFactor*(y(2)-y(1))/4;
    else
        barWidth=barFactor*(x(2)-x(1))/4;
    end
end

%% Plot the bars
for k=1:num2Plot
    if horizontalFlag
        ex=e(k);
        esy=barWidth/2;
%       the main line
        if ~topFlag || x(k)>=0  %also plot the bottom half.
            h(end+1) = plot([x(k)+ex x(k)],[y(k) y(k)],'color',lineStyleOrder{k},'linewidth',linewidth);
    %       the hat
            h(end+1) = plot([x(k)+ex x(k)+ex],[y(k)+esy y(k)-esy],'color',lineStyleOrder{k},'linewidth',linewidth);
        end
        if ~topFlag || x(k)<0  %also plot the bottom half.
            h(end+1) = plot([x(k) x(k)-ex],[y(k) y(k)],'color',lineStyleOrder{k},'linewidth',linewidth);
            h(end+1) = plot([x(k)-ex x(k)-ex],[y(k)+esy y(k)-esy],'color',lineStyleOrder{k},'linewidth',linewidth);
            %rest?
        end
    else %plot then vertically
        ey=e(k);
        esx=barWidth/2;
%         the main line
        if ~topFlag || y(k)>=0 %also plot the bottom half.
            h(end+1) = plot([x(k) x(k)],[y(k)+ey y(k)],'color',lineStyleOrder{k},'linewidth',linewidth);
    %       the hat
            h(end+1) = plot([x(k)+esx x(k)-esx],[y(k)+ey y(k)+ey],'color',lineStyleOrder{k},'linewidth',linewidth);
        end
        if ~topFlag || y(k)<0 %also plot the bottom half.
            h(end+1) = plot([x(k) x(k)],[y(k) y(k)-ey],'color',lineStyleOrder{k},'linewidth',linewidth);
            h(end+1) = plot([x(k)+esx x(k)-esx],[y(k)-ey y(k)-ey],'color',lineStyleOrder{k},'linewidth',linewidth);
        end
    end
end
%
%% plot the points, very simple

if pointsFlag
    for k=1:num2Plot
        h(end+1) = plot(x(k),y(k),'o','markersize',8,'color',lineStyleOrder{k},'MarkerFaceColor',lineStyleOrder{k});
    end
end

else % plot error bars by filling them in.

%     Plot the mean:
    plot(x,y,'linewidth',2,'color',color2Plot);
%     Make the polygon:

    xPoly = [x  fliplr(x) x(1)];
    yPoly = [y+e fliplr(y-e) y(1)+e(1)];

    h(end+1) = plot(xPoly,yPoly,'color',color2Plot)
    hReg = fill(xPoly,yPoly,color2Plot); % draw region
    set(get(get(hReg,'Annotation'),'LegendInformation'),'IconDisplayStyle','off'); % Exclude line from legend

end % fillFlag check over

for hLoop = 1:length(h)
    set(get(get(h(hLoop),'Annotation'),'LegendInformation'),'IconDisplayStyle','off');
end

drawnow;
% return the hold state of the figure
if ~hold_state
    hold off;
end

end

%%

function lineStyleOrder=linspecer(N,varargin)

% default colormap
colormap hot; A=colormap;

%% interperet varagin
if ~isempty(varargin)>0
    colormap (varargin{1}); A=colormap;
end

%%

if N<=0
    lineStyleOrder={};
    return;
end

values=round(linspace(1,50,N));
for n=1:N
    lineStyleOrder(n) = {A(values(n),:)};
end

end