function out_channel_ascii( BstFile, OutputFile, Format, isEEG, isHeadshape, isHeader, Factor, Transf)
% OUT_CHANNEL_ASCII: Exports a Brainstorm channel file in an ascii file.
%
% USAGE:  out_channel_ascii( BstFile, OutputFile, Format={X,Y,Z}, isEEG=1, isHeadshape=1, isHeader=0, Factor=.01, Transf=[]);
%
% INPUT:
%     - BstFile    : full path to Brainstorm file to export
%     - OutputFile : full path to output file
%     - Format     : Cell-array describing the columns in the ASCII file
%                    => 'X','Y','Z' : 3D position (float)
%                    => 'indice'    : indice (integer)
%                    => 'name'      : name (string)
%                    => otherwise   : do not use this column
%     - isEEG       : Writes the coordinates of the electrodes
%     - isHeadshape : Writes the coordinates of the headshape points
%     - isHeader    : Writes header (number of EEG points)
%     - Factor      : Factor to convert the positions values in meters.
%     - Transf      : 4x4 transformation matrix to apply to the 3D positions before saving
%                     or entire MRI structure for conversion to MNI space

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Francois Tadel, 2012-2020

%% ===== PARSE INPUTS =====
if (nargin < 3) || isempty(Format)
    Format = {'X','Y','Z'};
end
if (nargin < 4) || isempty(isEEG)
    isEEG = 1;
end
if (nargin < 5) || isempty(isHeadshape)
    isHeadshape = 1;
end
if (nargin < 6) || isempty(isHeader)
    isHeader = 0;
end
if (nargin < 7) || isempty(Factor)
    Factor = .01;
end
if (nargin < 8) || isempty(Transf)
    Transf = [];
end

% Load brainstorm channel file
BstMat = in_bst_channel(BstFile);
% Get all the positions
Loc    = zeros(3,0);
Label  = {};
if isEEG && isfield(BstMat, 'Channel') && ~isempty(BstMat.Channel)
    for i = 1:length(BstMat.Channel)
        if ~isempty(BstMat.Channel(i).Loc) && ~all(BstMat.Channel(i).Loc(:) == 0)
            Loc(:,end+1) = BstMat.Channel(i).Loc(:,1);
            Label{end+1} = strrep(BstMat.Channel(i).Name, ' ', '_');
        end
    end
end
if isHeadshape && isfield(BstMat, 'HeadPoints') && ~isempty(BstMat.HeadPoints) && ~isempty(BstMat.HeadPoints.Loc)
    Loc   = [Loc, BstMat.HeadPoints.Loc];
    Label = cat(2, Label, BstMat.HeadPoints.Label);
end

% Apply transformation
if ~isempty(Transf)
    % MNI coordinates: the entire MRI is passed in input
    if isstruct(Transf)
        Loc = cs_convert(Transf, 'scs', 'mni', Loc')';
    % World coordinates
    else
        R = Transf(1:3,1:3);
        T = Transf(1:3,4);
        Loc = R * Loc + T * ones(1, size(Loc,2));
    end
end
% Apply factor
Loc = Loc ./ Factor;

% Open output file
fid = fopen(OutputFile, 'w');
if (fid < 0)
   error('Cannot open file');
end
% Write header
nLoc = size(Loc,2);
if isHeader
    fwrite(fid, sprintf('%d\n', nLoc), 'char');
end
% Write file: one line per location
for i = 1:nLoc
    % Write each format entry
    for iF = 1:length(Format)
        % Entry types
        switch lower(Format{iF})
            case 'x',       str = sprintf('%1.4f', Loc(1,i));
            case '-x',      str = sprintf('%1.4f', -Loc(1,i));
            case 'y',       str = sprintf('%1.4f', Loc(2,i));
            case '-y',      str = sprintf('%1.4f', -Loc(2,i));
            case 'z',       str = sprintf('%1.4f', Loc(3,i));
            case '-z',      str = sprintf('%1.4f', -Loc(3,i));
            case 'indice',  str = sprintf('%d', i);
            case 'name',    str = Label{i};
            otherwise,      str = ' ';
        end
        % Write value
        fwrite(fid, str);
        % Add separator (space)
        if (iF ~= length(Format))
            fwrite(fid, sprintf('\t'));
        % Terminate line
        else
            fwrite(fid, 10);
        end
    end
end
% Close file
fclose(fid);


function sig = calcDoseSignature(doseIndex, planC)
%"calcDoseSignature"
%   Returns a signature to identify a dose distribution, for the purpose of
%   flagging DVHs as stale once the stored signature does not match an
%   existing dose distribution.
%
%   Currently uses the dose sum and the linear position of the
%   maxdose.  Some CRC signature may be possible in the future, if fast
%   code is available.
%
%JRA 12/3/04
%
%Usage:
%    function dS = calcDoseSignature(doseIndex, planC)
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.

indexS = planC{end};

try
    dA = getDoseArray((doseIndex), planC);

    [maxDose, loc]  = max(dA(:));
    doseSum         = sum(dA(:));
    sig             = [doseSum, loc];
catch
    error('Could not calculate dose signature for requested dose distribution.');
end


function benchmark_drift_simulation(rez, GTfilepath, simRecfilepath, sortType, bAutoMerge, varargin)

bOutFile = 0;

%these definitions for testing outside a script. comment out for normal calling!
%can leave out last 2 lines if output file not desired
% load('D:\test_new_sim\74U_20um_drift_standard\r28_KS2determ_r26rep\rez2.mat');
% GTfilepath = 'D:\test_new_sim\74U_20um_drift_standard\eMouseGroundTruth.mat';
% simRecfilepath = 'D:\test_new_sim\74U_20um_drift_standard\eMouseSimRecord.mat';
% bOutFile = 1;
% out_fid = fopen('D:\test_new_sim\74U_20um_drift_standard\r28_benchmark_output.txt','w');

sortType = 2;
bAutoMerge = 0;

load(GTfilepath);

if bAutoMerge
    testClu = 1 + rez.st3(:,5) ;
else
    testClu = rez.st3(:,2) ;
end

%fprintf( 'length of vargin: %d\n', numel(varargin));
if( numel(varargin) == 1)
    %path for output file
    bOutFile = 1;
    fprintf( 'output filename: %s\n', varargin{1} );
    out_fid = fopen( varargin{1}, 'w' );
end

testRes = rez.st3(:,1);

[testRes, tOrder] = sort(testRes);
testClu = testClu(tOrder);

%get cluster position footprint for each
[cluPos, unitSize] = getFootPrintRez(rez);

[allScores, allFPrates, allMissRates, allMerges, unDetected, overDetected, gtCluIDs] = ...
    compareClustering2_drift(gtClu, gtRes, testClu, testRes, []);

%

clid = unique(gtClu);
clear gtimes
for k = 1:length(clid)
    gtimes{k} = double(gtRes(gtClu==clid(k)));
end

%% figure and output results
autoMiss = (cellfun(@(x) x(1), allMissRates));
autoFP = (cellfun(@(x) x(1), allFPrates));
bestMiss = (cellfun(@(x) x(end), allMissRates));
bestFP = (cellfun(@(x) x(end), allFPrates));

autoScore = ones(1,numel(bestMiss));
autoScore = autoScore - autoMiss -autoFP;
bestScore = ones(1,numel(bestMiss));
bestScore = bestScore - bestMiss - bestFP;

figure

plot(sort(cellfun(@(x) x(1), allFPrates)), '-*b', 'Linewidth', 2)
hold all
plot(sort(cellfun(@(x) x(1), allMissRates)), '-*r', 'Linewidth', 2)
plot(sort(cellfun(@(x) x(end), allFPrates)), 'b', 'Linewidth', 2)
plot(sort(cellfun(@(x) x(end), allMissRates)), 'r', 'Linewidth', 2)
plot(sort(unDetected), 'g', 'Linewidth', 2);
%plot(sort(overDetected), '-g', 'Linewidth', 2);
ylim([0 1])
box off

thGood = 0.8;

fprintf('%d / %d good cells, score > %.2f (pre-merge) \n', sum(autoScore > thGood), numel(allScores), thGood)
fprintf('%d / %d good cells, score > %.2f (post-merge) \n', sum(bestScore > thGood), numel(allScores), thGood)

nMerges = cellfun(@(x) numel(x)-1, allMerges);
fprintf('Mean merges per good cell %2.2f \n', mean(nMerges(bestScore > thGood)))

% disp(cellfun(@(x) x(end), allScores))

xlabel('ground truth cluster')
ylabel('fractional error')

legend('false positives (initial)', 'miss rates (initial)', 'false positives (best)', 'miss rates (best)', 'undetected')
legend boxoff
set(gca, 'Fontsize', 15)
set(gcf, 'Color', 'w')

if bAutoMerge
    titleStr = sprintf('Kilosort%d with Automerge', sortType);
else
    titleStr = sprintf('Kilosort%d Results', sortType);
end
title(titleStr)

hold off;

%Calculate results vs. known unit properties

%sort these in order of the GT label
[~, sortLabelInd] = sort(gtCluIDs);

bestMiss = bestMiss(sortLabelInd);
bestFP = bestFP(sortLabelInd);

%read in amplitude data for the clusters
%contains yDriftRec nGTSpike x 4 array with
%   spike time in seconds
%   yDrift position
%   GT cluster label
%   nominal amplitude at the monitor site (before mulitplying by factor to
%   create amplitude std)
%
load(simRecfilepath);

%get average amplitude for each cluLabel
NN = numel(unique(yDriftRec(:,3)));
meanAmp = zeros(1,NN);
meanPos = zeros(1,NN);
nSpike = zeros(1,NN);
%for the special case of simulated data, the labels start at 1 and are
%sequential
for i = 1:NN
    ind = find(yDriftRec(:,3) == i);
    nSpike(i) = numel(ind);
    meanAmp(i) = mean(yDriftRec(ind,4));
    meanPos(i) = mean(yDriftRec(ind,2));
end

if( bOutFile )
    fprintf(out_fid, 'GTlabel\tnSpike\tmeanAmp\tmeanPos\tundetected\tbestMiss\tbestFP\tbestScore\tautoMiss\tautoFP\tautoScore\tnMerges\tphy labels\n');
else
    fprintf('GTlabel\tnSpike\tmeanAmp\tmeanPos\tundetected\tbestMiss\tbestFP\tbestScore\tautoMiss\tautoFP\tautoScore\tnMerges\tphy labels\n');
end

nMerges = zeros(1,NN);
for i = 1:NN
    nMerges(i) = length(allMerges{i})-1;
    if( bOutFile)
        fprintf(out_fid, '%d\t%d\t%.3f\t%.3f\t%.3f\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\t%d\t', ...
        i, nSpike(i), meanAmp(i), ...
        meanPos(i), unDetected(i), bestMiss(i), bestFP(i),bestScore(i), autoMiss(i),...
        autoFP(i), autoScore(i), nMerges(i));
        for j = 1:length(allMerges{i})-1
            fprintf( out_fid, '%d,', allMerges{i}(j)-1 );
        end
        fprintf(out_fid,'%d\n',allMerges{i}(length(allMerges{i}))-1);
    else
        fprintf('%d\t%d\t%.3f\t%.3f\t%.3f\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\t%d\t', ...
        i, nSpike(i), meanAmp(i), ...
        meanPos(i), unDetected(i), bestMiss(i), bestFP(i),bestScore(i), autoMiss(i),...
        autoFP(i), autoScore(i), nMerges(i));
        for j = 1:length(allMerges{i})-1
            fprintf( '%d,', allMerges{i}(j)-1 );
        end
        fprintf('%d\n',allMerges{i}(length(allMerges{i}))-1);
    end
end

fclose(out_fid);

end


%  Function gets activations of network (net) when it infers on an image
%  (img), for only specified layers (layers_to_use)
%
%  @authors: ufukefe, kutalmisince
%  Created on March 23, 2021
%  @Middle East Technical University, Center for Image Analysis
%  Last Edited on July 1, 2021

function activations = GetActivations(img,net,layers_to_use)

    % Check the type of the input image
    if ~isa(img, 'single')
        img = single(img);
    end

    % Forward pass
    net.eval({'x0',gpuArray(img)});

    % Insert activations inside cell array
    activations = cell(size(layers_to_use,1),2);

    for i=1:size(layers_to_use,1)
        activations{i,1} = layers_to_use{i};

        activations{i,2} = ...
        gather(net.vars(getVarIndex(net,net.layers(getLayerIndex(net, layers_to_use{i})).outputs)).value);
    end

    % Reset network for memory issues
    reset(net);

end


%% Test
disp('Accuracy per subject:')
disp(acc)
disp('Average accuracy:')
disp(mean(acc))

confusionchart(total_conf);


%% Enumerated
% Abstract superclass for enumerated quantities.

%%% Description
% |Enumerated| is the superclass of classes representing enumerated quantities.
% Each subclass of |Enumerated| allows only instances predefined by
% |enumeration|.  For more details about |enumeration|, see
% <matlab:web(['jar:file://',fullfile(matlabroot,'help','techdoc','help.jar!','matlab_oop','br4imrp.html')],'-helpbrowser')
% Enumerations>.
%
% |Enumerated| supports conversion of its instance into a string by |char()|,
% and into an integer by |int()|.
%
% Each concrete subclass of |Enumerated| allows comparison between its
% instances, i.e., supports relational operators <, <=, ==, >=, and >.  Also,
% the result consistent with this comparison is returned by |sort()| on a vector
% of these instances.

%%% Concrete Subclasses
% * <Axis.html |Axis|>: Catesion axes
% * <BC.html |BC|>: boundary conditions
% * <Dir.html |Dir|>: horizontal and vertical directions
% * <GT.html |GT|>: grid kinds
% * <PhysQ.html |PhysQ|>: physical quantities
% * <PML.html |PML|>: PML kinds
% * <Sign.html |Sign|>: negative and positive signs

%%% Methods (static)
% Below, |Enumerated| must be replaced by a concrete subclass.
%
% * |Enumerated.elems()|: returns a row vector of all instances
% * |Enumerated.count()|: returns the number of all instances

%%% Methods (public)
% Below, |enumerated| is an instance of a concrete subclass of |Enumerated|.
%
% * |char(enumerated)|: name of |enumerated|
% * |int(enumerated)|: integer representation of |enumerated|

%%% Example
% Below, the methods of |Enumerated| are demonstrated using a concrete subclass
% <Axis.html |Axis|>.
%
%   % Test conversion to integers and strings.
%   fprintf('Total # of Axis objects: %d\n', Axis.count);
%   for w = Axis.elems
%       fprintf('Name of Axis object %d: %s\n', int(w), char(w));
%   end
%
%   % Test sort().
%   unsorted = [Axis.z, Axis.x, Axis.y];
%   fprintf('\nBefore sort: ');
%   for w = unsorted
%       fprintf('%s  ', char(w));
%   end
%
%   fprintf('\nAfter sort: ');
%   sorted = sort(unsorted);
%   for w = sorted
%       fprintf('%s  ', char(w));
%   end
%   fprintf('\n');

classdef Enumerated < handle
	properties (SetAccess = immutable, GetAccess = private)
		name
	end

	methods (Abstract, Static)
		elems = elems(ind)
		count = count()
	end

%   (Deleted because it uses Axis rather than Enumerated, and also because
%   loading does not generate warnings without loadobj(); only saveobj() seems
%   necessary.)
% 	methods(Static)
% 		function obj = loadobj(S)
% 			% If saveobj() and loadobj() are not implemented, a warning is
% 			% issued when loading a saved Enumerated object.
% 			obj = Axis(char(S));
% 		end
% 	end

	methods
		function this = Enumerated(name)
			chkarg(ischar(name), '"name" should be string.');
			this.name = name;
		end

		function S = saveobj(this)
			% If saveobj() and loadobj() are not implemented, a warning is
			% issued when loading a saved Enumerated object.
			S.name = char(this);
		end

		function name = char(this)
			% This function returned name = this.name originally, but it is
			% modified to handle arguments given as arrays.
% 			name = this.name;
			name = cell2mat(arrayfun(@(x) x.name, this, 'UniformOutput', false));
		end

		function n = int(this)
			% This function returned n = find(this.elems==this) originally, but
			% it is modified to handle arguments given as arrays.
% 			[~, n] = ismember(this, this.elems, 'legacy');
% 			[~, n] = ismember(this, this.elems);
			n = arrayfun(@(x) find(this(1).elems==x), this);
		end

		function ind = subsindex(this)
			ind = int(this) - 1;
		end

		function c = plus(this, another)
				c = int(this) + double(another);
		end

		function [sorted, ind] = sort(this, varargin)
			n = length(this);
			nums = NaN(1, n);
			for i = 1:n
				nums(i) = int(this(i));
			end
			[~, ind] = sort(nums, varargin{:});
			sorted = this(ind);
		end

		function truth = lt(this, another)
			cn = class(this);  % class name
			chkarg(istypesizeof(another, cn), 'cannot compare %s with %s.', cn, class(another));
			truth = int(this) < int(another);
		end

		function truth = le(this, another)
			cn = class(this);  % class name
			chkarg(istypesizeof(another, cn), 'cannot compare %s with %s.', cn, class(another));
			truth = int(this) <= int(another);
		end

		function truth = gt(this, another)
			cn = class(this);  % class name
			chkarg(istypesizeof(another, cn), 'cannot compare %s with %s.', cn, class(another));
			truth = int(this) > int(another);
		end

		function truth = ge(this, another)
			cn = class(this);  % class name
			chkarg(istypesizeof(another, cn), 'cannot compare %s with %s.', cn, class(another));
			truth = int(this) >= int(another);
		end
	end
end


classdef TotalCoordinatesCalculator < handle

    properties (Access = public, Abstract)
        c
        theta
        nodes
        vertCoord
        boundCoord
        div
        totalCoord
    end

    methods (Access = public, Static)

        function obj = create(cParams)
            obj = TotalCoordinatesCalculatorFactory.create(cParams);
        end

    end

    methods (Access = protected)

        function init(obj,cParams)
            obj.c  = cParams.c;
            obj.theta = cParams.theta;
            obj.nodes = cParams.nodes;
            obj.vertCoord = cParams.vertCoord;
            obj.boundCoord = cParams.boundCoord;
            obj.div = cParams.div;
            obj.totalCoord = [];
        end

        function initBoundary(obj)
            boundNodes = obj.nodes.bound;
            obj.totalCoord(1:boundNodes,:) = obj.boundCoord;
        end

    end

end


% =========================================================================
% Test code for Super-Resolution Convolutional Neural Networks (SRCNN)
%
% Reference
%   Chao Dong, Chen Change Loy, Kaiming He, Xiaoou Tang. Learning a Deep Convolutional Network for Image Super-Resolution,
%   in Proceedings of European Conference on Computer Vision (ECCV), 2014
%
%   Chao Dong, Chen Change Loy, Kaiming He, Xiaoou Tang. Image Super-Resolution Using Deep Convolutional Networks,
%   arXiv:1501.00092
%
% Chao Dong
% IE Department, The Chinese University of Hong Kong
% For any question, send email to ndc.forward@gmail.com
% =========================================================================

close all;
clear all;

%% read ground truth image
im  = imread('Set5\butterfly_GT.bmp');
%im  = imread('Set14\zebra.bmp');

%% set parameters
up_scale = 3;
model = 'model\9-5-5(ImageNet)\x3.mat';
% up_scale = 3;
% model = 'model\9-3-5(ImageNet)\x3.mat';
% up_scale = 3;
% model = 'model\9-1-5(91 images)\x3.mat';
% up_scale = 2;
% model = 'model\9-5-5(ImageNet)\x2.mat';
% up_scale = 4;
% model = 'model\9-5-5(ImageNet)\x4.mat';

%% work on illuminance only
if size(im,3)>1
    im = rgb2ycbcr(im);
    im = im(:, :, 1);
end
im_gnd = modcrop(im, up_scale);
im_gnd = single(im_gnd)/255;

%% bicubic interpolation
im_l = imresize(im_gnd, 1/up_scale, 'bicubic');
im_b = imresize(im_l, up_scale, 'bicubic');

%% SRCNN
im_h = SRCNN(model, im_b);

%% remove border
im_h = shave(uint8(im_h * 255), [up_scale, up_scale]);
im_gnd = shave(uint8(im_gnd * 255), [up_scale, up_scale]);
im_b = shave(uint8(im_b * 255), [up_scale, up_scale]);

%% compute PSNR
psnr_bic = compute_psnr(im_gnd,im_b);
psnr_srcnn = compute_psnr(im_gnd,im_h);

%% show results
fprintf('PSNR for Bicubic Interpolation: %f dB\n', psnr_bic);
fprintf('PSNR for SRCNN Reconstruction: %f dB\n', psnr_srcnn);

figure, imshow(im_b); title('Bicubic Interpolation');
figure, imshow(im_h); title('SRCNN Reconstruction');

%imwrite(im_b, ['Bicubic Interpolation' '.bmp']);
%imwrite(im_h, ['SRCNN Reconstruction' '.bmp']);


function model = vargplvmInitDynamics(model,optionsDyn)
% VARGPLVMINITDYNAMICS Initialize the dynamics of a var-GPLVM model.
% FORMAT
% ARG optionsDyn : the VARGPLVM structure with the options used to
% create the vargplvm model..
%
%
% COPYRIGHT : Michalis K. Titsias, 2011
% COPYRIGHT : Neil D. Lawrence, 2011
% COPYRIGHT : Andreas C. Damianou, 2011
%
% SEEALSO : vargplvmOptionsDyn, vargplvmAddDynamics

% VARGPLVM

if ~isfield(model, 'dynamics') || isempty(model.dynamics)
    error(['model does not have field dynamics']);
end

%model.dynamics.kern.comp{1}.inverseWidth = 200./(((max(model.dynamics.t)-min(model.dynamics.t))).^2);
%params = vargplvmExtractParam(model);
%model = vargplvmExpandParam(model, params);

% Initialize barmu: first initialize X (mu) and then (see lines below)
% initialize barmu. The first 'if' statement checks if optionsDyn.initX is
% the initial X itself (e.g. calculated before in the demo) and there is no
% need to recalculate it.
if isfield(optionsDyn,'initX') && ~isstr(optionsDyn.initX)
    X = optionsDyn.initX;
else
    if isfield(optionsDyn,'initX')
        initFunc = str2func([optionsDyn.initX 'Embed']);
    else
        initFunc=str2func('ppcaEmbed');
    end

    % If the model is in "D greater than N" mode, then we want initializations
    % to be performed with the original model.m
    if isfield(model, 'DgtN') && model.DgtN
        X = initFunc(model.mOrig, model.q);
    else
        X = initFunc(model.m, model.q);
    end
end

%---------------------- TEMP -------------------------------%
% The following are several tries to make the init. of the means better.
% It does that by "squeezing" the ends of the means to values closer to
% zero.

% X(1,:)=zeros(size(X(1,:)));
% X(end,:)=zeros(size(X(1,:)));

% X = 0.1*randn(size(X));
% X(1,:)=zeros(size(X(1,:)));
% X(end,:)=zeros(size(X(1,:)));

% m = floor((size(X,1))/2);
% p=max(max(abs(X))); p=p/10; %p = p^(1/m);
% l = logspace(p,0,m);
% l2 = logspace(p,0,m);
% l2 = l2(end:-1:1);
% l = [l l2]';
% mask = repmat(l,1,size(X,2));
% X = X.*(1./mask);
% X(1,:) = zeros(size(X(1,:)));
% X(end,:) = zeros(size(X(1,:)));
% X(end-1,:) = zeros(size(X(1,:)));

%save 'TEMPX.mat' 'X' %%TEMP

if optionsDyn.regularizeMeans
    model.dynamics.regularizeMeans = 1;
    m = floor((size(X,1))/7);  % 7
    p=ones(1,model.q);
    mm=max(X).^(1/2); %1/2 % the smallest this ratio(the exponent) is, the largest the effect
    for i=0:m-4
        X(end-i,:) = X(end-i,:) -  X(end-i,:).*p;
        p = p./mm;
    end
    p=ones(1,model.q);
    for i=1:m
        X(i,:) = X(i,:) -  X(i,:).*p;
        p = p./mm;
    end
end

% The initial covariances we aim for, via calibrating the reparametrised
% covariances and measuring their median
if ~isfield(optionsDyn, 'initCovarMedian') || isempty(optionsDyn.initCovarMedian)
    initCovarMedian = 0.18;
else
    initCovarMedian = optionsDyn.initCovarMedian;
end
% The lowest acceptable value of the above
if ~isfield(optionsDyn, 'initCovarMedianLowest') || isempty(optionsDyn.initCovarMedianLowest)
    initCovarMedianLowest = initCovarMedian/1.8;
else
    initCovarMedianLowest = optionsDyn.initCovarMedianLowest;
end
% The highest acceptable value of the above
if ~isfield(optionsDyn, 'initCovarMedianHighest') || isempty(optionsDyn.initCovarMedianHighest)
    initCovarMedianHighest = initCovarMedian/0.3;
else
    initCovarMedianHighest = optionsDyn.initCovarMedianHighest;
end

%model.X = X;

% m = floor((size(X,1))/2);
% l = logspace(10,1,m);
% l2 = logspace(10,1,m);
% l2 = l2(end:-1:1);
% mask = repmat([l l2]',1,size(X,2));
% X2 = X-X.*mask;

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

vX = var(X);
noise = 0;%.01;
for q=1:model.q
    Lkt = chol(model.dynamics.Kt + noise*vX(q)*eye(model.N))';
    % barmu = inv(Kt + s*I)*X, so that  mu = Kt*barmu =  Kt*inv(Kt +
    % s*I)*X, which is jsut the GP prediction, is temporally smoothed version
    % of the PCA latent variables X (for the data Y)
    model.dynamics.vardist.means(:,q) = Lkt'\(Lkt\X(:,q));
end

if isfield(optionsDyn, 'vardistCovars') && ~isempty(optionsDyn.vardistCovars)
    if length(optionsDyn.vardistCovars) ==1
        model.dynamics.vardist.covars = 0.1*ones(model.N,model.q) + 0.001*randn(model.N,model.q);
        model.dynamics.vardist.covars(model.dynamics.vardist.covars<0.05) = 0.05;
        model.dynamics.vardist.covars = optionsDyn.vardistCovars * ones(size(model.dynamics.vardist.covars));
    elseif size(optionsDyn.vardistCovars) == size(model.dynamics.vardist.covars)
        model.dynamics.vardist.covars = optionsDyn.vardistCovars;
    end
else % Try to automatically find a satisfactory value for the initial reparametrized
     % covariances (lambda) so that the median of the real covariances is
     % as close as possible to an ideal value, eg 0.18
    fprintf(1, '# Finding an initial value for the reparametrized covariance, aiming at median(S)=%.2f...',initCovarMedian)
    % Try an initial calibration in the default search region of the
    % parameters
    [bestVdc, bestMed] = calibrateLambda(model, 0.05, 0.05, 3, initCovarMedian);
    if bestMed < initCovarMedianLowest || bestMed > initCovarMedianHighest
        % The above search failed. Try some other intervals for the search
        % parameter.
        fprintf(1, '.')
        [bestVdcNew, bestMedNew] = calibrateLambda(model, 0.0008 , 0.05, 0.05, initCovarMedian);
        if abs(bestMedNew - initCovarMedian) < abs(bestMed - initCovarMedian)
            bestMed = bestMedNew;
            bestVdc = bestVdcNew;
        end
    end
    if bestMed < initCovarMedianLowest || bestMed > initCovarMedianHighest
        % Repeat as above for a different interval.
        fprintf(1, '.')
        [bestVdcNew, bestMedNew] = calibrateLambda(model, 3, 0.05, 6.5, initCovarMedian);
        if abs(bestMedNew - initCovarMedian) < abs(bestMed - initCovarMedian)
            bestMed = bestMedNew;
            bestVdc = bestVdcNew;
        end
    end
    fprintf(1, '\n')
    model.dynamics.vardist.covars = 0.1*ones(model.N,model.q) + 0.001*randn(model.N,model.q);
    model.dynamics.vardist.covars(model.dynamics.vardist.covars<0.05) = 0.05;
    model.dynamics.vardist.covars = bestVdc * ones(size(model.dynamics.vardist.covars));
    model = vargplvmDynamicsUpdateStats(model);
    fprintf('# Automatically calibrated lambda so that median(covars)=%.2f\n',median(model.vardist.covars(:)))
end

% smaller lengthscales for the base model
%model.kern.comp{1}.inputScales = 5./(((max(X)-min(X))).^2);
params = vargplvmExtractParam(model);
model = vargplvmExpandParam(model, params);

if isfield(optionsDyn,'X_u')
    model.X_u = optionsDyn.X_u;
else
    % inducing point need to initilize based on model.vardist.means
    if model.k <= model.N % model.N = size(mode.vardist.means,1)
        if ~isfield(optionsDyn, 'labels')
            ind = randperm(model.N);
            ind = ind(1:model.k);
            model.X_u = model.X(ind, :);
        else
            % in the case that class labels are supplied, make sure that inducing inputs
            % from all classes are chosen
            [idcs, nSmpls] = class_samples( optionsDyn.labels, model.k );

            count = 1;
            midx = [];
            for inds = idcs
                ind   = inds{:};
                ind   = ind(randperm(numel(ind)));
                idx  = ind(1:nSmpls(count));

                % test that there is no overlap between index sets
                assert(isempty(intersect(midx, idx)));
                midx = [midx, idx];

                count = count+1;
            end
            model.X_u = model.X(midx,:);
        end
    else
        samplingInd=0; %% TEMP
        if samplingInd
            % !!! We could also try to sample all inducing points (more uniform
            % solution)
            % This only works if k<= 2*N
            model.X_u=zeros(model.k, model.q);
            ind = randperm(model.N);
            %ind = ind(1:model.N);
            model.X_u(1:model.N,:) = model.X(ind, :);

            % The remaining k-N points are sampled from the (k-N) first
            % distributions of the variational distribution (this could be done
            % randomly as well).
            dif=model.k-model.N;
            model.X_u(model.N+1:model.N+dif,:)=model.vardist.means(1:dif,:) + rand(size(model.vardist.means(1:dif,:))).*sqrt(model.vardist.covars(1:dif,:));  % Sampling from a Gaussian.
        else
            % !!! The following is not a good idea because identical initial
            % ind.points are difficult to optimise... better add some
            % additional noise.
            model.X_u=zeros(model.k, model.q);
            for i=1:model.k
                %ind=randi([1 size(model.vardist.means,1)]);
                % Some versions do not have randi... do it with rendperm
                % instead:
                ind=randperm(size(model.vardist.means,1));
                ind=ind(1);
                model.X_u(i,:) = model.vardist.means(ind,:)+0.001*randn(1,model.q);
            end
        end
    end
end

if isfield(optionsDyn, 'testReoptimise')
    model.dynamics.reoptimise = optionsDyn.testReoptimise;
end

model.dynamics.learnVariance = optionsDyn.learnVariance; % DEFAULT: 0

if isfield(optionsDyn, 'constrainType') && ~isempty(optionsDyn.constrainType)
    model.dynamics.constrainType = optionsDyn.constrainType;
end

params = vargplvmExtractParam(model);
model = vargplvmExpandParam(model, params);

med = median(model.vardist.covars(:));
minC = min(model.vardist.covars(:));
maxC = max(model.vardist.covars(:));
if med < initCovarMedianLowest || med > initCovarMedianHighest
   warning('!!! [Min Median Max] value of variational covariances is [%1.2f %1.2f %1.2f].\n', minC, med, maxC);
else
    fprintf('# [Min Median Max] value of variational covariances is [%1.2f %1.2f %1.2f].\n', minC, med, maxC);
end
end

function [bestVdc, bestMed] = calibrateLambda(model, from, step, to, initCovarMedian)
    if nargin < 2 || isempty(from)
        from = 0.05;
    end
    if nargin < 3 || isempty(step)
        step = 0.05;
    end
    if nargin < 4 || isempty(to)
        to = 3;
    end
    if nargin < 5 || isempty(initCovarMedian)
        initCovarMedian = 0.18;
    end

    bestVdc = 0.05; bestDiff = 1000;
    for vdc = [from:step:to]
        model.dynamics.vardist.covars = 0.1*ones(model.N,model.q) + 0.001*randn(model.N,model.q);
        model.dynamics.vardist.covars(model.dynamics.vardist.covars<0.05) = 0.05;
        model.dynamics.vardist.covars = vdc * ones(size(model.dynamics.vardist.covars));
        modelNew = vargplvmDynamicsUpdateStats(model);
        med = median(modelNew.vardist.covars(:));
        curDiff = abs(med - initCovarMedian);
        if (curDiff) < bestDiff % "Ideal" median is initCovarMedian
            bestVdc = vdc;
            bestDiff = curDiff;
            bestMed = med;
        end
    end
end


function g = fileKernGradient(kern, x, varargin)

% FILEKERNGRADIENT Gradient of FILE kernel's parameters.
% FORMAT
% DESC computes the gradient of functions with respect to the
% stored file
% kernel's parameters. As well as the kernel structure and the
% input positions, the user provides a matrix PARTIAL which gives
% the partial derivatives of the function with respect to the
% relevant elements of the kernel matrix.
% ARG kern : the kernel structure for which the gradients are being
% computed.
% ARG x : the input locations for which the gradients are being
% computed.
% ARG partial : matrix of partial derivatives of the function of
% interest with respect to the kernel matrix. The argument takes
% the form of a square matrix of dimension  numData, where numData is
% the number of rows in X.
% RETURN g : gradients of the function of interest with respect to
% the kernel parameters. The ordering of the vector should match
% that provided by the function kernExtractParam.
%
% FORMAT
% DESC computes the derivatives as above, but input locations are
% now provided in two matrices associated with rows and columns of
% the kernel matrix.
% ARG kern : the kernel structure for which the gradients are being
% computed.
% ARG x1 : the input locations associated with the rows of the
% kernel matrix.
% ARG x2 : the input locations associated with the columns of the
% kernel matrix.
% ARG partial : matrix of partial derivatives of the function of
% interest with respect to the kernel matrix. The matrix should
% have the same number of rows as X1 and the same number of columns
% as X2 has rows.
% RETURN g : gradients of the function of interest with respect to
% the kernel parameters.
%
% SEEALSO fileKernParamInit, kernGradient, fileKernDiagGradient, kernGradX
%
% COPYRIGHT : Neil D. Lawrence, 2005, 2006

% KERN

% The last argument is covGrad
if nargin < 4
  [k, sk] = fileKernCompute(kern, x);
else
  [k, sk] = fileKernCompute(kern, x, varargin{1});
end
g(1) =  sum(sum(varargin{end}.*sk));
%/~
if any(isnan(g))
  warning('g is NaN')
end
%~/


classdef ProductComputerFactory < handle

    properties (Access = private)
        secondOrder
        fourthOrder
        secondOrderOut
        productComputer
    end

    methods (Access = public)

        function pComp = create(obj,C,e)
            obj.init(C,e)
            obj.createProductComputer()
            pComp = obj.getProductComputer();
        end
    end

    methods (Access = private)

        function init(obj,C,e)
           obj.fourthOrder = C;
           obj.secondOrder = e;
        end

        function  createProductComputer(obj)
            C = obj.fourthOrder;
            e = obj.secondOrder;

            if obj.isVoigt()
                p = ProductComputerForVoigt(C,e);
            elseif obj.isTensor()
                p = ProductComputerForTensor(C,e);
            else
                 error('Not possible to compute Product with these classes')
            end

            obj.productComputer = p;

        end

        function itIs = isVoigt(obj)
            isFourthVoigt = strcmp(obj.fourthOrder.getRepresentation(),'voigt');
            isSecondVoigt = strcmp(obj.secondOrder.getRepresentation(),'voigt');
            itIs = isFourthVoigt && isSecondVoigt;
        end

        function itIs = isTensor(obj)
            isFourthVoigt = strcmp(obj.fourthOrder.getRepresentation(),'tensor');
            isSecondVoigt = strcmp(obj.secondOrder.getRepresentation(),'tensor');
            itIs = isFourthVoigt && isSecondVoigt;
        end

        function p = getProductComputer(obj)
            p = obj.productComputer;
        end

    end

end


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

%% -*- texinfo -*-
%% @documentencoding UTF-8
%% @defmethod  @@sym function_handle (@var{f})
%% @defmethodx @@sym function_handle (@var{f1}, @dots{}, @var{fn})
%% @defmethodx @@sym function_handle (@dots{}, @var{param}, @var{value})
%% @defmethodx @@sym function_handle (@dots{}, 'vars', [@var{x} @dots{} @var{z}])
%% @defmethodx @@sym function_handle (@dots{}, 'file', @var{filename})
%% @defmethodx @@sym function_handle (@dots{}, 'outputs', [@var{o1} @dots{} @var{on}])
%% Convert symbolic expression into a standard function.
%%
%% This can make anonymous functions from symbolic expressions:
%% @example
%% @group
%% syms x y
%% f = x^2 + sin(y)
%%   @result{} f = (sym)
%%        2
%%       x  + sin(y)
%% h = function_handle(f)
%%   @result{} h = @@(x, y) x .^ 2 + sin (y)
%% h(2, pi/2)
%%   @result{} ans =  5
%% @end group
%% @end example
%%
%% Multiple arguments correspond to multiple outputs of the
%% function.  For example, the final @code{x} in this example
%% specifies the third output (rather than the input):
%% @example
%% @group
%% h = function_handle(x^2, 5*x, x);
%% [a, b, c] = h(2)
%%   @result{} a = 4
%%   @result{} b = 10
%%   @result{} c = 2
%% @end group
%% @end example
%%
%% The order and number of inputs can be specified:
%% @example
%% @group
%% syms x y z
%% h = function_handle(f, 'vars', [z y x])
%%   @result{} h = @@(z, y, x) x .^ 2 + sin (y)
%% @end group
%% @end example
%%
%% For compatibility with the Symbolic Math Toolbox in Matlab, we
%% provide a synonym: @pxref{@@sym/matlabFunction}
%%
%% OctSymPy can also generate an @code{.m} file from a symbolic
%% expression by passing the keyword @code{file} with a string
%% argument for @var{filename}.  A handle to the function in the
%% file will be returned.
%% Passing an empty @var{filename} creates an anonymous function:
%% @example
%% @group
%% h = function_handle(f, 'file', '')
%%   @result{} h = @@(x, y) x .^ 2 + sin (y)
%% @end group
%% @end example
%%
%% FIXME: naming outputs with @var{PARAM} as @code{outputs}
%% not implemented.
%%
%% FIXME: does not ``optimize'' code, for example, using common
%% subexpression elimination.
%%
%% @seealso{@@sym/ccode, @@sym/fortran, @@sym/latex, @@sym/matlabFunction}
%% @end defmethod

function f = function_handle(varargin)

  % We use the private/codegen function only for its input parsing
  [flg, meh] = codegen(varargin{:}, 'lang', 'octave');
  assert(flg == -1);
  [Nin, inputs, inputstr, Nout, param] = deal(meh{:});

  %% Outputs
  if (param.codegen) && (~isempty(param.fname))
    cmd = { '(expr,fcnname,filename,showhdr,in_vars) = _ins' ...
            'from sympy.utilities.codegen import codegen' ...
            'try:' ...
           ['    out = codegen((fcnname,expr), "' param.lang ...
            '", filename, header=showhdr' ...
            ', argument_sequence=in_vars)'] ...
            'except ValueError as e:' ...
            '    return (False, str(e))' ...
            'return (True, out)' };

    [fcnpath, fcnname, fcnext] = fileparts(param.fname);
    [worked, out] = pycall_sympy__ (cmd, varargin(1:Nout), fcnname, fcnname, param.show_header, inputs);

    if (~worked)
      if (strcmp(out, 'Language ''octave'' is not supported.'))
        error('function_handle: your SymPy has no octave codegen');
      else
        out
        error('function_handle: Some other error from SymPy code gen?  file a bug!');
      end
    end
    M.name = out{1}{1};
    M.code = out{1}{2};

    assert (strcmp (M.name, [fcnname '.m']), 'sanity check failed: names should match');

    file_to_write = fullfile(fcnpath, [fcnname '.m']);
    [fid,msg] = fopen(file_to_write, 'w');
    assert(fid > -1, msg)
    fprintf(fid, '%s', M.code);
    fclose(fid);
    fprintf('Wrote file %s.\n', file_to_write);

    % FIXME: Check upstream to rehash the files correctly once created
    % Due to an upstream bug in octave on windows, we have to wait for the file to be loaded.
    % See https://savannah.gnu.org/bugs/?31080 for more information...\n
    if (exist('OCTAVE_VERSION', 'builtin') && ispc())
      fprintf('Workaround savannah.gnu.org/bugs/?31080: waiting for %s... ', fcnname);
      fflush(stdout);
      while (exist(fcnname) == 0)
        rehash()
        pause(1)
      end
      fprintf('Found!\n');
    end

    f = str2func(fcnname);

  else % output function handle

    exprstrs = {};
    for i=1:Nout
      expr = varargin{i};
      cmd = { '(f,) = _ins' ...
              'try:' ...
              '    a, b, s = octave_code(f, human=False)' ...
              'except NameError as e:' ...
              '    return (False, str(e))' ...
              'if len(b) != 0:' ...
              '    return (False, s)' ...
              'if len(a) != 0:' ...
              '    return (False, "expected symbols-to-declare to be empty")' ...
              'return (True, s)' };
      [worked, codestr] = pycall_sympy__ (cmd, expr);
      if (~worked)
        error('function_handle: python codegen failed: %s', codestr)
      end
      exprstr{i} = codestr;
    end

    if (Nout == 1)
      f = eval(sprintf('@(%s) %s', inputstr, exprstr{1}));
    else
      str = [ sprintf('@(%s) deal(', inputstr) ...
              sprintf('%s,', exprstr{:})];
      str = [str(1:end-1) ')'];
      f = eval(str);
    end
  end

  % Note: this fails in Matlab SMT too:
  %h = function_handle({x,y,z},'vars',{x y z})
  % (could fix by moving it outside @sym)
end

%!shared x,y,z
%! syms x y z

%!test
%! % basic test
%! h = function_handle(2*x);
%! assert(isa(h, 'function_handle'))
%! assert(h(3)==6)

%!test
%! % autodetect inputs
%! h = function_handle(2*x*y, x+y);
%! [t1, t2] = h(3,5);
%! assert(t1 == 30 && t2 == 8)

%!test
%! % specified inputs
%! h = function_handle(2*x*y, 'vars', [x y]);
%! assert(h(3,5)==30)
%! h = function_handle(2*x*y, x+y, 'vars', [x y]);
%! [t1, t2] = h(3,5);
%! assert(t1 == 30 && t2 == 8)

%!test
%! % cell arrays for vars list
%! h = function_handle(2*x*y, x+y, 'vars', {x y});
%! [t1, t2] = h(3,5);
%! assert(t1 == 30 && t2 == 8)
%! h = function_handle(2*x*y, x+y, 'vars', {'x' 'y'});
%! [t1, t2] = h(3,5);
%! assert(t1 == 30 && t2 == 8)

%!test
%! % cell arrays specfies order, overriding symvar order
%! h = function_handle(x*y, 12/y, 'vars', {y x});
%! [t1, t2] = h(3, 6);
%! assert(t1 == 18 && t2 == 4)
%! h = function_handle(x*y, 12/y, 'vars', [y x]);
%! [t1, t2] = h(3, 6);
%! assert(t1 == 18 && t2 == 4)

%!test
%! % cell arrays specfies order, overriding symvar order
%! h = function_handle(x*y, 12/y, 'vars', {y x});
%! [t1, t2] = h(3, 6);
%! assert(t1 == 18 && t2 == 4)
%! h = function_handle(x*y, 12/y, 'vars', [y x]);
%! [t1, t2] = h(3, 6);
%! assert(t1 == 18 && t2 == 4)

%!test
%! % Functions with different names in Sympy.
%! f = abs(x);  % becomes Abs(x)
%! h = function_handle(f);
%! assert(h(-10) == 10)
%! f = ceil(x);
%! h = function_handle(f);
%! assert(h(10.1) == 11)

%!test
%! % 'file' with empty filename returns handle
%! h = function_handle(2*x*y, 'file', '');
%! assert(isa(h, 'function_handle'))
%! assert(h(3,5)==30)
%! h = function_handle(2*x*y, 'vars', {x y}, 'file', '');
%! assert(isa(h, 'function_handle'))
%! assert(h(3,5)==30)

%!test
%! % output to disk
%! fprintf('\n')
%! if (exist ('OCTAVE_VERSION', 'builtin'))
%!   temp_file = tempname('', 'oct_');
%! else
%!   temp_file = tempname();
%! end
%! % allow loading function from temp_file
%! [temp_path, ans, ans] = fileparts(temp_file);
%! addpath(temp_path);
%! f = function_handle(2*x*y, 2^x, 'vars', {x y z}, 'file', temp_file);
%! assert( isa(f, 'function_handle'))
%! addpath(temp_path);  % Matlab 2014a needs this?
%! [a,b] = f(10,20,30);
%! assert (isnumeric (a) && isnumeric (b))
%! assert (a == 400)
%! assert (b == 1024)
%! if (exist ('OCTAVE_VERSION', 'builtin'))
%!   assert (unlink([temp_file '.m']) == 0)
%! else
%!   delete ([temp_file '.m'])
%! end
%! % remove temp_path from load path
%! rmpath(temp_path);

%!test
%! % output to disk: also works with .m specified
%! if (exist ('OCTAVE_VERSION', 'builtin'))
%!   temp_file = [tempname('', 'oct_') '.m'];
%! else
%!   temp_file = [tempname() '.m'];
%! end
%! % allow loading function from temp_file
%! [temp_path, ans, ans] = fileparts(temp_file);
%! addpath(temp_path);
%! f = function_handle(2*x*y, 2^x, 'vars', {x y z}, 'file', temp_file);
%! assert( isa(f, 'function_handle'))
%! addpath(temp_path);  % Matlab 2014a needs this?
%! [a,b] = f(10,20,30);
%! assert (isnumeric (a) && isnumeric (b))
%! assert (a == 400)
%! assert (b == 1024)
%! if (exist ('OCTAVE_VERSION', 'builtin'))
%!   assert (unlink(temp_file) == 0)
%! else
%!   delete (temp_file)
%! end
%! % remove temp_path from load path
%! rmpath(temp_path);

%!test
%! % non-scalar outputs
%! H = [x y z];
%! M = [x y; z 16];
%! V = [x;y;z];
%! h = function_handle(H, M, V);
%! [t1,t2,t3] = h(1,2,3);
%! assert(isequal(t1, [1 2 3]))
%! assert(isequal(t2, [1 2; 3 16]))
%! assert(isequal(t3, [1;2;3]))

%!test
%! % non-scalar outputs in .m files
%! H = [x y z];
%! M = [x y; z 16];
%! V = [x;y;z];
%! if (exist ('OCTAVE_VERSION', 'builtin'))
%!   temp_file = tempname('', 'oct_');
%! else
%!   temp_file = tempname();
%! end
%! % allow loading function from temp_file
%! [temp_path, ans, ans] = fileparts(temp_file);
%! addpath(temp_path);
%! h = function_handle(H, M, V, 'vars', {x y z}, 'file', temp_file);
%! assert( isa(h, 'function_handle'))
%! addpath(temp_path);  % Matlab 2014a needs this?
%! [t1,t2,t3] = h(1,2,3);
%! assert(isequal(t1, [1 2 3]))
%! assert(isequal(t2, [1 2; 3 16]))
%! assert(isequal(t3, [1;2;3]))
%! if (exist ('OCTAVE_VERSION', 'builtin'))
%!   assert (unlink([temp_file '.m']) == 0)
%! else
%!   delete ([temp_file '.m'])
%! end
%! % remove temp_path from load path
%! rmpath(temp_path);

%!test
%! % order of outputs is lexiographic
%! syms a A x y
%! f = y + 10*a + 100*x + 1000*A;
%! h = function_handle(f);
%! assert (h(1, 2, 3, 4) == 1000 + 20 + 300 + 4)

%!test
%! % https://github.com/cbm755/octsympy/issues/854
%! f = function_handle (x + 1i*sqrt (sym(3)));
%! assert (f (1), complex (1, sqrt (3)), -eps)


% pop_loadascinstep() - import an INStep ASC (ASCII) file
%
% Usage:
%   >> OUTEEG = pop_loadascinstep( filename );
%
% Inputs:
%   filename       - file name
%
% Outputs:
%   OUTEEG         - EEGLAB data structure
%
% Author: Arnaud Delorme, SCCN, INC, UCSD, July 2006

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

function [EEG, com] = pop_loadascinstep( filename );

if nargin < 1
    [filename, filepath] = uigetfile('*.*', 'Choose an INStep ASC file -- pop_loadascinstep');
    drawnow;
    if filename == 0 return; end;
    filename = fullfile(filepath, filename);
end;

EEG = eeg_emptyset;
fid = fopen(filename, 'r');
if fid == -1, error('Cannot open file'); end;
num1 = fscanf(fid, '%f', 1);tmp   = fgetl(fid);
num2 = fscanf(fid, '%f', 1);tmp   = fgetl(fid);
num3 = fscanf(fid, '%f', 1);tmp   = fgetl(fid);

if ~isempty(num3)
    EEG.nbchan = num1;
    EEG.pnts   = num2;
    EEG.srate  = 1000/num3;
    tline = fgetl(fid);
    tline = fgetl(fid);
else
    EEG.nbchan = num1;
    EEG.srate  = 1000/num2;
    tline = tmp;
end;

allf  = parsetxt(tline);

EEG.data = fscanf(fid, '%f', [EEG.nbchan+5 Inf]);
fclose(fid);

EEG.xmin = EEG.data(3,1)/1000;
EEG.data(4,:) = EEG.data(4,:).*EEG.data(2,:); % stimulus times category
EEG.data([1:3],:) = []; % trial column
EEG.chanlocs = struct('labels', allf(4:end));
EEG = eeg_checkset(EEG);

EEG = pop_chanevent(EEG, 1, 'edge', 'leading', 'delchan', 'on');
EEG = pop_chanevent(EEG, 1, 'edge', 'leading', 'delchan', 'on', 'delevent', 'off', 'nbtype', 1, 'typename', 'resp' );
EEG = eeg_checkset(EEG, 'eventconsistency');

com = sprintf('EEG = pop_loadascinstep(''%s'');',filename);


%Vehicle Car-like vehicle class
%
% This class models the kinematics of a car-like vehicle (bicycle model) on
% a plane that moves in SE(2).  For given steering and velocity inputs it
% updates the true vehicle state and returns noise-corrupted odometry
% readings.
%
% Methods::
%   init         initialize vehicle state
%   f            predict next state based on odometry
%   step         move one time step and return noisy odometry
%   control      generate the control inputs for the vehicle
%   update       update the vehicle state
%   run          run for multiple time steps
%   Fx           Jacobian of f wrt x
%   Fv           Jacobian of f wrt odometry noise
%   gstep        like step() but displays vehicle
%   plot         plot/animate vehicle on current figure
%   plot_xy      plot the true path of the vehicle
%   add_driver   attach a driver object to this vehicle
%   display      display state/parameters in human readable form
%   char         convert to string
%
% Class methods::
%   plotv        plot/animate a pose on current figure
%
% Properties (read/write)::
%   x               true vehicle state: x, y, theta (3x1)
%   V               odometry covariance (2x2)
%   odometry        distance moved in the last interval (2x1)
%   rdim             dimension of the robot (for drawing)
%   L               length of the vehicle (wheelbase)
%   alphalim        steering wheel limit
%   maxspeed        maximum vehicle speed
%   T               sample interval
%   verbose         verbosity
%   x_hist          history of true vehicle state (Nx3)
%   driver          reference to the driver object
%   x0              initial state, restored on init()
%
% Examples::
%
% Create a vehicle with odometry covariance
%       v = Vehicle( diag([0.1 0.01].^2 );
% and display its initial state
%       v
% now apply a speed (0.2m/s) and steer angle (0.1rad) for 1 time step
%       odo = v.update([0.2, 0.1])
% where odo is the noisy odometry estimate, and the new true vehicle state
%       v
%
% We can add a driver object
%      v.add_driver( RandomPath(10) )
% which will move the vehicle within the region -10<x<10, -10<y<10 which we
% can see by
%      v.run(1000)
% which shows an animation of the vehicle moving for 1000 time steps
% between randomly selected wayoints.
%
% Notes::
% - Subclasses the MATLAB handle class which means that pass by reference semantics
%   apply.
%
% Reference::
%
%   Robotics, Vision & Control, Chap 6
%   Peter Corke,
%   Springer 2011
%
% See also RandomPath, EKF.

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

classdef Vehicle < handle

    properties
        % state
        x           % true state (x,y,theta)
        x_hist      % x history

        % parameters
        L           % length of vehicle
        alphalim    % steering wheel limit
        maxspeed    % maximum speed
        dim         % dimension of the world -dim -> +dim in x and y
        rdim    % dimension of the robot
        dt           % sample interval
        V           % odometry covariance

        odometry    % distance moved in last interval

        verbose

        driver      % driver object
        x0          % initial state
    end

    methods

        function veh = Vehicle(V, varargin)
        %Vehicle Vehicle object constructor
        %
        % V = Vehicle(V_ACT, OPTIONS)  creates a Vehicle object with actual odometry
        % covariance V_ACT (2x2) matrix corresponding to the odometry vector [dx dtheta].
        %
        % Options::
        % 'stlim',A       Steering angle limited to -A to +A (default 0.5 rad)
        % 'vmax',S        Maximum speed (default 5m/s)
        % 'L',L           Wheel base (default 1m)
        % 'x0',x0         Initial state (default (0,0,0) )
        % 'dt',T          Time interval
        % 'rdim',R        Robot size as fraction of plot window (default 0.2)
        % 'verbose'       Be verbose
        %
        % Notes::
        % - Subclasses the MATLAB handle class which means that pass by reference semantics
        %   apply.

            if ~isnumeric(V)
                error('first arg is V');
            end
            veh.x = zeros(3,1);
            if nargin < 1
                V = zeros(2,2);
            end

            opt.stlim = 0.5;
            opt.vmax = 5;
            opt.L = 1;
            opt.rdim = 0.2;
            opt.dt = 0.1;
            opt.x0 = zeros(3,1);
            opt = tb_optparse(opt, varargin);

            veh.V = V;

            veh.dt = opt.dt;
            veh.alphalim = opt.stlim;
            veh.maxspeed = opt.vmax;
            veh.L = opt.L;
            veh.x0 = opt.x0(:);
            veh.rdim = opt.rdim;
            veh.verbose = opt.verbose;

            veh.x_hist = [];
        end

        function init(veh, x0)
            %Vehicle.init Reset state of vehicle object
            %
            % V.init() sets the state V.x := V.x0, initializes the driver
            % object (if attached) and clears the history.
            %
            % V.init(X0) as above but the state is initialized to X0.
            if nargin > 1
                veh.x = x0(:);
            else
                veh.x = veh.x0;
            end
            veh.x_hist = [];
            if ~isempty(veh.driver)
                veh.driver.init()
            end
        end

        function add_driver(veh, driver)
            %Vehicle.add_driver Add a driver for the vehicle
            %
            % V.add_driver(D) connects a driver object D to the vehicle.  The driver
            % object has one public method:
            %        [speed, steer] = D.demand();
            % that returns a speed and steer angle.
            %
            % Notes::
            % - The Vehicle.step() method invokes the driver if one is attached.
            %
            % See also Vehicle.step, RandomPath.
            veh.driver = driver;
            driver.veh = veh;
        end

        function xnext = f(veh, x, odo, w)
            %Vehicle.f Predict next state based on odometry
            %
            % XN = V.f(X, ODO) is the predicted next state XN (1x3) based on current
            % state X (1x3) and odometry ODO (1x2) = [distance, heading_change].
            %
            % XN = V.f(X, ODO, W) as above but with odometry noise W.
            %
            % Notes::
            % - Supports vectorized operation where X and XN (Nx3).
            if nargin < 4
                w = [0 0];
            end

            dd = odo(1) + w(1); dth = odo(2);

            % straightforward code:
            % thp = x(3) + dth;
            % xnext = zeros(1,3);
            % xnext(1) = x(1) + (dd + w(1))*cos(thp);
            % xnext(2) = x(2) + (dd + w(1))*sin(thp);
            % xnext(3) = x(3) + dth + w(2);
            %
            % vectorized code:

            thp = x(:,3) + dth;
            xnext = x + [(dd+w(1))*cos(thp)  (dd+w(1))*sin(thp) ones(size(x,1),1)*dth+w(2)];
        end

        function odo = update(veh, u)
            %Vehicle.update Update the vehicle state
            %
            % ODO = V.update(U) is the true odometry value for
            % motion with U=[speed,steer].
            %
            % Notes::
            % - Appends new state to state history property x_hist.
            % - Odometry is also saved as property odometry.

            xp = veh.x; % previous state
            veh.x(1) = veh.x(1) + u(1)*veh.dt*cos(veh.x(3));
            veh.x(2) = veh.x(2) + u(1)*veh.dt*sin(veh.x(3));
            veh.x(3) = veh.x(3) + u(1)*veh.dt/veh.L * u(2);
            odo = [colnorm(veh.x(1:2)-xp(1:2)) veh.x(3)-xp(3)];
            veh.odometry = odo;

            veh.x_hist = [veh.x_hist; veh.x'];   % maintain history
        end

        function J = Fx(veh, x, odo)
        %Vehicle.Fx  Jacobian df/dx
        %
        % J = V.Fx(X, ODO) is the Jacobian df/dx (3x3) at the state X, for
        % odometry input ODO (1x2) = [distance, heading_change].
        %
        % See also Vehicle.f, Vehicle.Fv.
            dd = odo(1); dth = odo(2);
            thp = x(3) + dth;

            J = [
                1   0   -dd*sin(thp)
                0   1   dd*cos(thp)
                0   0   1
                ];
        end

        function J = Fv(veh, x, odo)
            %Vehicle.Fv  Jacobian df/dv
            %
            % J = V.Fv(X, ODO) is the Jacobian df/dv (3x2) at the state X, for
            % odometry input ODO (1x2) = [distance, heading_change].
            %
            % See also Vehicle.F, Vehicle.Fx.
            dd = odo(1); dth = odo(2);
            thp = x(3) + dth;

            J = [
                cos(thp)    -dd*sin(thp)
                sin(thp)    dd*cos(thp)
                0           1
                ];
        end

        function odo = step(veh, varargin)
            %Vehicle.step Advance one timestep
            %
            % ODO = V.step(SPEED, STEER) updates the vehicle state for one timestep
            % of motion at specified SPEED and STEER angle, and returns noisy odometry.
            %
            % ODO = V.step() updates the vehicle state for one timestep of motion and
            % returns noisy odometry.  If a "driver" is attached then its DEMAND() method
            % is invoked to compute speed and steer angle.  If no driver is attached
            % then speed and steer angle are assumed to be zero.
            %
            % Notes::
            % - Noise covariance is the property V.
            %
            % See also Vehicle.control, Vehicle.update, Vehicle.add_driver.

            % get the control input to the vehicle from either passed demand or driver
            u = veh.control(varargin{:});

            % compute the true odometry and update the state
            odo = veh.update(u);

            % add noise to the odometry
            if veh.V
                odo = veh.odometry + randn(1,2)*veh.V;
            end
        end

        function u = control(veh, speed, steer)
            %Vehicle.control Compute the control input to vehicle
            %
            % U = V.control(SPEED, STEER) is a control input (1x2) = [speed,steer]
            % based on provided controls SPEED,STEER to which speed and steering angle
            % limits have been applied.
            %
            % U = V.control() as above but demand originates with a "driver" object if
            % one is attached, the driver's DEMAND() method is invoked. If no driver is
            % attached then speed and steer angle are assumed to be zero.
            %
            % See also Vehicle.step, RandomPath.
            if nargin < 2
                % if no explicit demand, and a driver is attached, use
                % it to provide demand
                if ~isempty(veh.driver)
                    [speed, steer] = veh.driver.demand();
                else
                    % no demand, do something safe
                    speed = 0;
                    steer = 0;
                end
            end

            % clip the speed
            u(1) = min(veh.maxspeed, max(-veh.maxspeed, speed));

            % clip the steering angle
            u(2) = max(-veh.alphalim, min(veh.alphalim, steer));
        end

        function p = run(veh, nsteps)
            %Vehicle.run Run the vehicle simulation
            %
            % V.run(N) runs the vehicle model for N timesteps and plots
            % the vehicle pose at each step.
            %
            % P = V.run(N) runs the vehicle simulation for N timesteps and
            % return the state history (Nx3) without plotting.  Each row
            % is (x,y,theta).
            %
            % See also Vehicle.step.

            if nargin < 2
                nsteps = 1000;
            end

            %veh.clear();
            if ~isempty(veh.driver)
                veh.driver.visualize();
            end

            veh.visualize();
            for i=1:nsteps
                veh.step();
                if nargout == 0
                    % if no output arguments then plot each step
                    veh.plot();
                    drawnow
                end
            end
            p = veh.x_hist;
        end

        % TODO run and run2 should become superclass methods...

        function p = run2(veh, T, x0, speed, steer)
            %Vehicle.run2 Run the vehicle simulation with control inputs
            %
            % P = V.run2(T, X0, SPEED, STEER) runs the vehicle model for a time T with
            % speed SPEED and steering angle STEER.  P (Nx3) is the path followed and
            % each row is (x,y,theta).
            %
            % Notes::
            % - Faster and more specific version of run() method.
            % - Used by the RRT planner.
            %
            % See also Vehicle.run, Vehicle.step, RRT.
            veh.init(x0);

            for i=1:(T/veh.dt)
                veh.update([speed steer]);
            end
            p = veh.x_hist;
        end

        function h = plot(veh, varargin)
        %Vehicle.plot Plot vehicle
        %
        % V.plot(OPTIONS) plots the vehicle on the current axes at a pose given by
        % the current state.  If the vehicle has been previously plotted its
        % pose is updated.  The vehicle is depicted as a narrow triangle that
        % travels "point first" and has a length V.rdim.
        %
        % V.plot(X, OPTIONS) plots the vehicle on the current axes at the pose X.
        %
        % H = V.plotv(X, OPTIONS) draws a representation of a ground robot as an
        % oriented triangle with pose X (1x3) [x,y,theta].  H is a graphics handle.
        %
        % V.plotv(H, X) as above but updates the pose of the graphic represented
        % by the handle H to pose X.
        %
        % Options::
        % 'scale',S    Draw vehicle with length S x maximum axis dimension
        % 'size',S     Draw vehicle with length S
        % 'color',C    Color of vehicle.
        % 'fill'       Filled
        %
        % See also Vehicle.plotv.

            h = findobj(gcf, 'Tag', 'Vehicle.plot');
            if isempty(h)
                % no instance of vehicle graphical object found
                h = Vehicle.plotv(veh.x, varargin{:});
                set(h, 'Tag', 'Vehicle.plot');  % tag it
            end

            if ~isempty(varargin) && isnumeric(varargin{1})
                % V.plot(X)
                Vehicle.plotv(h, varargin{1}); % use passed value
            else
                % V.plot()
                Vehicle.plotv(h, veh.x);    % use current state
            end
        end

        function out = plot_xy(veh, varargin)
            %Vehicle.plot_xy Plots true path followed by vehicle
            %
            % V.plot_xy() plots the true xy-plane path followed by the vehicle.
            %
            % V.plot_xy(LS) as above but the line style arguments LS are passed
            % to plot.
            %
            % Notes::
            % - The path is extracted from the x_hist property.

            xyt = veh.x_hist;
            if nargout == 0
                plot(xyt(:,1), xyt(:,2), varargin{:});
            else
                out = xyt;
            end
        end

        function visualize(veh)
            grid on
        end

        function verbosity(veh, v)
        %Vehicle.verbosity Set verbosity
        %
        % V.verbosity(A) set verbosity to A.  A=0 means silent.
            veh.verbose = v;
        end

        function display(nav)
        %Vehicle.display Display vehicle parameters and state
        %
        % V.display() displays vehicle parameters and state in compact
        % human readable form.
        %
        % Notes::
        % - This method is invoked implicitly at the command line when the result
        %   of an expression is a Vehicle object and the command has no trailing
        %   semicolon.
        %
        % See also Vehicle.char.

            loose = strcmp( get(0, 'FormatSpacing'), 'loose');
            if loose
                disp(' ');
            end
            disp([inputname(1), ' = '])
            disp( char(nav) );
        end % display()

        function s = char(veh)
        %Vehicle.char Convert to a string
        %
        % s = V.char() is a string showing vehicle parameters and state in
        % a compact human readable format.
        %
        % See also Vehicle.display.

            s = 'Vehicle object';
            s = char(s, sprintf(...
            '  L=%g, maxspeed=%g, alphalim=%g, T=%f, nhist=%d', ...
                veh.L, veh.maxspeed, veh.alphalim, veh.dt, ...
                numrows(veh.x_hist)));
            if ~isempty(veh.V)
                s = char(s, sprintf(...
                '  V=(%g,%g)', ...
                    veh.V(1,1), veh.V(2,2)));
            end
            s = char(s, sprintf('  x=%g, y=%g, theta=%g', veh.x));
            if ~isempty(veh.driver)
                s = char(s, '  driven by::');
                s = char(s, [['    '; '    '] char(veh.driver)]);
            end
        end

    end % method

    methods(Static)

        function h_ = plotv(x, varargin)
        %Vehicle.plotv Plot ground vehicle pose
        %
        % H = Vehicle.plotv(X, OPTIONS) draws a representation of a ground robot as an
        % oriented triangle with pose X (1x3) [x,y,theta].  H is a graphics handle.
        % If X (Nx3) is a matrix it is considered to represent a trajectory in which case
        % the vehicle graphic is animated.
        %
        % Vehicle.plotv(H, X) as above but updates the pose of the graphic represented
        % by the handle H to pose X.
        %
        % Options::
        % 'scale',S    Draw vehicle with length S x maximum axis dimension
        % 'size',S     Draw vehicle with length S
        % 'color',C    Color of vehicle.
        % 'fill'       Filled with solid color as per 'color' option
        % 'fps',F      Frames per second in animation mode (default 10)
        %
        % Example::
        %
        % Generate some path 3xN
        %         p = PRM.plan(start, goal);
        % Set the axis dimensions to stop them rescaling for every point on the path
        %         axis([-5 5 -5 5]);
        %
        % Now invoke the static method
        %         Vehicle.plotv(p);
        %
        % Notes::
        % - This is a class method.
        %
        % See also Vehicle.plot.

            if isscalar(x) && ishandle(x)
                % plotv(h, x)
                h = x;
                x = varargin{1};
                x = x(:)';
                T = transl([x(1:2) 0]) * trotz( x(3) );
                set(h, 'Matrix', T);
                return
            end

            opt.scale = 1/60;
            opt.size = [];
            opt.fill = false;
            opt.color = 'r';
            opt.fps = 10;

            [opt,args] = tb_optparse(opt, varargin);

            lineprops = { 'Color', opt.color' };
            if opt.fill
                lineprops = [lineprops 'fill' opt.color ];
            end

            % compute the dimensions of the robot
            if ~isempty(opt.size)
                d = opt.size;
            else
                % get the current axes dimensions
                a = axis;
                d = (a(2)+a(4) - a(1)-a(3)) * opt.scale;
            end

            % draw it
            points = [
                d 0
                -d -0.6*d
                -d 0.6*d
            ]';

            h = hgtransform();
            hp = plot_poly(points, lineprops{:});
            for hh=hp
                set(hh, 'Parent', h);
            end

            if (numel(x) > 3) && (numcols(x) == 3)
                % animation mode
                for i=1:numrows(x)
                    T = transl([x(i,1:2) 0]) * trotz( x(i,3) );
                    set(h, 'Matrix', T);
                    pause(1/opt.fps);
                end
            elseif (numel(x) == 3)
                % compute the pose
                % convert vector form of pose to SE(3)

                x = x(:)';
                T = transl([x(1:2) 0]) * trotz( x(3) );
                set(h, 'Matrix', T);
            else
                error('bad pose');
            end

            if nargout > 0
                h_ = h;
            end
        end

    end % static methods

end % classdef


function [D, Isubj]=pons_cut_dir_adf(dirname,th_pval)
%         For all the subjects in the directory "dirname":
%           Computes the Dice coefficients D=2Nab/Na+Nb
%                           where:
%   Na is the volume of the Cerebellum obtrained trough the volume-based labeling
%     Nb is the volume "filled" obtained from the surface-based stream
%              Nab is the volume of the overlap
%

%
% pons_cut_dir_afd.m
%
% Original Author: Laurence Wastiaux
% CVS Revision Info:
%    $Author: nicks $
%    $Date: 2011/03/02 00:04:12 $
%    $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
%

if (nargin<1 | nargin>2)
    msg=sprintf('USAGE: [D]=cc_cut_dir_adf(dirname, th_pval)');
    disp(msg)
end

%%% Get the table's directory %%%
if(getenv('FREESURFER_HOME'))
    fsh=getenv('FREESURFER_HOME');
    fsafdDir=strcat(fsh, '/fsafd');
else
    error(sprintf('Impossible to find FREESURFER_HOME\n'));
end

%%% Load stats from the Buckner data set %%%
%stat_file='/space/okapi/3/data/laurence/ADF/cutting_planes/PonsCutDice.adf';
stat_file=strcat(fsafdDir, '/PonsCutDice.adf');
fid=fopen(stat_file);
if(fid==-1)
    mess=sprintf('Could not find %s', stat_file);
    error(mess)
end
while(strfind(fgetl(fid), '#'))
    pos=ftell(fid);
end
fseek(fid, pos, 'bof');
DDpons=fscanf(fid, '%g');

files=dir(dirname);

D=[];
Isubj=[];
for i=1:length(files)
    SubjectDir=strcat(dirname,'/',files(i).name);
    %disp(SubjectDir)
    CorDir1=strcat(SubjectDir,'/mri/aseg/');
    CorDir2=strcat(SubjectDir,'/mri/filled/');
    d1=dir(CorDir1);
    d2=dir(CorDir2);
    if (length(d1)<3 | length(d2)<3 |(strcmp(files(i).name, '010128_2105')==1) |(strcmp(files(i).name, '010621_vc7110')==1) | ( length(strfind(files(i).name,'0'))==0 &&(length(strfind(files(i).name,'1'))==0 )))
    %if (length(d1)<3 | length(d2)<3 )
        i=i+1; % go to the next subject in the directory
    else
        %%% load the volumes aseg and wm %%%
    [vol1 M1 t1]=load_cor2(SubjectDir,'aseg');
    [vol2 M2 t2]=load_cor2(SubjectDir,'filled');

    if ((t1~=1) | (t2~=1))
        i=i+1;
    else
        %%% Compute the Dice coefficient %%%
        d=compute_dice(vol1,vol2);
        D=[D d];
        Isubj=[Isubj i];
        pval=compute_pval(d, DDpons);
        if (pval<th_pval)
            mess=sprintf('Cerebellum & Brain-stem not succesfully removed for subject: %s (dice=%.3g, pval=%.3g)', files(i).name, d, pval);
            disp(mess)
        else
            mess=sprintf('Cerebellum & Brain-stem succesfully removed for subject: %s (dice=%.3g, pval=%.3g)', files(i).name, d, pval);
            disp(mess)
        end
    end
    end
    vol1=[];
    vol2=[];
end

%%% sub-function [n]=compute_dice(vol1,vol2) %%%

function [n]=compute_dice(vol1,vol2)

Na=0;
Nb=0;
Nab=0;
sz=size(vol1);
sw=size(vol2);
if (sz==sw)
    for i=1:sz(1)
        for j=1:sz(2)
            for k=1:sz(3)
                if (vol1(i,j,k)==7 | vol1(i,j,k)==46 | vol1(i,j,k)==16)
                    Na=Na+1;
                end
                if (vol2(i,j,k)~=0)
                    Nb=Nb+1;
                end
                if ((vol1(i,j,k)==7 | vol1(i,j,k)==46 | vol1(i,j,k)==16) && (vol2(i,j,k)~=0))
                    Nab=Nab+1;
                end
            end
        end
    end
    n=2*Nab/(Na+Nb);
else
    mess=sprintf('The wm and aseg volumes do not have the same size');
    n=0;
    disp(mess)
end

% subfunction compute_pval() %
function [p_sup]=compute_pval(val, Dpons)
%load('/space/okapi/3/data/laurence/ADF/cutting_planes/Dice_pons.mat'); %loads Dpons
pas=0.05;
x=0:pas:1;
[h] = hist(Dpons,x);
p = h/sum(h);
dsup=find(x>val);
xsup=x(dsup);
psup=p(length(x)-length(xsup)+1:end);
if (val>=0 & length(xsup) >1)
    p_sup=trapz(xsup,psup)/pas;
elseif (val>=0 & (length(xsup)<2))
    pas2=pas/10;
    x2=0:pas2:1;
    [h2] = hist(Dpons,x2);
    p2 = h2/sum(h2);
    dsup2=find(x2>val);
    xsup2=x2(dsup2);
    psup2=p2(length(x2)-length(xsup2)+1:end);
    if(length(xsup2)>1)
        p_sup=trapz(xsup2,psup2)/pas2;
    else
        p_sup=0;
    end
else
    p_sup=0;
end


%% FUNCTION Construct_iMSF
%   Prepares input for iMSF optimization. This function is not intended to
%   directly called by users. See the Logistic_iMSF function.
%
%% LICENSE
%   This program is free software: you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation, either version 3 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You should have received a copy of the GNU General Public License
%   along with this program.  If not, see <http://www.gnu.org/licenses/>.
%
%   Copyright (C) 2011 - 2012 Lei Yuan, Jiayu Zhou, and Jieping Ye
%
%   You are suggested to first read the Manual.
%   For any problem, please contact with Jiayu Zhou via jiayu.zhou@asu.edu
%
%   Last modified on June 12, 2012.
%
%% RELATED FUNCTIONS
%   init_opts, Construct_iMSF, Logistic_iMSF, MultiSource_LogisticR

function [A_Set, Y_Set, W, G, ind, PS, A_Set_Complete] = Construct_iMSF(X_Set, Y)
%

X = [];
temp = [];
IndMissing = [];
nF = [];
FeatureTypes = cell(length(X_Set), 1);

for i = 1:length(X_Set)
    temp = X_Set{i};
    FeatureTypes{i} = sprintf('%d', i);

    temp(~isnan(temp(:, 1)), :) = zscore(temp(~isnan(temp(:, 1)), :));

    IndMissing = [IndMissing ~isnan(temp(:, 1))];
    X = [X temp];
    nF = [nF size(temp, 2)];
end

IndAllZero = sum(IndMissing, 2) == 0;
IndMissing = IndMissing(~IndAllZero, :);
numIndMissing = bin2dec(num2str(IndMissing));
% IndMissing denotes what type of feature is missing for each particular
% sample.

X = X(~IndAllZero, :);
Y = Y(~IndAllZero, :);

PS = nchoose(FeatureTypes);
% PS is the collection of all combinations.
ind_valid = true(length(PS), 1);

% The starting index of each feature type.
nF_Start = [0 cumsum(nF)];
nF_Start = nF_Start(1:end - 1) + 1;

% We shall first remove the combinations that have too few samples.
for i = 1:length(PS)
    curTypes = PS{i};
    temp = zeros(1, length(FeatureTypes));

    for j = 1:length(curTypes)
        type = curTypes{j};
        temp(strcmp(type, FeatureTypes)) = 1;
    end

    temp = bin2dec(num2str(temp));

    ind_temp = numIndMissing == temp;
    Y_Cur = Y(ind_temp);

    if length(unique(Y_Cur)) < 2
        % If there is not enough training label (at least 1 pos 1 neg), we
        % remove this combination.
        ind_valid(i) = false;
    end
end

PS = PS(ind_valid);

IndMatrix = zeros(length(PS), sum(nF));

IndStart = 1;

for i = 1:length(PS)
    curTypes = PS{i};

    for j = 1:length(curTypes)
        type = curTypes{j};
        loc_type = find(strcmp(type, FeatureTypes));
        IndCur = nF_Start(loc_type):nF_Start(loc_type) + nF(loc_type) - 1;
        IndMatrix(i, IndCur) = IndStart:IndStart + nF(loc_type) - 1;
        IndStart = IndStart + nF(loc_type);
    end
end

W = [];
G = [];
IndStart = 1;

for i = 1:size(IndMatrix, 2)
    curGroup = IndMatrix(:, i)';
    curGroup(curGroup == 0) = [];
    G = [G curGroup];
    W = [W [IndStart; IndStart + length(curGroup) - 1]];
    IndStart = IndStart + length(curGroup);
end

A_Set = cell(length(PS), 1);
A_Set_Complete = cell(length(PS), 1);
Y_Set = cell(length(PS), 1);
ind = zeros(length(PS) + 1, 1);

for i = 1:length(PS)
    curTypes = PS{i};
    temp = zeros(1, length(FeatureTypes));
    ind_col = false(1, sum(nF));

    for j = 1:length(curTypes)
        type = curTypes{j};
        loc_type = find(strcmp(type, FeatureTypes));
        temp(loc_type) = 1;
        IndCur = nF_Start(loc_type):nF_Start(loc_type) + nF(loc_type) - 1;
        ind_col(IndCur) = true;
    end

    ind(i + 1) = ind(i) + nnz(ind_col);

    temp = bin2dec(num2str(temp));

    ind_temp = numIndMissing == temp;

    A_Set{i} = X(ind_temp, ind_col);
    A_Set_Complete{i} = X(ind_temp, :);
    Y_Set{i} = Y(ind_temp);
end


classdef GenericLoss < dagnn.ElementWise

  properties
    display = true;
  end

  properties (Transient)
    average = 0
    numAveraged = 0
  end

  methods
    function outputs = account(obj, inputs, outputs)
      if obj.display
        n = obj.numAveraged ;
        m = n + size(inputs{1},4) ;
        obj.average = (n * obj.average + gather(outputs{1})) / m ;
        obj.numAveraged = m ;
      end
    end

    function reset(obj)
      obj.average = 0 ;
      obj.numAveraged = 0 ;
    end

    function outputSizes = getOutputSizes(obj, inputSizes, paramSizes)
      outputSizes{1} = [1 1 1 inputSizes{1}(4)] ;
    end

    function rfs = getReceptiveFields(obj)
      % the receptive field depends on the dimension of the variables
      % which is not known until the network is run
      rfs(1,1).size = [NaN NaN] ;
      rfs(1,1).stride = [NaN NaN] ;
      rfs(1,1).offset = [NaN NaN] ;
      rfs(2,1) = rfs(1,1) ;
    end

  end
end


function ideal_vocal_tract_GUI25
% Modifiable runGUI file
clc;
clear all;
fileName = 'ideal_vocal_tract.mat';    %USER - ENTER FILENAME
fileData=load(fileName);
temp=fileData(1).temp;

f = figure('Visible','on',...
'Units','normalized',...
'Position',[0,0,1,1],...
'MenuBar','none',...
'NumberTitle','off');

Callbacks_ideal_vocal_tract_GUI25(f,temp);    %USER - ENTER PROPER CALLBACK FILE
%panelAndButtonEdit(f, temp);       % Easy access to Edit Mode

% Note comment PanelandBUttonCallbacks(f,temp) if panelAndButtonEdit is to
% be uncommented and used
end

% ideal_vocal_tract_GUI25 design
% 2 Panels
%   #1 - input parameters
%   #2 - graphics displays
% 6 Graphic Panels
%   #1 - excitation impulses in time
%   #2 - excitation line frequency spectrum
%   #3 - VT impulse response
%   #4 - VT frequency response
%   #5 - periodic vowel in time
%   #6 - periodic vowel spectrum
% 1 TitleBox
% 6 Buttons
%   #1 - popupmenu - vowel choices
%   #2 - editable button - T: pitch period
%   #3 - editable button - N: analysis frame length
%   #4 - popupmenu - log/linear spectrum plot
%   #5 - pushbutton - Run ideal vocal tract
%   #6 - pushbutton - Close GUI


% new procedure: generate motor seed/map in trialRes space
% find top 100 cells correlating to motor, screen with Rh4+Rh5(+Rh6??) masks

% corr sweep (0.5-0.7) to get top %2 cells, then kmeans, save; rank by stim-lock, save
clear all; close all; clc

%% folder setup
isSaveFig = 1;
isPlotFig = 1;

outputDir = GetOutputDataDir;
saveDir = [];
saveDir{1} = fullfile(outputDir,'motor_map_notlrRes_1_kmeans_030417');
% saveDir{2} = fullfile(outputDir,'motor_map_notlrRes_2_autoclus_030417');
if ~exist(saveDir{1}, 'dir'), mkdir(saveDir{1}), end;
% if ~exist(saveDir{2}, 'dir'), mkdir(saveDir{2}), end;

%% init

hfig = figure;
InitializeAppData(hfig);
ResetDisplayParams(hfig);

setappdata(hfig,'isMotorseed',1);
setappdata(hfig,'isTrialRes',1);

%% run fish
range_fish = GetFishRange;%[1:3,5:18];
M_thres_reg = zeros(3,18);
M_numTopCorr = zeros(1,18);
M_motorseedRegs = cell(1,18);
M_compareMotorCellNumber = zeros(2,18);

for i_fish = range_fish
    ClusterIDs = [11,2];
    [gIX_seed,gIX_seed,M,stim,behavior,M_0] = LoadSingleFishDefault(i_fish,hfig,ClusterIDs);

    MASKs = getappdata(hfig,'MASKs');
    CellXYZ_norm = getappdata(hfig,'CellXYZ_norm');
    absIX = getappdata(hfig,'absIX');

    %% regression (in tRes), thresholding by % of cells (instead of corr thres)

    %     [~,Reg_tRes] = GetTrialAvrLongTrace(hfig,Reg);
    %     [~,M_0_tRes] = GetTrialAvrLongTrace(hfig,M_0);

    Reg = FindClustermeans(gIX_seed,M);
%     Reg_LR = Reg;
    Reg_LR = Reg-repmat(mean(Reg),2,1);

    %     Corr = corr(Reg_tRes_LR',M_0_tRes');
    Corr = corr(Reg_LR',M_0');
    [Corr_sorted,IX_corr] = sort(Corr,2,'descend');

    %     [corr_max,IX] = max(Corr,[],1);
    %     [~,I] = sort(corr_max,'descend');

    M_target_prctcell= [1,2,3];
    for i_numcell = 1%:2,
        nCells_total = size(M_0,1);
        prctcell = M_target_prctcell(i_numcell);
        nCells_target = round(prctcell/100 * nCells_total);

        %% target cell number: counting cells in hindbrain only

        Msk_IDs = 114; % mask for full hindbrain

        % isScreenMskFromAllCells
        cIX = (1:length(absIX))';
        gIX = ones(size(cIX));
        [cIX_hb,gIX_hb] = ScreenCellsWithMasks(Msk_IDs,cIX,gIX,MASKs,CellXYZ_norm,absIX);

        I_hb = ismember(IX_corr,cIX_hb);
        cum_I_hb1 = cumsum(I_hb(1,:));
        cum_I_hb2 = cumsum(I_hb(2,:));
        lastIX{1} = find(cum_I_hb1==nCells_target,1,'first');
        lastIX{2} = find(cum_I_hb2==nCells_target,1,'first');

        % cut off the desired number of cells to display
        for i_lr = 1:2
            cIX = IX_corr(i_lr,1:lastIX{i_lr})';
            gIX = ceil((1:length(cIX))'/(length(cIX)/20));
            M = UpdateIndices_Manual(hfig,cIX,gIX);
            [~,M_tRes] = GetTrialAvrLongTrace(hfig,M);
            setappdata(hfig,'M',M_tRes);

            M_thres_reg(i_lr,i_fish) = Corr_sorted(i_lr,lastIX{i_lr});
            M_compareMotorCellNumber(i_lr,i_fish) = length(cIX);

            %% clustering: trying Autoclus here!
            if i_numcell==1
                %%
                numK = 16; % manual
                gIX = Kmeans_Direct(M_tRes,numK);
            else
                cIX_reg = cIX;%(1:size(M_0,1))';
                [cIX,gIX] = AutoClustering(cIX,gIX,M_0,cIX_reg);
                UpdateIndices_Manual(hfig,cIX,gIX);
            end
            %% Plot anat
            if isPlotFig,

                I = LoadCurrentFishForAnatPlot(hfig,cIX,gIX);
                f{i_lr} = DrawCellsOnAnat(I);
%                 f{i_lr} = figure('Position',[50,100,1400,800]);
%                 % isCentroid,isPlotLines,isPlotBehavior,isPlotRegWithTS
%                 subplot(121)
%                 setappdata(hfig,'isPlotBehavior',1);
%                 setappdata(hfig,'isStimAvr',0);
%                 setappdata(hfig,'isPlotLines',0);
%                 %             UpdateTimeIndex(hfig);
%                 DrawTimeSeries(hfig,cIX,gIX);
%
%                 % right plot
%                 ax = subplot(122);
%                 I = LoadCurrentFishForAnatPlot(hfig,cIX,gIX);
%                 DrawCellsOnAnat(I,ax);

            end
        end

        combineFiguresLR(f{1},f{2});

        % Save plot
        if isSaveFig,
            filename = fullfile(saveDir{i_numcell}, ['Fish',num2str(i_fish),'_motormap_',num2str(prctcell),'%_each']);
            saveas(gcf, filename, 'png');
            close(gcf)
        end

    end
end

%%
% range_fish excludes Fish 4
% M_compareMotorCellNumber(:,4) = NaN;
% figure;bar(M_compareMotorCellNumber')

github-repos/MATLAB/xiuyechen-FishExplorer/FishExplorer-c61392cf0835480d64fc03c15f1992935fdc7106/figure scripts/SensoryMotor/arc code/motormap, tRes versions, comparisons, w Clusters or Autoclus to follow/fig3_motormap_trialRes_lrRes.m


function plot_path(map, path)
% PLOT_PATH Visualize a path through an environment
%   PLOT_PATH(map, path) creates a figure showing a path through the
%   environment.  path is an N-by-3 matrix where each row corresponds to the
%   (x, y, z) coordinates of one point along the path.

% figure(1);
% path = points_to_idx(map, path);

% [x,y,z] = meshgrid(1:size(map.map3d,1),1:size(map.map3d,2),1:size(map.map3d,3));
% x = x(:); y = y(:); z = z(:);
%
% xyz = [];
% for i = 1:numel(x)
%     if map.map3d(x(i),y(i),z(i),1)~= 255 | map.map3d(x(i),y(i),z(i),2)~= 255 | map.map3d(x(i),y(i),z(i),2)~= 255
%         xyz = [xyz; x(i),y(i),z(i)];
%     end
% end
% rgb = zeros(size(xyz,1),3);
% for i = 1:size(xyz,1)
%     rgb(i,:) = map.map3d(xyz(i,1),xyz(i,2),xyz(i,3),:);
% end
% xyz = idx_to_points(map, xyz);
% if size(xyz,1) > 0
% pcshow(xyz, rgb, 'MarkerSize', 20);
% end
% hold on;
% if size(path,1) > 0
% pcshow(path, [0,0,0],'MarkerSize', 20);
% end
% hold off;

hold on;
for i = 1:size(map.blocks,1)
    block = map.blocks(i, :);

    x = [ones(4,1) * block(1); ones(4,1) * block(4)];
    y = [ones(2,1) * block(5); ones(2,1) * block(2); ones(2,1) * block(5); ones(2,1) * block(2)];
    z = [block(3);block(6);block(3);block(6);block(3);block(6);block(3);block(6)];

    vert = [x, y, z];
    fac = [1 2 6 5;2 3 7 6;3 4 8 7;4 1 5 8;1 2 3 4;5 6 7 8];
    c = block(7:9)/255;
    patch('Vertices',vert,'Faces',fac,...
          'FaceVertexCData',hsv(6),'FaceColor',c);

    x = [ones(4,1) * block(1); ones(4,1) * block(4)];
    y = [block(2);block(5);block(2);block(5);block(2);block(5);block(2);block(5)];
    z = [ones(2,1) * block(3); ones(2,1) * block(6); ones(2,1) * block(3); ones(2,1) * block(6)];

    vert = [x, y, z];
    fac = [1 2 6 5;2 3 7 6;3 4 8 7;4 1 5 8;1 2 3 4;5 6 7 8];
    c = block(7:9)/255;
    patch('Vertices',vert,'Faces',fac,...
          'FaceVertexCData',hsv(6),'FaceColor',c);
end

if size(path,1) > 0
% pcshow(path, [0,0,0],'MarkerSize', 0.1);
end
% axis([map.boundary(1)-1, map.boundary(4)-1, map.boundary(2)-1,map.boundary(5)+1,map.boundary(3)+1,map.boundary(6)+1])
hold off;
% view(3);
end


%==============================================================================
% This code is part of the VAMPIRE app for the Matlab-based toolbox
%  FAIR - Flexible Algorithms for Image Registration.
% For details see
% - https://github.com/C4IR/FAIR.m
%==============================================================================
%
% VAMPIRE - Variational Algorithm for Mass-Preserving Image REgistration
%
%
%         xxxxxxxx                                           xxxx
%      xxxxxxxxxxxxxx                                     xxxxxxxxxxx
%    xxxxxxxxxxxxxxxxx                                 xxxxxxxxxxxxxxxx
%   xxxxxxxxxxxxxxxxxxxx                             xxxxxxxxxxxxxxxxxxxx
%  xxxxxxxxxxxxxxxxxxxxxxx                          xxxxxxxxxxxxxxxxxxxxxx
%       xxxxxxxxxxxxxxxxxxx                       xxxxxxxxxxxxxxxxxxxxx
%         xxxxxxxxxxxxxxxxxxx     xxx   xxx      xxxxxxxxxxxxxxxxxxx
%         xxxxxxxxxxxxxxxxxxxx    xxxxxxxxx    xxxxxxxxxxxxxxxxxxxx
%          xxxxxxxxxxxxxxxxxxxxx  xxxxxxxxx  xxxxxxxxxxxxxxxxxxxxx
%          xxxx  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
%                   xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx       xx
%                     xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
%                      xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
%                      x       xxxxxxxxxxxxxxxx    xxx
%                               xxxxxxxxxxxxxx
%                               xxx  xxxxxxxx
%                               x          xx
%
%
% For a quick example, run: EV_3Dmouse_VAMPIRE.m
%
% Contents of VAMPIRE toolbox:
%
% VAMPIRENPIRobjFctn.m   - objective function for non-parametric registration
% VAMPIREPIRobjFctn.m    - objective function for non-parametric registration
% VAMPIREsolveGN_PCG.m   - matrix-free PCG solver for Gauss-Newton system
%
% Examples:
%
% EV_2DGaussian_VAMPIRE.m        - 2D example, non-parametric mass-preserving
% EV_2DGaussian_VAMPIRE_MLPIR.m  - 2D example, parametric mass-preserving
% EV_2DGaussianNoise_VAMPIRE.m   - 2D example, non-parametric mass-preserving
% EV_3Dmouse_VAMPIRE.m           - 3D example, non-parametric mass-preserving
% EV_3Dmouse_VAMPIRE_MLPIR.m     - 3D example, parametric mass-preserving
%
% ==================================================================================

function debit = contents
if nargout == 0, help(mfilename); return; end;

debit = {
          'VAMPIRENPIRobjFctn.m'
          'VAMPIREPIRobjFctn.m'
          'VAMPIREsolveGN_PCG.m'
          'contents.m'
          'README.md'
          'examples'
        };


function [struct_irf_record, D_record, gamma_record]=irfsignrespanel(beta_gibbs,sigma_gibbs,It,Bu,IRFperiods,n,p,m,k,signrestable,signresperiods)

% function [struct_irf_record D_record gamma_record]=irfsignrespanel(sigma_gibbs,irf_record,It,Bu,IRFperiods,n,signrestable,signresperiods,checkalgo,checkiter)
% runs the gibbs sampler to obtain draws from the posterior distribution of
% IRFs, orthogonalised with sign restrictions
% inputs:  - matrix'sigma_gibbs': record of the gibbs sampler draws for the sigma matrix (vectorised)
%          - cell 'irf_record': record of the gibbs sampler draws for the IRFs
%          - integer 'It': total number of iterations of the Gibbs sampler (defined p 28 of technical guide)
%          - integer 'Bu': number of burn-in iterations of the Gibbs sampler (defined p 28 of technical guide)
%          - integer 'IRFperiods': number of periods for IRFs
%          - integer 'n': number of endogenous variables in the BVAR model (defined p 7 of technical guide)
% outputs: - cell 'struct_irf_record': record of the gibbs sampler draws for the orthogonalised IRFs
%          - matrix 'D_record': record of the gibbs sampler draws for the structural matrix D
%          - matrix 'gamma_record': record of the gibbs sampler draws for the structural disturbances variance-covariance matrix gamma

% this function implements the sign restrictions approach for the panel

% preliminary tasks
% create first the cell that will store the results from the simulations
struct_irf_record=cell(n,n);
% storage cell
storage1=cell(It-Bu,1);
storage2=cell(It-Bu,1);

% now identify all the periods concerned with restrictions
% first expand the non-empty entries in signresperiods since they are only expressed in intervals: transform into list
% for instance, translate [1 4] into [1 2 3 4]; I don't think this can done without a loop
temp=cell2mat(signresperiods(~cellfun(@isempty,signresperiods)));
periods=[];
for ii=1:size(temp,1)
    periods=[periods temp(ii,1):temp(ii,2)];
end
% suppress duplicates and sort
periods=sort(unique(periods))';
% count the total number of restriction periods (required for IRF matrix)
nperiods=size(periods,1);

% Identify the restriction matrices
% create five cells, corresponding to the three possible restrictions:
% one cell for sign restrictions, three cells for magnitude restrictions, one cell for zero restrictions
Scell=cell(1,n);
Mcell=cell(1,n);
Mlcell=cell(1,n);
Mucell=cell(1,n);
Zcell=cell(1,n);

% loop over rows and columns of the period matrix
for ii=1:n
    for jj=1:n
        % if entry (ii,jj) of the period matrix is not empty...
        if ~isempty(signresperiods{ii,jj})
            % ... then there is a restriction over one (or several) periods
            % loop overt those periods
            for kk=signresperiods{ii,jj}(1,1):signresperiods{ii,jj}(1,2)
                % identify the position of the considered period within the list of all periods (required to build the matrix)
                position=find(periods==kk);
                % now create the restriction matrix: this will depend on the type of restriction
                % if it is a positive sign restriction...
                if strcmp(signrestable{ii,jj},'+')
                    % ... then input a 1 entry in the corresponding S matrix
                    Scell{1,jj}=[Scell{1,jj};zeros(1,n*nperiods)];
                    Scell{1,jj}(end,(position-1)*n+ii)=1;
                    % if it is a negative sign restriction...
                elseif strcmp(signrestable{ii,jj},'-')
                    % ... then input a -1 entry in the corresponding S matrix
                    Scell{1,jj}=[Scell{1,jj};zeros(1,n*nperiods)];
                    Scell{1,jj}(end,(position-1)*n+ii)=-1;
                    % if it is a zero restriction...
                elseif strcmp(signrestable{ii,jj},'0')
                    % ... then input a 1 entry in the corresponding Z matrix
                    Zcell{1,jj}=[Zcell{1,jj};zeros(1,n*nperiods)];
                    Zcell{1,jj}(end,(position-1)*n+ii)=1;
                    % else, a non-empty entry being neither a sign nor a zero restriction has to be a magnitude restriction
                else
                    % fill the corresponding M matrices:
                    % input a 1 in M
                    Mcell{1,jj}=[Mcell{1,jj};zeros(1,n*nperiods)];
                    Mcell{1,jj}(end,(position-1)*n+ii)=1;
                    % input the lower value of the interval in Ml
                    temp=str2num(signrestable{ii,jj});
                    Mlcell{1,jj}=[Mlcell{1,jj};temp(1,1)];
                    % input the upper value of the interval in Mu
                    Mucell{1,jj}=[Mucell{1,jj};temp(1,2)];
                end
            end
        end
    end
end

% now check what kind of restrictions apply among sign, zero and magnitude restrictions
% check for sign restrictions: if there are any, at least one entry in the cell Scell is non-empty
if sum(~cellfun(@isempty,Scell))~=0
    signres=1;
else
    signres=0;
end
% similarly check for zero restrictions
if sum(~cellfun(@isempty,Zcell))~=0
    zerores=1;
else
    zerores=0;
end
% and finally, check for magnitude restrictions
if sum(~cellfun(@isempty,Mcell))~=0
    magnres=1;
else
    magnres=0;
end

hbar = bear.parfor_progressbar(It-Bu,'Progress');  %create the progress bar

% step 1: repeat simulations a number of times equal to the number of simulations retained from Gibbs sampling
parfor ii=1:It-Bu
    % initiate the variable 'success'; this variable will be used to check whether the restrictions are satisfied
    % if there are only zero restrictions, they will be satisfied by construction, and 'success' will simply be ignored
    success=0;
    % how the algorithm will be conducted will depend on the types of restrictions implemented

    % if there are only zero restrictions, the algorithm is simple as no checking is required: the conditions are satisfied by construction
    if zerores==1 && signres==0 && magnres==0
        % draw beta and sigma
        beta=beta_gibbs(:,ii);
        sigma=reshape(sigma_gibbs(:,ii),n,n);
        hsigma=chol(bear.nspd(sigma),'lower');
        % obtain orthogonalised IRFs
        [irfmatrix, ortirfmatrix]=bear.irfsim(beta,hsigma,n,m,p,k,max(IRFperiods,max(periods)));
        % generate the stacked IRF matrix
        stackedirfmat=[];
        for jj=1:numel(periods)
            stackedirfmat=[stackedirfmat;ortirfmatrix(:,:,periods(jj,1)+1)];
        end
        % draw an entire random matrix Q satisfying the zero restrictions
        [Q]=bear.qzerores(n,Zcell,stackedirfmat);
        % there is no need to verify the restrictions: there are satisfied by construction

        % if there are sign/magnitude restrictions, possibly associated with zero restrictions
    else
        % the algorithm becomes a bit more complicated as conditions now need to be checked
        % to maintain efficiency, the algorithm proceeds recursively shock by shock, and stops as soon as a condition on the considered shock fails
        % repeat algorithm for the iteration as long as not all conditions are satisfied
        while success==0
            % switch 'success' to 1; it will be turned back to zero if at any time Q is detected as a candidate not satisfying the restrictions
            success=1;
            % draw randomly the vector of VAR coefficients: draw a random index
            index=floor(rand*(It-Bu))+1;
            % then draw a random set of beta and sigma corresponding to this index (this is done to make it possible to draw, if required, an infinite number of values from the gibbs sampler record, with equal probability on each value)
            beta=beta_gibbs(:,index);
            sigma=reshape(sigma_gibbs(:,index),n,n);
            hsigma=chol(bear.nspd(sigma),'lower');
            % obtain orthogonalised IRFs
            [irfmatrix, ortirfmatrix]=bear.irfsim(beta,hsigma,n,m,p,k,max(IRFperiods,max(periods)));
            % generate the stacked IRF matrix
            stackedirfmat=[];
            for jj=1:numel(periods)
                stackedirfmat=[stackedirfmat;ortirfmatrix(:,:,periods(jj,1)+1)];
            end
            % initiate Qj
            Qj=[];
            % now start looping over the shocks and checking sequentially whether conditions on these shocks hold
            % stop as soon as one restriction fails
            kk=1;
            while success==1 && kk<=n
                % build column j of the random matrix Q
                [qj]=bear.qrandj(n,Zcell{1,kk},stackedirfmat,Qj);
                % obtain the candidate column fj
                fj=stackedirfmat*qj;
                % check restrictions: first sign restrictions
                [success qj]=bear.checksignres(Scell{1,kk},qj,fj);
                % if 'success' is still equal to 1, also check for magnitude restrictions
                if success==1
                    [success]=bear.checkmagres(Mcell{1,kk},Mlcell{1,kk},Mucell{1,kk},fj);
                end
                % also, if 'success' is still equal to 1, update Qj by concatenating qj
                if success==1
                    Qj=[Qj qj];
                end
                kk=kk+1;
            end
            % repeat this loop until a succesful draw is obtained
        end
        % with succesful Qj at hand, eventually set Q as Qj
        Q=Qj;
    end

    % store
    for jj=1:IRFperiods
        storage1{ii,1}(:,:,jj)=ortirfmatrix(:,:,jj)*Q;
    end
    storage2{ii,1}=hsigma*Q;

    hbar.iterate(1);   % update progress by one iteration

end

close(hbar);   %close progress bar

% reorganise storage
% loop over iterations
for ii=1:It-Bu
    % loop over IRF periods
    for jj=1:IRFperiods
        % loop over variables
        for kk=1:n
            % loop over shocks
            for ll=1:n
                struct_irf_record{kk,ll}(ii,jj)=storage1{ii,1}(kk,ll,jj);
            end
        end
    end
    D_record(:,ii)=storage2{ii,1}(:);
    gamma_record(:,ii)=bear.vec(eye(n));
end