classdef prtRvMvn < prtRv & prtRvMemebershipModel
    % prtRvMvn  Multivariate normal random variable
    %
    %   RV = prtRvMvn creates a prtRvMvn object with empty mean and
    %   covariance matrices. The mean and covariance matrices must be set
    %   either directly, or by calling the MLE method.
    %
    %   RV = prtRvMvn('covarianceStructure', VALUE) enforces a covariance
    %   structure, which may be either 'full', 'spherical', or 'diagonal'.
    %   Setting this property to 'spherical' or 'diagonal' will enforce
    %   this structure onto the existing covariance matrix, or one
    %   estimated by calling the MLE method.
    %
    %   RV = prtRvMvn(PROPERTY1, VALUE1,...) creates a prtRvMv object RV
    %   with properties as specified by PROPERTY/VALUE pairs.
    %
    %   A prtRvMvn object inherits all properties from the prtRv class. In
    %   addition, it has the following properties:
    %
    %   covarianceStructure - A string specifying the structure of the
    %                         covariance matrix to estimate or enforce.
    %                         Valid values are 'full','spherical', or
    %                         'diagonal'
    %   mu                  - The mean of the distribution, which is
    %                         a 1 x nDimensions vector.
    %   sigma               - The covariance matrix of the distribution,
    %                         which is a nDimensions x nDimensions
    %                         matrix.
    %
    %  A prtRvMvn object inherits all methods from the prtRv class. The MLE
    %  method can be used to estimate the distribution parameters from
    %  data.
    %
    %  Example:
    %
    %  dataSet    = prtDataGenUnimodal;   % Load a dataset consisting of 2
    %                                     % classes
    %  % Extract one of the classes from the dataSet
    %  dataSetOneClass = prtDataSetClass(dataSet.getObservationsByClass(1));
    %
    %  RV = prtRvMvn;                       % Create a prtRvMvn object
    %  RV = RV.mle(dataSetOneClass.getX);   % Compute the maximum
    %                                       % likelihood estimate from the
    %                                       % data
    %  RV.plotPdf                           % Plot the pdf
    %
    %  RVspec = prtRvMvn;                   % Create another prtRvMvn
    %                                       % object
    %  RVspec.mu = [1 2];                   % Specify the mean
    %  RVspec.sigma = [2 -1; -1 2]          % Specify the covariance
    %  figure;
    %  RVspec.plotPdf                       % Plot the pdf
    %  sample = RVspec.draw(1)              % Draw 1 random sample from the
    %                                       % Distribution
    %
    %   See also: prtRv, prtRvGmm, prtRvMultinomial, prtRvUniform,
    %   prtRvUniformImproper, prtRvVq, prtRvDiscrete

    properties (SetAccess = 'private')
        name = 'Multi-Variate Normal';
        nameAbbreviation = 'RVMVN';
    end

    properties (SetAccess = 'protected')
        isSupervised = false;
        isCrossValidateValid = true;
    end

    properties (Dependent)
        covarianceStructure  % The covariance structure
        mu                   % The mean vector
        sigma                % The covariance matrix
    end
    properties (SetAccess = 'private', GetAccess = 'private', Hidden = true)
        muDepHelper
        sigmaDepHelper
        covarianceStructureDepHelper = 'full';
    end

    properties (Hidden = true)
        covarianceBias = [];
    end

    properties (Hidden = true, Dependent = true)
        nDimensions
    end

    properties (SetAccess = 'private', Hidden = true)
        trueCovariance
        badCovariance = false;
    end

    methods
        function R = prtRvMvn(varargin)
            R = constructorInputParse(R,varargin{:});
        end

        function R = mle(R,X)
           % MLE Compute the maximum likelihood estimate
            %
            % RV = RV.mle(X) computes the maximum likelihood estimate based
            % the data X. X should be nObservations x nDimensions.

            X = R.dataInputParse(X); % Basic error checking etc

            R.mu = mean(X,1);
            if size(X,1) == 1
                % A single observation
                % This is bad..
                % You can't call cov for this case
                % Since we always want to output sum( (x_i - u)'*(x_i - u))
                % We will output a matrix of zeros of the correct size.
                % Error checking for a propert covariance will happen later
                % after the bias has been applied.
                R.sigma = zeros(size(X,2));
            else
                R.sigma = cov(X);
            end

        end

        function vals = pdf(R,X)
            % PDF Output the pdf of the random variable evaluated at the points specified
            %
            % pdf = RV.pdf(X) returns  the pdf of the prtRv
            % object evaluated at X. X must be an N x nDims matrix, where
            % N is the number of locations to evaluate the pdf, and nDims
            % is the same as the number of dimensions, nDimensions, of the
            % prtRv object RV.

            [isValid, reasonStr] = R.isValid;
            assert(isValid,'PDF cannot yet be evaluated. This RV is not yet valid %s.',reasonStr);

            assert(~R.badCovariance,'Covariance matrix is not positive definite. Consider modifying "covarianceStructure".');
            X = R.dataInputParse(X); % Basic error checking etc

            assert(size(X,2) == R.nDimensions,'Data, RV dimensionality missmatch. Input data, X, has dimensionality %d and this RV has dimensionality %d.', size(X,2), R.nDimensions)
            assert(isnumeric(X) && ndims(X)==2,'X must be a 2D numeric array.');

            vals = exp(prtRvUtilMvnLogPdf(X,R.mu,R.sigma));
        end

        function vals = logPdf(R,X)
            % LOGPDF Output the log pdf of the random variable evaluated at the points specified
            %
            % logpdf = RV.logpdf(X) returns the logarithm of value of the
            % pdf of the prtRv object evaluated at X. X must be an N x
            % nDims matrix, where N is the number of locations to evaluate
            % the pdf, and nDims is the same as the number of dimensions,
            % nDimensions, of the prtRv object RV.

            X = R.dataInputParse(X); % Basic error checking etc
            try
               vals = prtRvUtilMvnLogPdf(X,R.mu,R.sigma);
            catch ME
                [isValid, reasonStr] = R.isValid;
                assert(isValid,'LOGPDF cannot yet be evaluated. This RV is not yet valid %s.',reasonStr);
                assert(size(X,2) == R.nDimensions,'Data, RV dimensionality missmatch. Input data, X, has dimensionality %d and this RV has dimensionality %d.', size(X,2), R.nDimensions)
                throw(ME);
            end
        end

        function varargout = plotCdf(R,varargin)
            % PLOTCDF Plots the CDF of the prtRv
            assert(R.nDimensions == 1,'prtRvMvn.plotCdf can only be used for 1D RV objects.');

            varargout = cell(nargout,1);

            [varargout{:}] = plotCdf@prtRv(R,varargin{:});

        end

        function vals = cdf(R,X)
            % CDF Output the cdf of the random variable evaluated at the points specified
            %
            % cdf = RV.cdf(X) returns the value of the cdf of the prtRv
            % object evaluated at X. X must be an N x nDims matrix, where
            % N is the number of locations to evaluate the pdf, and nDims
            % is the same as the number of dimensions, nDimensions, of the
            % prtRv object RV.

            [isValid, reasonStr] = R.isValid;
            assert(isValid,'CDF cannot yet be evaluated. This RV is not yet valid %s.',reasonStr);

            assert(~R.badCovariance,'Covariance matrix is not positive definite. Consider modifying "covarianceStructure"');
            X = R.dataInputParse(X); % Basic error checking etc

            assert(size(X,2) == R.nDimensions,'Data, RV dimensionality missmatch. Input data, X, has dimensionality %d and this RV has dimensionality %d.', size(X,2), R.nDimensions)
            vals = prtRvUtilMvnCdf(X,R.mu,R.sigma);
        end

        function vals = draw(R,N)
            % DRAW  Draw random samples from the distribution described by the prtRv object
            %
            % VAL = RV.draw(N) generates N random samples drawn from the
            % distribution described by the prtRv object RV. VAL will be a
            % N x nDimensions vector, where nDimensions is the number of
            % dimensions of RV.

            assert(numel(N)==1 && N==floor(N) && N > 0,'N must be a positive integer scalar.')
            [isValid, reasonStr] = R.isValid;
            assert(isValid,'DRAW cannot yet be evaluated. This RV is not yet valid %s.',reasonStr);

            assert(~R.badCovariance,'Covariance matrix is not positive definite. Consider modifying "covarianceStructure"');
            vals = prtRvUtilMvnDraw(R.mu,R.sigma,N);
        end
    end

    methods (Hidden=true)
        function [val, reasonStr] = isValid(R)

            if numel(R) > 1
                val = false(size(R));
                for iR = 1:numel(R)
                    [val(iR), reasonStr] = isValid(R(iR));
                end
                return
            end

            val = ~isempty(R.sigma) && ~isempty(R.mu);

            if val
                reasonStr = '';
            else
                badCov = isempty(R.sigma);
                badMean = isempty(R.mu);

                if badCov && ~badMean
                    reasonStr = 'because sigma has not been set';
                elseif ~badCov && badMean
                    reasonStr = 'because mu has not been set';
                elseif badCov && badMean
                    reasonStr = 'because mu and sigma have not been set';
                else
                    reasonStr = 'because of an unknown reason';
                end
            end
        end

        function val = plotLimits(R)
            [isValid, reasonStr] = R.isValid;
            if isValid
                minX = min(R.mu, [], 1)' - 2*sqrt(diag(R.sigma));
                maxX = max(R.mu, [], 1)' + 2*sqrt(diag(R.sigma));

                val = zeros(1,2*R.nDimensions);
                val(1:2:R.nDimensions*2-1) = minX;
                val(2:2:R.nDimensions*2) = maxX;
            else
                error('prtRvMvn:plotLimits','Plotting limits can not be determined for this RV. It is not yet valid %s',reasonStr)
            end
        end

        function R = weightedMle(R,X,weights)
            assert(numel(weights)==size(X,1),'The number of weights must mach the number of observations.');

            weights = weights(:);

            Nbar = sum(weights);
            R.mu = 1/Nbar*sum(bsxfun(@times,X,weights),1);
            X = bsxfun(@times,bsxfun(@minus,X,R.mu),sqrt(weights));
            R.sigma = 1/Nbar*(X'*X);
        end
    end

    % Get methods
    methods
        function val = get.nDimensions(R)
            val = getNumDimensions(R);
        end

        function val = get.mu(R)
            val = R.muDepHelper;
        end
        function val = get.sigma(R)
            val = R.sigmaDepHelper;
        end
        function val = get.covarianceStructure(R)
            val = R.covarianceStructureDepHelper;
        end
    end
    methods (Access = 'protected')
        function val = getNumDimensions(R)
            if ~isempty(R.mu)
                val = length(R.mu);
            elseif ~isempty(R.sigma)
                val = size(R.sigma,2);
            else
                val = [];
            end
        end
    end
    % Set Methods
    methods
        function R = set.covarianceStructure(R,covarianceStructure)
            % Find and fix known abbreviations

            assert(ischar(covarianceStructure),'covarianceStructure must be a string that is either, full, diagonal, or spherical');

            covarianceStructure = lower(covarianceStructure);

            if strcmpi(covarianceStructure,'diag')
                covarianceStructure = 'diagonal';
            end

            % Limit the options for the covariance structure
            if ~(strcmpi(covarianceStructure,'full') || ...
                    strcmpi(covarianceStructure,'diagonal') || ...
                    strcmpi(covarianceStructure,'spherical'))
                error('%s is not a valid covariance structure. Possible types are, full, diagonal, and spherical',covarianceStructure);
            end
            R.covarianceStructureDepHelper = covarianceStructure;

            % Redo the covariance to reflect the updated covarianceStructure
            if ~isempty(R.sigma)
                R.sigma = R.trueCovariance; % This will call set.sigma()
            end
        end

        function R = set.mu(R,meanVal)
            if ~isempty(R.sigma) && size(meanVal,2) ~= size(R.sigma,2)
                error('prtRvMvn:dimensions','Dimensions mismatch between supplied mu and prtRvMvn dimensionality');
            end
            R.muDepHelper = meanVal;
        end

        function R = set.sigma(R,sigma)
            if size(sigma,1) ~= size(sigma,2)
                error('Covariance matrix must be square.')
            end

            if ~isempty(R.mu) && size(sigma,1) ~= R.nDimensions
                error('prtRvMvn:dimensions','Dimensions mismatch between sigma and prtRvMvn dimensionality')
            end

            % Save this input as a true hidden sigma
            R.trueCovariance = sigma;

            % Enforce the covariance structure
            switch lower(R.covarianceStructure)
                case 'full'
                    R.sigmaDepHelper = sigma;
                case 'diagonal'
                    R.sigmaDepHelper = eye(size(sigma)).*sigma;
                case 'spherical'
                    R.sigmaDepHelper = eye(size(sigma))*mean(diag(sigma));
            end

            if ~isempty(R.covarianceBias)
                R.sigmaDepHelper = R.sigmaDepHelper + R.covarianceBias.*eye(size(sigma));
            end

            [dontNeed, cholErr] = chol(R.sigmaDepHelper); %#ok<ASGLU>
            if cholErr ~=0
                R.badCovariance = true;
                warning('prt:prtRvMvn','Covariance matrix is not positive definite. This may cause errors. Consider modifying "covarianceStructure".');
            end
        end
    end
end


function [] = shapeSIRFS(class,jobID)
%GETDEPTHIMAGE Summary of this function goes here
%   Detailed explanation goes here

statesDir = jobDirs(class,jobID,'state');
sirfsstatedir = jobDirs(class,jobID,'sirfs');
dmapDir = jobDirs(class,jobID,'dmap');
mkdirOptional(sirfsstatedir);
fnames = getFileNamesFromDirectory(dmapDir,'types',{'.mat'});

fprintf('\n%%%%%%%%%%%% SIRFS %%%%%%%%%%%%\n');
%% Loading precomputed shape
for i=1:length(fnames)
%for i=1:length(fnames)
    sirfsdmapFile = fullfile(sirfsstatedir,fnames{i});
    if(exist(sirfsdmapFile,'file'))
        continue;
    end
    stateFile = fullfile(statesDir,fnames{i});
    state = load(stateFile);state=state.state;
    dmapFile = fullfile(dmapDir,fnames{i});
    dmap = load(dmapFile); dmap = dmap.dmap;
    sirfsstate = getsirfsstate(state,dmap);
    savefunc(sirfsdmapFile,sirfsstate);
    %vis_PSIRFS(sirfsstate); pause
end
end

function savefunc(file,state)
    save(file,'state');
end

function sirfsstate = getsirfsstate(state,depthIm)
    sigma = 3; % Controls the "bandwidth" of the input depth (the standard deviation of a Gaussian at which point the signal becomes reliable)
    mult = 5; % Controls the importance of the input depth (the multiplier on the loss)
    niters = 200;
    depthIm(isinf(depthIm)) = nan;
    depthIm = -depthIm;
    input_image = im2double(state.im);
    input_image(input_image<1/255) = 1/255;
    dmapMask = ~isinf(depthIm) & ~isnan(depthIm);
    %imshow(color_seg(dmapMask,state.im));
    sirfsstate = SIRFS(input_image, dmapMask, depthIm, ...
        ['params.DO_DISPLAY = 0; params.N_ITERS_OPTIMIZE = ' num2str(niters) ';params.USE_INIT_Z = true; params.INIT_Z_SIGMA = ',...
        num2str(sigma), ';params.multipliers.height.init = { ', num2str(mult), ' };']);
%     sirfsstate = SIRFS(input_image, (state.mask), [], ...
%         ['params.DO_DISPLAY = 0; params.N_ITERS_OPTIMIZE = ' num2str(niters) ';']);
    sirfsstate.mask = dmapMask;
    sirfsstate.im = input_image;
    sirfsstate.dmap = sirfsstate.height;
end


function [MDP] = spm_MDP_check(MDP)
% MDP structure checking
% FORMAT [MDP] = spm_MDP_check(MDP)
%
% MDP.V(T - 1,P,F)      - P allowable policies of T moves over F factors
% or
% MDP.U(1,P,F)          - P allowable actions at each move
% MDP.T                 - number of outcomes
%
% MDP.A{G}(O,N1,...,NF) - likelihood of O outcomes given hidden states
% MDP.B{F}(NF,NF,MF)    - transitions among hidden under MF control states
% MDP.C{G}(O,T)         - prior preferences over O outcomes in modality G
% MDP.D{F}(NF,1)        - prior probabilities over initial states
%
% MDP.a{G}              - concentration parameters for A
% MDP.b{F}              - concentration parameters for B
% MDP.d{F}              - concentration parameters for D
%
% optional:
% MDP.s(F,T)            - vector of true states - for each hidden factor
% MDP.o(G,T)            - vector of outcome     - for each outcome modality
% MDP.u(F,T - 1)        - vector of action      - for each hidden factor
% MDP.w(1,T)            - vector of precisions
%
% if C or D are not specified, they will be set to default values (of no
% preferences and uniform priors over initial steps).  If there are no
% policies, it will be assumed that I = 1 and all policies (for each
% marginal hidden state) are allowed.
%__________________________________________________________________________
% Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging

% Karl Friston
% $Id: spm_MDP_check.m 7766 2020-01-05 21:37:39Z karl $

% deal with a sequence of trials
%==========================================================================

% if there are multiple structures check each separately
%--------------------------------------------------------------------------
if numel(MDP) > 1
    for m = 1:size(MDP,1)
        for i = 1:size(MDP,2)
            mdp(m,i) = spm_MDP_check(MDP(m,i));
        end
    end
    MDP   = mdp;
    return
end

% fill in (posterior or  process) likelihood and priors
%--------------------------------------------------------------------------
if ~isfield(MDP,'A'), MDP.A = MDP.a; end
if ~isfield(MDP,'B'), MDP.B = MDP.b; end

% check format of likelihood and priors
%--------------------------------------------------------------------------
if ~iscell(MDP.A), MDP.A = {full(MDP.A)}; end
if ~iscell(MDP.B), MDP.B = {full(MDP.B)}; end

if isfield(MDP,'a'), if ~iscell(MDP.a), MDP.a = {full(MDP.a)}; end; end
if isfield(MDP,'b'), if ~iscell(MDP.b), MDP.b = {full(MDP.b)}; end; end

% check dimensions and orders
%==========================================================================

% numbers of transitions, policies and states
%--------------------------------------------------------------------------
Nf  = numel(MDP.B);                 % number of hidden state factors
Ng  = numel(MDP.A);                 % number of outcome factors
for f = 1:Nf
    Nu(f)    = size(MDP.B{f},3);    % number of hidden controls
    Ns(f)    = size(MDP.B{f},1);    % number of hidden states
    MDP.B{f} = double(MDP.B{f});
end
for g = 1:Ng
    No(g)    = size(MDP.A{g},1);    % number of outcomes
    MDP.A{g} = double(MDP.A{g});
end

% check policy specification (create default moving policy U, if necessary)
% V = V(Nt,Np,Nf)
% U = U(Np,Nf)
%--------------------------------------------------------------------------
if isfield(MDP,'U')
    if size(MDP.U,1) == 1 && size(MDP.U,3) == Nf
        MDP.U = shiftdim(MDP.U,1);
    end
end
try
    V(1,:,:) = MDP.U;               % allowable actions (1,Np)
catch
    try
        V = MDP.V;                  % allowable policies (T - 1,Np)
    catch

        % allowable (moving) policies using all allowable actions
        %------------------------------------------------------------------
        for f = 1:Nf
            u = 1;
            for i = 1:Nf
                if i == f
                    u = kron(1:Nu(i),u);
                else
                    u = kron(ones(1,Nu(i)),u);
                end
            end
            MDP.U(:,f)  = u;
        end
        V(1,:,:) = MDP.U;
    end
end
MDP.V = V;

% check policy specification
%--------------------------------------------------------------------------
if Nf ~= size(V,3) && size(V,3) > 1
    error('please ensure V(:,:,1:Nf) is consistent with MDP.B{1:Nf}')
end

% check preferences
%--------------------------------------------------------------------------
if ~isfield(MDP,'C')
    for g = 1:Ng
        MDP.C{g} = zeros(No(g),1);
    end
end
for g = 1:Ng
    if iscell(MDP.C)
        if isvector(MDP.C{g})
            MDP.C{g} = spm_vec(MDP.C{g});
        end
        if No(g) ~= size(MDP.C{g},1)
            error(['please ensure A{' num2str(g) '} and C{' num2str(g) '} are consistent'])
        end
    end
end

% check iinitial states
%--------------------------------------------------------------------------
if ~isfield(MDP,'D')
    for f = 1:Nf
        MDP.D{f} = ones(Ns(f),1);
    end
end
if Nf  ~= numel(MDP.D)
    error('please ensure V(:,:,1:Nf) is consistent with MDP.D{1:Nf}')
end

% check iinitial states and internal consistency
%--------------------------------------------------------------------------
if Nf  ~= numel(MDP.D)
    error('please ensure V(:,:,1:Nf) is consistent with MDP.D{1:Nf}')
end
for f = 1:Nf
    if Ns(f) ~= size(MDP.D{f},1)
        error(['please ensure B{' num2str(f) '} and D{' num2str(f) '} are consistent'])
    end
    if size(V,3) > 1
        if Nu(f) < max(spm_vec(V(:,:,f)))
            error(['please check V(:,:,' num2str(f) ') or U(:,:,' num2str(f) ')'])
        end
    end
    for g = 1:Ng
        Na  = size(MDP.A{g});
        if ~all(Na(2:end) == Ns)
            error(['please ensure A{' num2str(g) '} and D{' num2str(f) '} are consistent'])
        end
    end
end

% check probability matrices are properly specified
%--------------------------------------------------------------------------
for f = 1:Nf
    if ~all(spm_vec(any(MDP.B{f},1)))
        error(['please check B{' num2str(f) '} for missing entries'])
    end
end
for g = 1:Ng
    if ~all(spm_vec(any(MDP.A{g},1)))
        error(['please check A{' num2str(g) '} for missing entries'])
    end
end

% check initial states
%--------------------------------------------------------------------------
if isfield(MDP,'s')
    if size(MDP.s,1) > Nf
        error('please specify an initial state MDP.s for %i factors',Nf)
    end
    f  = max(MDP.s,[],2)';
    if any(f > Ns(1:numel(f)))
        error('please ensure initial states MDP.s are consistent with MDP.B')
    end
end

% check outcomes if specified
%--------------------------------------------------------------------------
if isfield(MDP,'o')
    if numel(MDP.o)
        if size(MDP.o,1) ~= Ng
            error('please specify an outcomes MDP.o for %i modalities',Ng)
        end
        if any(max(MDP.o,[],2) > No(:))
            error('please ensure outcomes MDP.o are consistent with MDP.A')
        end
    end
end

% check (primary link array if necessary)
%--------------------------------------------------------------------------
if isfield(MDP,'link')

    % cardinality of subordinate level
    %----------------------------------------------------------------------
    nf    = numel(MDP.MDP(1).B);               % number of hidden factors
    for f = 1:nf
        ns(f)    = size(MDP.MDP(1).B{f},1);    % number of hidden states
    end

    % check the size of link
    %----------------------------------------------------------------------
    if ~all(size(MDP.link) == [nf,Ng]);
        error('please check the size of link {%i,%i}',nf,Ng)
    end

    % convert matrix to cell array if necessary
    %----------------------------------------------------------------------
    if isnumeric(MDP.link)
        link  = cell(nf,Ng);
        for f = 1:size(MDP.link,1)
            for g = 1:size(MDP.link,2)
                if MDP.link(f,g)
                    link{f,g} = spm_speye(ns(f),No(g),0);
                end
            end
        end
        MDP.link = link;
    end

    % check sizes of cell array
    %----------------------------------------------------------------------
    for f = 1:size(MDP.link,1)
        for g = 1:size(MDP.link,2)
            if ~isempty(MDP.link{f,g})
                if ~all(size(MDP.link{f,g}) == [ns(f),No(g)]);
                    error('please check link{%i,%i}',f,g)
                end
            end
        end
    end

end

% Empirical prior preferences
%--------------------------------------------------------------------------
if isfield(MDP,'linkC')
    if isnumeric(MDP.linkC)
        linkC  = cell(numel(MDP.MDP.C),Ng);
        for f = 1:size(MDP.linkC,1)
            for g = 1:size(MDP.linkC,2)
                if MDP.linkC(f,g)
                    linkC{f,g} = spm_speye(size(MDP.MDP.C{f},1),No(g),0);
                end
            end
        end
        MDP.linkC = linkC;
    end
end

% Empirical priors over policies
%--------------------------------------------------------------------------
if isfield(MDP,'linkE')
    if isnumeric(MDP.linkE)
        linkE  = cell(1,Ng);
        for g = 1:size(MDP.linkE,2)
            if MDP.linkE(g)
                linkE{g} = spm_speye(size(MDP.MDP.E,1),No(g),0);
            end
        end
        MDP.linkE = linkE;
    end
end

% check factors and outcome modalities have proper labels
%--------------------------------------------------------------------------
for i = 1:Nf

    % name of factors
    %----------------------------------------------------------------------
    try
        MDP.label.factor(i);
    catch
        try
            MDP.label.factor{i} = MDP.Bname{i};
        catch
            MDP.label.factor{i} = sprintf('factor %i',i);
        end
    end

    % name of levels of each factor
    %----------------------------------------------------------------------
    for j = 1:Ns(i)
        try
            MDP.label.name{i}(j);
        catch
            try
                MDP.label.name{i}{j} = MDP.Sname{i}{j};
            catch
                MDP.label.name{i}{j} = sprintf('state %i(%i)',j,i);
            end
        end
    end

    % name of actions under each factor
    %----------------------------------------------------------------------
    for j = 1:Nu(i)
        try
            MDP.label.action{i}(j);
        catch
            MDP.label.action{i}{j} = sprintf('act %i(%i)',j,i);
        end
    end
end

% name of outcomes under each modality
%--------------------------------------------------------------------------
for i = 1:Ng
    try
        MDP.label.modality(i);
    catch
        try
            MDP.label.modality{i} = MDP.Bname{i};
        catch
            MDP.label.modality{i} = sprintf('modality %i',i);
        end
    end
    for j = 1:No(i)
        try
            MDP.label.outcome{i}(j);
        catch
            try
                MDP.label.outcome{i}{j} = MDP.Oname{i}{j};
            catch
                MDP.label.outcome{i}{j} = sprintf('outcome %i(%i)',j,i);
            end
        end
    end
end

% check names are specified properly
%--------------------------------------------------------------------------
if isfield(MDP,'Aname')
    if numel(MDP.Aname) ~= Ng
        error('please specify an MDP.Aname for each modality')
    end
else
    MDP.Aname = MDP.label.modality;
end
if isfield(MDP,'Bname')
    if numel(MDP.Bname) ~= Nf
        error('please specify an MDP.Bname for each factor')
    end
else
    MDP.Bname = MDP.label.factor;
end


function showTrendCorrelation(fitVals, correlations, titleString)

figure('Name', titleString, 'Color', [1, 1, 1]);
hold on
line([-1, 1], [0, 0], 'LineWidth', 2', 'Color', [0.9, 0.9, 0.9])
plot(correlations, fitVals(:, 1), 'k', 'Marker', '+', 'MarkerSize', 12', ...
    'LineWidth', 2, 'LineStyle', 'None')
hold off
set(gca, 'XLim', [-1, 1], 'XLimMode', 'manual')
xlabel('Channel-trend correlation')
ylabel('Slope of trend')
title(titleString, 'Interpreter', 'none')

figure('Name', titleString, 'Color', [1, 1, 1]);
hold on
line( [0, 0], [-1, 1], 'LineWidth', 2', 'Color', [0.9, 0.9, 0.9])
plot(fitVals(:, 1), correlations, 'k', 'Marker', '+', 'MarkerSize', 12', ...
    'LineWidth', 2, 'LineStyle', 'None')
hold off
set(gca, 'YLim', [-1, 1], 'YLimMode', 'manual')
ylabel('Channel-trend correlation')
xlabel('Slope of trend')
title(titleString, 'Interpreter', 'none')


function []=TVEmavardisp(beta_median,beta_std,beta_lbound,beta_ubound,theta_median,psi_std,psi_lbound,psi_ubound,sigma_median,X,Z,Y,n,m,p,k1,k3,q1,q2,T,ar,lambda1,lambda2,lambda3,lambda4,lambda5,IRFt,beta_gibbs,endo,exo,psi_gibbs,startdate,enddate,stringdates1,decimaldates1,datapath,data_endo,TVEH,indH,pref)

% function []=mavardisp(beta_median,beta_std,beta_lbound,beta_ubound,psi_median,psi_std,psi_lbound,psi_ubound,sigma_median,X,Z,Y,n,m,p,k1,k3,q1,q2,T,ar,lambda1,lambda2,lambda3,lambda4,lambda5,IRFt,beta_gibbs,endo,exo,psi_gibbs,startdate,enddate,stringdates1,decimaldates1,datapath)
% displays estimation results for the MABVAR model on Matlab prompt, creates a copy of these results on the text file results.txt
% inputs:  - vector 'beta_median': median value of the posterior distribution of beta
%          - vector 'beta_std': standard deviation of the posterior distribution of beta
%          - vector 'beta_lbound': lower bound of the credibility interval of beta
%          - vector 'beta_ubound': upper bound of the credibility interval of beta
%          - vector 'psi_median': median value of the posterior distribution of psi
%          - vector 'psi_std': standard deviation of the posterior distribution of psi
%          - vector 'psi_lbound': lower bound of the credibility interval of psi
%          - vector 'psi_ubound': upper bound of the credibility interval of psi
%          - vector 'sigma_median': median value of the posterior distribution of sigma (vectorised)
%          - matrix 'X': matrix of regressors for the VAR model (defined in 3.5.10)
%          - matrix 'Z': matrix of exogenous regressors for the MABVAR model (defined in 3.5.10)
%          - matrix 'Y': matrix of regressands for the VAR model (defined in 3.5.10)
%          - integer 'n': number of endogenous variables in the BVAR model (defined p 7 of technical guide)
%          - integer 'm': number of exogenous variables in the BVAR model (defined p 7 of technical guide)
%          - integer 'p': number of lags included in the model (defined p 7 of technical guide)
%          - integer 'k1': number of endogenous coefficients to estimate for each equation in the MABVAR model (defined p 77 of technical guide)
%          - integer 'k3': number of exogenous coefficients to estimate for each equation in the reformulated MABVAR model (defined p 77 of technical guide)
%          - integer 'q1': total number of endogenous coefficients to estimate in the MABVAR model (defined p 77 of technical guide)
%          - integer 'q2': total number of exogenous coefficients to estimate in the MABVAR model (defined p 77 of technical guide)
%          - integer 'T': number of sample time periods (defined p 7 of technical guide)
%          - scalar 'lambda1': overall tightness hyperparameter (defined p 16 of technical guide)
%          - scalar 'lambda2': cross-variable weighting hyperparameter(defined p 16 of technical guide)
%          - scalar 'lambda3': lag decay hyperparameter (defined p 16 of technical guide)
%          - scalar 'lambda4': exogenous variable tightness hyperparameter (defined p 17 of technical guide)
%          - scalar 'lambda5': block exogeneity shrinkage hyperparameter (defined p 32 of technical guide)
%          - integer 'IRFt': determines which type of structural decomposition to apply (none, Choleski, triangular factorization)
%          - matrix 'beta_gibbs': record of the gibbs sampler draws for the beta vector
%          - cell 'endo': list of endogenous variables of the model
%          - matrix 'psi_gibbs': record of the gibbs sampler draws for the psi vector
%          - cell 'exo': list of exogenous variables of the model
%          - string 'startdate': start date of the sample
%          - string 'enddate': end date of the sample
%          - cell 'stringdates1': date strings for the sample period
%          - vector 'decimaldates1': dates converted into decimal values, for the sample period
%          - string 'datapath': user-supplied path to excel data spreadsheet
% outputs: none

% before displaying and saving the results, start estimating the evaluation measures for the model

% obtain first a point estimate betatilde of the VAR coefficients related to endogenous variables
% this is simply beta_median, which is both the mean and the median of the normal distribution
betatilde=beta_median;
Btilde=reshape(betatilde,k1,n);
% generate U, using Btilde, from (3.5.15)
% U=eye(n*m);
%    for jj=1:p
%    U=[U;kron(eye(m),Btilde((jj-1)*n+1:jj*n,:)')];
%    end

% obtain then a point estimate psitilde of the VAR coefficients related to exogenous variables
% this is simply psi_median, which is both the mean and the median of the normal distribution
theta=theta_median;

% % combine the two to obtain vec(DELTA'), using (3.5.14)
% vecdeltap=U*psitilde;
% % recover delta
% deltap=reshape(vecdeltap,n,k3);
% DELTA=deltap';

for it=1:T+p
    eq(it,:)=(squeeze(TVEH(:,:,indH(it),it))*theta)'; % compute the equilibrium values given theta
end

temp2=data_endo-eq;
temp3=bear.lagx(temp2,p);
Yhat=temp3(:,1:n);
Xhat=temp3(:,n+1:end);

% then produce the corresponding residuals, using (3.5.9)
EPStilde=Yhat-Xhat*Btilde;
Ytilde=Y-EPStilde;

% check first whether the model is stationary, using (1.9.1)
[stationary eigmodulus]=mabear.checkstable(Btilde,n,p);

% Compute then the sum of squared residuals
% compute first the RSS matrix, defined in (1.9.5)
RSS=EPStilde'*EPStilde;
% retain only the diagonal elements to get the vector of RSSi values
rss=diag(RSS);

% Go on calculating R2
% generate Mbar
Mbar=eye(T)-ones(T,T)/T;
% then compute the TSS matrix, defined in (1.9.8)
TSS=Y'*Mbar*Y;
% generate the R2 matrix in (1.9.9)
R2=eye(n)-RSS./TSS;
% retain only the diagonal elements to get the vector of R2 values
r2=diag(R2);

% then calculate the adjusted R2, using (1.9.11)
R2bar=eye(n)-((T-1)/(T-(k1+m)))*(eye(n)-R2);
% retain only the diagonal elements to get the vector of R2bar values
r2bar=diag(R2bar);

% now start displaying and saving the results

% preliminary task: create and open the txt file used to save the results

% filelocation=datapath;
% filelocation=[filelocation '\results.txt'];
% fid=fopen(filelocation,'wt');

filelocation=fullfile(pref.results_path, [pref.results_sub '.txt']);
fid=fopen(filelocation,'wt');

% print toolbox header

fprintf('%s\n','');
fprintf(fid,'%s\n','');

fprintf('%s\n','%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');
fprintf(fid,'%s\n','%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');
fprintf('%s\n','%                                                                                %%');
fprintf(fid,'%s\n','%                                                                                %');
fprintf('%s\n','%    BAYESIAN ESTIMATION, ANALYSIS AND REGRESSION (BEAR) TOOLBOX                                         %');
fprintf(fid,'%s\n','%    BAYESIAN ESTIMATION, ANALYSIS AND REGRESSION (BEAR) TOOLBOX                                     %');
fprintf('%s\n','%                                                                                %');
fprintf(fid,'%s\n','%                                                                                %');
fprintf('%s\n','%    This statistical package has been developed by the external developments division of the ECB.       %');
fprintf(fid,'%s\n','%    This statistical package has been developed by the external developments division of the ECB.   %');
fprintf('%s\n','%                                                                                %');
fprintf(fid,'%s\n','%                                                                                %');
fprintf('%s\n','%    Authors:                                                                                %');
fprintf(fid,'%s\n','%    Authors:                                                                                %');
fprintf('%s\n','%    Romain Legrand  (Romain Legrand <b00148883@essec.edu>)                                              %');
fprintf(fid,'%s\n','%    Romain Legrand  (Romain Legrand <b00148883@essec.edu>)                                          %');
fprintf('%s\n','%    Alistair Dieppe (adieppe@worldbank.org)                                                             %');
fprintf(fid,'%s\n','%    Alistair Dieppe (adieppe@worldbank.org)                                                         %');
fprintf('%s\n','%    Björn van Roye  (Bjorn.van_Roye@ecb.europa.eu)                                                      %');
fprintf(fid,'%s\n','%    Björn van Roye  (Bjorn.van_Roye@ecb.europa.eu)                                                  %');
fprintf('%s\n','%                                                                                %');
fprintf(fid,'%s\n','%                                                                                %');
fprintf('%s\n','%    Version 4.4                                                                                %');
fprintf(fid,'%s\n','%    Version 4.4                                                                                %');
fprintf('%s\n','%                                                                                %');
fprintf(fid,'%s\n','%                                                                                %');
fprintf('%s\n','%    The authors are grateful to Paolo Bonomolo, Marta Banbura, Martin Bruns, Fabio Canova,              %');
fprintf(fid,'%s\n','%    The authors are grateful to Paolo Bonomolo, Marta Banbura, Martin Bruns, Fabio Canova,          %');
fprintf('%s\n','%    Matteo Ciccarelli, Marek Jarocinski, Niccolo Battistini, Gabriel Bobeica                            %');
fprintf(fid,'%s\n','%    Matteo Ciccarelli, Marek Jarocinski, Niccolo Battistini, Gabriel Bobeica                        %');
fprintf('%s\n','%    Michele Lenza, Chiara Osbat, Mirela Miescu, Gary Koop, Giorgio Primiceri                            %');
fprintf(fid,'%s\n','%    Michele Lenza, Chiara Osbat, Mirela Miescu, Gary Koop, Giorgio Primiceri,                       %');
fprintf('%s\n','%    Michal Rubaszek, Barbara Rossi, Ben Schumann, Peter Welz, Hugo Vega de la Cruz and Francesca Loria. %');
fprintf(fid,'%s\n','%  Michal Rubaszek, Barbara Rossi, Ben Schumann, Peter Welz, Hugo Vega de la Cruz and Francesca Loria%');
fprintf('%s\n','%    valuable input and advice which contributed to improve the quality of this work.                    %');
fprintf(fid,'%s\n','%  valuable input and advice which contributed to improve the quality of this work.                  %');
fprintf('%s\n','%                                                                                %');
fprintf(fid,'%s\n','%                                                                                %');
fprintf('%s\n','%   These programmes are the responsibilities of the authors and not of the ECB and the Worldbank.       %');
fprintf(fid,'%s\n','%   These programmes are the responsibilities of the authors and not of the ECB and the Worldbank.   %');
fprintf('%s\n','%   Errors and ommissions remain those of the authors.                                                   %');
fprintf(fid,'%s\n','%   Errors and ommissions remain those of the authors.                                               %');
fprintf('%s\n','%                                                                                %');
fprintf(fid,'%s\n','%                                                                                %');
fprintf('%s\n','%    Please do not use or quote this work without permission.                                            %');
fprintf(fid,'%s\n','%    Please do not use or quote this work without permission.                                        %');
fprintf('%s\n','%                                                                                %');
fprintf(fid,'%s\n','%                                                                                %');
fprintf('%s\n','%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');
fprintf(fid,'%s\n','%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');

% print then estimation results

fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');

toolboxinfo='BEAR toolbox estimates';
fprintf('%s\n',toolboxinfo);
fprintf(fid,'%s\n',toolboxinfo);

time=clock;
datestring=datestr(time);
dateinfo=['Date: ' datestring(1,1:11) '   Time: ' datestring(1,13:17)];
fprintf('%s\n',dateinfo);
fprintf(fid,'%s\n',dateinfo);

fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');

VARtypeinfo='Mean-adjusted BVAR';
fprintf('%s\n',VARtypeinfo);
fprintf(fid,'%s\n',VARtypeinfo);

if IRFt==1
SVARinfo='structural decomposition: none';
elseif IRFt==2
SVARinfo='structural decomposition: choleski factorisation';
elseif IRFt==3
SVARinfo='structural decomposition: triangular factorisation';
elseif IRFt==4
SVARinfo='structural decomposition: sign restrictions';
end
fprintf('%s\n',SVARinfo);
fprintf(fid,'%s\n',SVARinfo);

temp='endogenous variables: ';
for ii=1:n
temp=[temp ' ' endo{ii,1} ' '];
end
endoinfo=temp;
fprintf('%s\n',endoinfo);
fprintf(fid,'%s\n',endoinfo);

temp='exogenous variables: constant';
% if m>1
%    for ii=1:m-1
%    temp=[temp ' ' exo{ii,1} ' '];
%    end
% end
exoinfo=temp;
fprintf('%s\n',exoinfo);
fprintf(fid,'%s\n',exoinfo);

sampledateinfo=['estimation sample: ' startdate '-' enddate];
fprintf('%s\n',sampledateinfo);
fprintf(fid,'%s\n',sampledateinfo);

samplelengthinfo=['sample size (omitting initial conditions): ' num2str(T)];
fprintf('%s\n',samplelengthinfo);
fprintf(fid,'%s\n',samplelengthinfo);

laginfo=['number of lags included in regression: ' num2str(p)];
fprintf('%s\n',laginfo);
fprintf(fid,'%s\n',laginfo);

hyperparam1='hyperparameters:';
fprintf('%s\n',hyperparam1);
fprintf(fid,'%s\n',hyperparam1);

%hyperparam2=['autoregressive coefficient (ar):          ' num2str(ar)];
%fprintf('%s\n',hyperparam2);
%fprintf(fid,'%s\n',hyperparam2);

hyperparam3=['overall tightness (lambda1):              ' num2str(lambda1)];
fprintf('%s\n',hyperparam3);
fprintf(fid,'%s\n',hyperparam3);

hyperparam4=['cross-variable weighting (lambda2):       ' num2str(lambda2)];
fprintf('%s\n',hyperparam4);
fprintf(fid,'%s\n',hyperparam4);

hyperparam5=['lag decay (lambda3):                      ' num2str(lambda3)];
fprintf('%s\n',hyperparam5);
fprintf(fid,'%s\n',hyperparam5);

%hyperparam6=['exogenous variable tightness (lambda4):   ' num2str(lambda4)];
%fprintf('%s\n',hyperparam6);
%fprintf(fid,'%s\n',hyperparam6);

hyperparam7=['block exogeneity shrinkage (lambda5):     ' num2str(lambda5)];
fprintf('%s\n',hyperparam7);
fprintf(fid,'%s\n',hyperparam7);

% display coefficient estimates

fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');

coeffinfo=['VAR coefficients (beta): posterior estimates'];
fprintf('%s\n',coeffinfo);
fprintf(fid,'%s\n',coeffinfo);

for ii=1:n

fprintf('%s\n','');
fprintf(fid,'%s\n','');
if ii~=1
fprintf('%s\n','');
fprintf(fid,'%s\n','');
end

endoinfo=['Endogenous: ' endo{ii,1}];
fprintf('%s\n',endoinfo);
fprintf(fid,'%s\n',endoinfo);

coeffheader=fprintf('%25s %15s %15s %15s %15s\n','','Median','St.dev','Low.bound','Upp.bound');
coeffheader=fprintf(fid,'%25s %15s %15s %15s %15s\n','','Median','St.dev','Low.bound','Upp.bound');

% handle the endogenous
   for jj=1:n
      for kk=1:p
      values=[beta_median((ii-1)*k1+n*(kk-1)+jj,1) beta_std((ii-1)*k1+n*(kk-1)+jj,1) beta_lbound((ii-1)*k1+n*(kk-1)+jj,1) beta_ubound((ii-1)*k1+n*(kk-1)+jj,1)];
      fprintf('%25s %15.3f %15.3f %15.3f %15.3f\n',strcat(endo{jj,1},'(-',int2str(kk),')'),values);
      fprintf(fid,'%25s %15.3f %15.3f %15.3f %15.3f\n',strcat(endo{jj,1},'(-',int2str(kk),')'),values);
      end
   end

% handle the exogenous
% display the results related to the constant
values=[theta_median(ii,1) psi_std(ii,1) psi_lbound(ii,1) psi_ubound(ii,1)];
fprintf('%25s %15.3f %15.3f %15.3f %15.3f\n','Constant',values);
fprintf(fid,'%25s %15.3f %15.3f %15.3f %15.3f\n','Constant',values);
   % if there is no other exogenous, stop here
   if m==1
   % if there are other exogenous, display their results
   elseif m>1
      for jj=1:m-1
      %values=[theta_median(n*jj+ii,1) psi_std(n*jj+ii,1)
      %psi_lbound(n*jj+ii,1) psi_ubound(n*jj+ii,1)]; BVR, commeted out as
      %it was unused!
      %fprintf('%25s %15.3f %15.3f %15.3f %15.3f\n',exo{jj,1},values);
     %fprintf(fid,'%25s %15.3f %15.3f %15.3f %15.3f\n',exo{jj,1},values);
     end
   end

fprintf('%s\n','');
fprintf(fid,'%s\n','');

% display evaluation measures
rssinfo=['Sum of squared residuals: ' num2str(rss(ii,1),'%.2f')];
fprintf('%s\n',rssinfo);
fprintf(fid,'%s\n',rssinfo);

r2info=['R-squared: ' num2str(r2(ii,1),'%.3f')];
fprintf('%s\n',r2info);
fprintf(fid,'%s\n',r2info);

adjr2info=['adj. R-squared: ' num2str(r2bar(ii,1),'%.3f')];
fprintf('%s\n',adjr2info);
fprintf(fid,'%s\n',adjr2info);

end

fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');

% display VAR stability results
eigmodulus=reshape(eigmodulus,p,n);
stabilityinfo1=['Roots of the characteristic polynomial (modulus):'];
fprintf('%s\n',stabilityinfo1);
fprintf(fid,'%s\n',stabilityinfo1);
for ii=1:p
temp=num2str(eigmodulus(ii,1),'%.3f');
   for jj=2:n
   temp=[temp,'  ',num2str(eigmodulus(ii,jj),'%.3f')];
   end
fprintf('%s\n',temp);
fprintf(fid,'%s\n',temp);
end
if stationary==1;
stabilityinfo2=['No root lies outside the unit circle.'];
stabilityinfo3=['The estimated VAR model satisfies the stability condition'];
fprintf('%s\n',stabilityinfo2);
fprintf(fid,'%s\n',stabilityinfo2);
fprintf('%s\n',stabilityinfo3);
fprintf(fid,'%s\n',stabilityinfo3);
else
stabilityinfo2=['Warning: at leat one root lies on or outside the unit circle.'];
stabilityinfo3=['The estimated VAR model will not be stable'];
fprintf('%s\n',stabilityinfo2);
fprintf(fid,'%s\n',stabilityinfo2);
fprintf('%s\n',stabilityinfo3);
fprintf(fid,'%s\n',stabilityinfo3);
end

fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');

% display posterior for sigma
sigmainfo=['sigma (residual covariance matrix): posterior estimates'];
fprintf('%s\n',sigmainfo);
fprintf(fid,'%s\n',sigmainfo);
% calculate the (integer) length of the largest number in sigma, for formatting purpose
width=length(sprintf('%d',floor(max(abs(bear.vec(sigma_median))))));
% add a separator, a potential minus sign, and three digits (total=5) to obtain the total space for each entry in the matrix
width=width+5;
for ii=1:n
temp=[];
   for jj=1:n
   % convert matrix entry into string
   number=num2str(sigma_median(ii,jj),'% .3f');
      % pad potential missing blanks
      while numel(number)<width
      number=[' ' number];
      end
   number=[number '  '];
   temp=[temp number];
   end
fprintf('%s\n',temp);
fprintf(fid,'%s\n',temp);
end

fclose(fid);

% Finally, display the results in terms of graph
if pref.plot

% graph the empirical posterior distribution of the VAR parameters
% first reshape the gibbs sampler output to be compatible with the way Matlab uses subplot
% first concatenate psi_gibbs on beta_gibbs to obtain a vector similar to beta in the classical BVAR model
temp=[];
for ii=1:n
temp=[temp;beta_gibbs((ii-1)*k1+1:ii*k1,:)];
   for jj=1:m
   temp=[temp;psi_gibbs((jj-1)*m+ii,:)];
   end
end
beta_reshape=temp;
[beta_swap]=bear.betaswap(beta_reshape,n,m,p,k1+m);
plotvar=1;
plotlag=1;
plotexo=1;
plotconst=1;
% then plot the figure
%{
postdis=figure;
set(postdis,'Color',[0.9 0.9 0.9]);
set(postdis,'name','posterior ditribution of VAR coefficients');
for ii=1:(q1+q2)
subplot(n,k1+m,ii)
hist(beta_swap(ii,:),20);
histproperties=findobj(gca,'Type','patch');
set(histproperties,'FaceColor',[0.7 0.78 1],'EdgeColor',[0 0 0],'LineWidth',0.1);
set(gca,'FontName','Times New Roman');
   % top labels for endogenous
   if ii<=n*p
   temp=[endo{plotvar,1} '(-' num2str(plotlag) ')'];
   title(temp,'FontWeight','normal');
      if plotlag<p
      plotlag=plotlag+1;
      elseif plotlag==p
      plotlag=1;
      plotvar=plotvar+1;
      end
   end
   % top labels for exogenous
   %if ii==k1+1
   %title('Constant','FontWeight','normal');
   %end
   %if ii>k1+1 && ii<=k1+m
   %title(exo{plotexo,1},'FontWeight','normal');
   %plotexo=plotexo+1;
   %end
   % side labels
   %if rem((ii-1)/(k1+m),1)==0
   ylabel(endo{(ii-1)/(k1+m)+1,1},'FontWeight','normal');
   %end
end
%}

% plot actual vs. fitted
actualfitted=figure;
set(actualfitted,'Color',[0.9 0.9 0.9]);
set(actualfitted,'name','model estimation: actual vs fitted')
ncolumns=ceil(n^0.5);
nrows=ceil(n/ncolumns);
for ii=1:n
subplot(nrows,ncolumns,ii)
hold on
plot(decimaldates1,Y(:,ii),'Color',[0 0 0],'LineWidth',2);
plot(decimaldates1,Ytilde(:,ii),'Color',[1 0 0],'LineWidth',2);
hold off
set(gca,'XLim',[decimaldates1(1,1) decimaldates1(end,1)],'FontName','Times New Roman');
title(endo{ii,1},'FontName','Times New Roman','FontSize',10);
   if ii==1
   plotlegend=legend('actual','fitted');
   set(plotlegend,'FontName','Times New Roman');
   end
end

% plot the residuals
residuals=figure;
set(residuals,'Color',[0.9 0.9 0.9]);
set(residuals,'name','model estimation: residuals')
for ii=1:n
subplot(nrows,ncolumns,ii)
plot(decimaldates1,EPStilde(:,ii),'Color',[0 0 0],'LineWidth',2)
set(gca,'XLim',[decimaldates1(1,1) decimaldates1(end,1)],'FontName','Times New Roman');
title(endo{ii,1},'FontName','Times New Roman','FontSize',10);
end

end

% finally, save the results on excel
bear.data.excelrecord2fcn(T, n, endo, stringdates1, Y, Ytilde, pref, EPStilde)


function test_failed = test_libltfat_ifftreal(varargin)
test_failed = 0;

fprintf(' ===============  %s ================ \n',upper(mfilename));

definput.flags.complexity={'double','single'};
[flags]=ltfatarghelper({},definput,varargin);
dataPtr = [flags.complexity, 'Ptr'];

[~,~,enuminfo]=libltfatprotofile;
phaseconv = enuminfo.ltfat_phaseconvention;

fftwflags = struct('FFTW_MEASURE',0,'FFTW_ESTIMATE',64,'FFTW_PATIENT',32,'FFTW_DESTROY_INPUT',1,...
    'FFTW_UNALIGNED',2,'FFTW_EXHAUSTIVE',8,'FFTW_PRESERVE_INPUT',16);

Larr  = [351];
Warr  = [6];

for idx = 1:numel(Larr)
    L = Larr(idx);
    W = Warr(idx);
    M2 = floor(L/2) + 1;

    f = randn(M2,W,flags.complexity) + 1i*randn(M2,W,flags.complexity);
    fi = complex2interleaved(f);
    fPtr = libpointer(dataPtr,fi);

    c = cast(randn(L,W),flags.complexity);
    coutPtr = libpointer(dataPtr,c);

    truec = ifftreal(f,L)*L;

    funname = makelibraryname('ifftreal',flags.complexity,0);
    status = calllib('libltfat',funname,fPtr,L,W,coutPtr);

    res = norm(truec - coutPtr.Value,'fro');
    [test_failed,fail]=ltfatdiditfail(res+status,test_failed);
    fprintf(['FFT   L:%3i, W:%3i, %s %s %s\n'],L,W,flags.complexity,ltfatstatusstring(status),fail);

    % With plan
    c = cast(randn(L,W),flags.complexity);
    coutPtr = libpointer(dataPtr,c);

    plan = libpointer();
    funname = makelibraryname('ifftreal_init',flags.complexity,0);
    statusInit = calllib('libltfat',funname,L,W,fPtr,coutPtr, fftwflags.FFTW_ESTIMATE, plan);

    funname = makelibraryname('ifftreal_execute',flags.complexity,0);
    statusExecute = calllib('libltfat',funname,plan);

    res = norm(truec - coutPtr.Value,'fro');
    [test_failed,fail]=ltfatdiditfail(res+statusInit,test_failed);
    fprintf(['FFT L:%3i, W:%3i, %s %s %s\n'],L,W,flags.complexity,ltfatstatusstring(status),fail);

    c = cast(randn(L,W),flags.complexity);
    coutPtr = libpointer(dataPtr,c);

    funname = makelibraryname('ifftreal_execute_newarray',flags.complexity,0);
    statusExecute = calllib('libltfat',funname,plan,fPtr,coutPtr);

    res = norm(truec - coutPtr.Value,'fro');
    [test_failed,fail]=ltfatdiditfail(res+statusInit,test_failed);
    fprintf(['FFT L:%3i, W:%3i, %s %s %s\n'],L,W,flags.complexity,ltfatstatusstring(status),fail);

    funname = makelibraryname('ifftreal_done',flags.complexity,0);
    statusDone = calllib('libltfat',funname,plan);

    %%%%%% Inplace
    c = f;
    cout = complex2interleaved(c);
    coutPtr = libpointer(dataPtr,cout);

    plan = libpointer();
    funname = makelibraryname('ifftreal_init',flags.complexity,0);
    statusInit = calllib('libltfat',funname,L,W, coutPtr, coutPtr, fftwflags.FFTW_MEASURE, plan);

    funname = makelibraryname('ifftreal_execute',flags.complexity,0);
    statusExecute = calllib('libltfat',funname,plan);

    ctmp = coutPtr.Value;
    res = norm(truec - ctmp(1:L,:),'fro');
    [test_failed,fail]=ltfatdiditfail(res+statusInit,test_failed);
    fprintf(['FFT L:%3i, W:%3i, %s %s %s\n'],L,W,flags.complexity,ltfatstatusstring(status),fail);

    c = f;
    cout = complex2interleaved(c);
    coutPtr = libpointer(dataPtr,cout);

    funname = makelibraryname('ifftreal_execute_newarray',flags.complexity,0);
    statusExecute = calllib('libltfat',funname,plan,coutPtr,coutPtr);

    ctmp = (coutPtr.Value);
    res = norm(truec - ctmp(1:L,:),'fro');
    [test_failed,fail]=ltfatdiditfail(res+statusInit,test_failed);
    fprintf(['FFT L:%3i, W:%3i, %s %s %s\n'],L,W,flags.complexity,ltfatstatusstring(status),fail);

    funname = makelibraryname('ifftreal_done',flags.complexity,0);
    statusDone = calllib('libltfat',funname,plan);
end


filename='Gripping_quad_coarse';
 ptype = 'MACRO';
method = 'SIMPALL';
materialType = 'ISOTROPIC';
initial_case = 'full';
cost = {'nonadjoint_compliance'};
weights = [1, 0.1];
constraint = {'volumeConstraint'};
constraint_case = 'INEQUALITY';
optimizer = 'MMA'; incrementFactor = 1;
filterType = 'P1';

nsteps = 1;
Vfrac_final = 0.75;
optimality_final = 1e-3;
constr_final =1e-3;

Vfrac_initial = 1;
optimality_initial = 1e-3;
constr_initial = 1e-3;
TOL.rho_plus = 1;
TOL.rho_minus = 0;
TOL.E_plus = 1;
TOL.E_minus = 1e-3;
TOL.nu_plus = 1/3;
TOL.nu_minus = 1/3;


function [seq_ids, frame_ids] = load_dataset_indexes(filename)

fid = fopen(filename, 'r');
C = textscan(fid, '%s');
indexes = C{1};
fclose(fid);

num = numel(indexes);
seq_ids = zeros(num, 1);
frame_ids = zeros(num, 1);

for i = 1:num
    str = indexes{i};
    pos = strfind(str, '/');
    seq_ids(i) = str2double(str(1:pos-1));
    frame_ids(i) = str2double(str(pos+1:end));
end


% op_B0Correction.m
% Jamie Near, McGill University 2021.
%E dits from Brenden Kadota, 2021.
%
% USAGE:
% [out, phaseMap, freqMap]=op_B0Correction(in, (optional) phaseMap);
%
% DESCRIPTION:
% Corrects for slight B0 shifts by aligning all voxels to the voxel with
% the highest water peak. (Possibly not correct output as highest peak may
% no have the correct ppm shifts)
%
% INPUTS:
% in   = MRSI struct
% phaseMap = phaseMap matrix used to apply corrections
%
% OUTPUTS:
% B0Map        = 2D array of shift intensity at each specific voxel
% phaseMap     = 2D array of phase shift intensity at each specific voxel
% freqMap      = 2D array of frequency shift intensity at each specific voxel

function [MRSIStruct, phaseMap, freqMap] = op_CSIB0Correction(MRSIStruct, phaseMap, ...
        freqMap, plottingArguments)
    arguments
        MRSIStruct (1, 1) struct
        phaseMap double = []
        freqMap double = []
        plottingArguments.isPlot = false;
    end
    %only correct if coils have be combined
    if(getFlags(MRSIStruct, 'addedrcvrs') == 0)
        error("MRSIStruct Error. Add coils first in MRSIStruct");
    end
    if(getFlags(MRSIStruct, 'spatialft') == 0)
        error("Please fourier transform along the spatial dimension");
    end
    if(getFlags(MRSIStruct, 'spectralft') == 0)
        error("Please fourier transform along the spectral dimension");
    end

    %find the coordinate of the highest intensity
    [x, y, a] = findMaxCoord(MRSIStruct);

    %create twix object from coordinate with highest intensity
    referenceMRS = op_CSItoMRS(MRSIStruct, x, y, "averageIndex", a);
    referenceMRS = setFlags(referenceMRS, 'averaged', true);
    referenceMRS.flags.isISIS = 0;

    if(~isempty(phaseMap) && ~isempty(freqMap))
        [MRSIStruct, prevPermute, prevSize] = reshapeDimensions(MRSIStruct, {'t', 'y', 'x'});
        MRSIStruct = applyFreqMap(MRSIStruct, freqMap);
        MRSIStruct = applyPhaseMap(MRSIStruct, phaseMap);
        MRSIStruct = reshapeBack(MRSIStruct, prevPermute, prevSize);

    else

        [MRSIStruct, prevPermute, prevSize] = reshapeDimensions(MRSIStruct, {'t', 'y', 'x'});

        phaseMap = zeros(getSizeFromDimensions(MRSIStruct, {'y', 'x', 'extras'}));
        freqMap = zeros(getSizeFromDimensions(MRSIStruct, {'y', 'x', 'extras'}));

        data = getData(MRSIStruct);
        for e = 1:getSizeFromDimensions(MRSIStruct, {'extras'})
            for y = 1:getSizeFromDimensions(MRSIStruct, {'y'})
                for x = 1:getSizeFromDimensions(MRSIStruct, {'x'})
                    %get twix object at x and y coordinate
                    alignMRS = op_CSItoMRS(MRSIStruct, x, y, 'Extra', e);
                    alignMRS = setFlags(alignMRS, 'averaged', true);
                    alignMRS.flags.isISIS = 0;
                    %aligns twix object to the maximum intensity twix object
                    [alignMRS, phase, freq] = op_alignScans(alignMRS, referenceMRS, referenceMRS.t(end));

                    timeDimension = getDimension(alignMRS, 't');
                    %adds the aligned twix to the specs of MRSI object.
                    data(:, y, x, e) = flip(alignMRS.specs, timeDimension);
                    %add phase and frequency to maps
                    phaseMap(y, x, e) = phase;
                    freqMap(y, x, e) = freq;
                end
            end
        end
        MRSIStruct = setData(MRSIStruct, data);
        MRSIStruct = reshapeBack(MRSIStruct, prevPermute, prevSize);

        %plot maps
        if(plottingArguments.isPlot)
            plotFreqAndPhaseMap(phaseMap, MRSIStruct, freqMap);
        end
        MRSIStruct = setFlags(MRSIStruct, 'phasecorrected', 1);
        MRSIStruct = setFlags(MRSIStruct, 'freqcorrected', 1);
    end
end

%finds the (x,y) coordinate with the highest intensity spectrum.
function [x,y,a] = findMaxCoord(in)
    [~, i] = max(getData(in),[], 'all', 'linear');
    out = cell(size(in.sz));
    [out{:}] = ind2sub(in.sz, i);
    x = out{in.dims.x};
    y = out{in.dims.y};
    if(in.dims.averages)
        a = out{in.dims.averages};
    else
        a = 1;
    end

end

function plotFreqAndPhaseMap(phaseMap, MRSIStruct, freqMap)
    for i = 1:size(phaseMap,3)
        figure;
        subplot(2,1,1);
        imagesc(MRSIStruct.coordinates.x, MRSIStruct.coordinates.y, phaseMap(:,:,i)')
        title("phaseMap")
        subplot(2,1,2);
        imagesc(MRSIStruct.coordinates.x, MRSIStruct.coordinates.y, freqMap(:,:,i)')
        title("freqMap")
    end
end

function MRSIStruct = applyFreqMap(MRSIStruct, freqMap)
    %applying the freqMap map if added as an argument
    for e = 1:getSizeFromDimensions(MRSIStruct, {'extras'})
        for x = 1:getSizeFromDimensions(MRSIStruct, {'x'})
            for y = 1:getSizeFromDimensions(MRSIStruct, {'y'})
                %create twix object from the coordinates
                alignMRS = op_CSItoMRS(MRSIStruct, x, y, 'extraIndex', e);
                %align twix object with op_freqshift to the equivalent
                %freqmap coordinate.
                alignMRS = op_freqshift(alignMRS, freqMap(x, y));
                %add the specs to MRSI object
                MRSIStruct.data(:, x, y, e) = alignMRS.specs;
            end
        end
    end
end

function MRSIStruct = applyPhaseMap(MRSIStruct, phaseMap)
    %applying the freqMap map if added as an argument
    for e = 1:getSizeFromDimensions(MRSIStruct, {'extras'})
        for x = 1:getSizeFromDimensions(MRSIStruct, {'x'})
            for y = 1:getSizeFromDimensions(MRSIStruct, {'y'})
                %create twix object from the coordinates
                alignMRS = op_CSItoMRS(MRSIStruct, x, y, 'extraIndex', e);
                %align twix object with op_freqshift to the equivalent
                %freqmap coordinate.
                alignMRS = op_addphase(alignMRS, phaseMap(x, y));
                %add the specs to MRSI object
                MRSIStruct.data(:, x, y, e) = alignMRS.specs;
            end
        end
    end
end


if 0
    load('ecoli_core_model.mat');
    %objective
    model.biomassRxnAbbr='Biomass_Ecoli_core_N(w/GAM)-Nmet2';
    model = changeObjective(model,model.biomassRxnAbbr,1);
    osenseStr = 'max';
    model.osenseStr = osenseStr;

    if ~isfield(model,'SConsistentRxnBool')  || ~isfield(model,'SConsistentMetBool')
        massBalanceCheck=1;
        printLevel=2;
        [SConsistentMetBool, SConsistentRxnBool, SInConsistentMetBool, SInConsistentRxnBool, unknownSConsistencyMetBool, unknownSConsistencyRxnBool, model]...
            = findStoichConsistentSubset(model, massBalanceCheck, printLevel);
    end
else
    modelToLoad='circularToy';
    modelToLoad='ecoli_core';
    modelToLoad='modelRecon3MitoOpen';
    modelToLoad='Recon3DModel';
    driver_thermoModelLoad
end

param.fbaOptimal = 1;
param.printLevel = 1;

[nMet,nRxn]=size(model.S);
nIntRxn = nnz(model.SConsistentRxnBool);

%compute a normalised random vector of conductances
q1=rand(nIntRxn,1);
q1 = q1/sum(q1);

%compute a thermodynamically feasible flux vector using randomBoundThermoFeasible
model.q=q1;
[model, vRandThermo,yRandThermo, qRandThermo] = randomBoundThermoFeasible(model,param);
v = vRandThermo(model.SConsistentRxnBool);
g1 = model.S(:,model.SConsistentRxnBool)'*yRandThermo;

model = rmfield(model,'q');

% %compute a thermodynamically feasible flux vector using thermoQP
% sol = thermoQP(model,qRandThermo,param.printLevel);
% vRandThermo = sol.v;
% yRandThermo = sol.y;

solutionThermo.v = vRandThermo;
[qRecovered,gRecovered] = thermoFlux2QNty(model,solutionThermo,param);
q3 = qRecovered(model.SConsistentRxnBool);
g3 = gRecovered(model.SConsistentRxnBool);

rxns=model.rxns(model.SConsistentRxnBool);

%compare the initial and recovered q and g
T=table(rxns,v,q1,q3,g1,g3);

feasTol = getCobraSolverParams('LP', 'feasTol');
param.eta = feasTol*10;
g1(abs(g1)<param.eta)=0;
g3(abs(g1)<param.eta)=0;
nDifferentSigns = nnz(sign(g1)~=sign(g3));
assert(nDifferentSigns==0)


function stim = rmJitterImages(stim, params)
% Offset a retinotopic mapping stimulus to compensate for eye position.
%
%   stim = rmJitterImages(stim, params)
%
% The eye movements are read from a file in stim.jitterFile. This file
% contains two variables, x and y, that indicate the x and y positions of
% the jitter across temporal samples. The number of time samples in the eye
% position must much the number of volume acquisitions (TRs), which are
% ordinarily matched to the number of stimulus frames.
%
% Eye movement position is encoded in visual angle, with one (x, y)
% coordinate pair per stimulus frame (or TR).
%
% 12/2008: JW
%
% When describing the stimulus in the vista UI (Analsysis || Retinotopic
% Model || Set Parameters), any matlab file located in the directory
% 'Stimuli' and containing the string 'jitter' in the name will be
% available in the drop down menu for image jitter.
%
% An example of building a jitter file:
%   A scan had 96 frames + 5 pre-scan (removed) frames.
%   The subject fixated 3 deg to the right and above fixation for the
%   entire scan.
%
%   nFrames = 101;
%   deg = 3;
%   x = ones(1, nFrames) * deg;
%   y = ones(1, nFrames) * deg;
%   save Stimuli/jitter3deg101frames x y;
%
% Example to simulate random eye movements with a standard deviation of 1
% deg:
%
%

%% If no eye movement data, return without doing anything
if ~checkfields(stim, 'jitterFile'), return; end
[p, n, e] = fileparts(stim.jitterFile);
if strcmpi(n,'none'), return; end  % A filename of None returns

%% Build jittered images

% Parse eye eyePosition data
[x, y] = parseEyePositionData(stim);

% Get stimulus mesh grid in visual angle
[m n step] = prfSamplingGrid(params);
nrows = size(m,1); ncols = size(m, 2);

% Convert eye positions from degrees to pixels
%   Note that x must be negated, since a positive shift in x means a
%   rightward eye position (and hence a leftward shift in the image),
%   and leftward image shifts are represented by negative numbers. But
%   y is not negated, since a positive shift in y means an upward eye
%   movement (and hence a downward shift in the image), and downward
%   image shifts are represented by positive numbers.
x = -round(x / step);
y = round(y / step);

% Initialize an image of the correct 2D dimenstions
im = zeros(size(m));
inStimWindow = params.stim(1).instimwindow;

% Jitter stimulus frame-by-frame to compensate for eye position
for f = 1:stim.nFrames
    % Reshape image from 1D to 2D
    im(inStimWindow) = stim.images(:, f);

    % Jitter in opp direction to eye movement

    imShifted = zeros(size(im));

    % We can shift in 4 possible ways:
    if x(f) >= 0
        xShifted = 1:ncols-x(f); xUnshifted =  x(f)+1:ncols;
    else
        xShifted = -x(f)+1:ncols; xUnshifted =  1:ncols+x(f);
    end

    if y(f) >= 0
        yShifted = 1:nrows-y(f); yUnshifted =  y(f)+1:nrows;
    else
        yShifted = -y(f)+1:nrows; yUnshifted =  1:nrows+y(f);
    end

    imShifted(yShifted, xShifted) = im(yUnshifted, xUnshifted);

    % Reshape from 2D to 1D
    stim.images(:, f) = imShifted(inStimWindow);
end

% --------------------------------------------------------------
%% test (un-comment to view jittered images as they are created)
% im = zeros(size(m));
% range = mrvMinmax(stim.images(:));
% for f = 1:stim.nFrames
%     % reshape image from 1D to 2D
%     im(inStimWindow) = stim.images(:, f);
%     figure(99);
%     imagesc(im, range);
%     axis image off;
%     pause(0.05)
% end
%---------------------------------------------------------------

return

function [x, y] = parseEyePositionData(stim)
% Read the stimulated eye positions

if ischar(stim.jitterFile)
    tmp = load(stim.jitterFile);
    x = tmp.x; y = tmp.y;
end

if length(x) ~= length(y), error('x/y eye positions not matched'); end

nFrames = size(stim.images,2);
if length(x) < nFrames
    error('Eye movement length (%d) less than nFrames (%d)\n',length(x),nFrames);
elseif length(x) > nFrames
    fprintf('Eye movement length (%d) too long. Truncating to (%d).\n',length(x),nFrames);
    x = x(1:nFrames);
    y = y(1:nFrames);
end

return;


%AOK TFR 2.0
%Deming Zhang
%deming.zhang@gmail.com
%

function varargout = tfagui(varargin)

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @TFA_OpeningFcn, ...
                   'gui_OutputFcn',  @TFA_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin & isstr(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

% --- Executes just before TFA is made visible.
function TFA_OpeningFcn(hObject, eventdata, handles, varargin)
% Choose default command line output for TFA
vars = evalin('base','who');
set(handles.listbox_var,'String',vars);

handles.fs=1;
handles.lag=32;
handles.fftlen=512;
handles.tstep=1;
handles.vol=2;
handles.sig=[];
handles.tfr=[];
handles.t=[];
handles.f=[];
handles.begin=1;
handles.end=1;
handles.res=1;
handles.color=JET;
handles.times=6;
handles.vmanner=1;%linear
handles.realf=1;
%Ridges
handles.ci=[];
handles.ri=[];

handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
set(gcf,'Color',[1 1 1]);

% UIWAIT makes TFA wait for user response (see UIRESUME)
% uiwait(handles.figure1);

% --- Outputs from this function are returned to the command line.
function varargout = TFA_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;

% --- Executes on slider movement.
function slider_vol_Callback(hObject, eventdata, handles)
h=get(hObject);
handles.vol=h.Value;
handles.output = hObject;
guidata(hObject, handles);

% --- Executes on selection change in listbox_color.
function listbox_color_Callback(hObject, eventdata, handles)
h=get(hObject);
list_entries = get(hObject,'String');
index_selected = get(hObject,'Value');
str = list_entries{index_selected};
handles.color=str2num(str);
handles.output = hObject;
guidata(hObject, handles);
colormap(handles.color);

% --- Executes on button press in pushbutton_apply.
function pushbutton_apply_Callback(hObject, eventdata, handles)
s=handles.sig;
if imag(s)==0,      s=[s imag(hilbert(s))];
else                s=[real(s) imag(s)];end
s=s(handles.begin:handles.end,:);
res=handles.res;
if res>1,    s=resample(s,10,round(res*10));
elseif res>0 & res~=1,    s=resample(s,10,round(10*res));end
%slen=handles.slen;
slen=length(s);
fs=handles.fs;
lag=handles.lag;
fftlen=handles.fftlen;
tstep=handles.tstep;
vol=handles.vol;

fid = fopen('signal','w');
fprintf(fid,'%d %d %d %d %f\n',slen,lag,fftlen,tstep,vol);
fprintf(fid,'%f %f\n',s');
fclose(fid);
tic
!ATFR.exe signal >NUL
toc
Nt=floor((slen+lag-1)/tstep+1);
fid=fopen('TFR','rb');
TFR=fread(fid,[fftlen,Nt],'double');
fclose(fid);
!del TFR signal >NUL

t=linspace(0,(slen-1)/fs,slen);
f=linspace(-fs*(0.5-1/fftlen),fs*(0.5-1/fftlen),fftlen);

suffix=round(lag/(2*tstep));
TFR=TFR(:,suffix+1:Nt-suffix);
TFR=[TFR(1+fftlen/2:end,:);TFR(1:fftlen/2,:)];

handles.t=t;
handles.f=f;
%save 'd:\tfr.mat' TFR;
handles.tfr=TFR;

updateAOK(handles);

axes(handles.ax_pow);
p=( abs(fftshift(fft(s(:,1)+i*s(:,2)))) );

plot(p,linspace(f(1),f(end),length(p)));
if handles.realf==0,
axis([min(p)-1,max(p)+1,f(1),f(end)]);ylabel('Frequency(Hz)');title('Spectrum');
else axis([min(p)-1,max(p)+1,0,f(end)]);ylabel('Frequency(Hz)');title('Spectrum');
end
axes(handles.ax_wav);
ts=0:slen/(fs*(slen-1)):slen/fs;
if handles.realf==0,
plot(ts,s);axis tight;ylabel('WaveForm');
else plot(ts,s(:,1));axis tight;ylabel('WaveForm');
end
handles.output = hObject;
guidata(hObject, handles);

function edit_lag_Callback(hObject, eventdata, handles)
h=get(hObject);
handles.lag=str2num(h.String);
handles.output = hObject;
guidata(hObject, handles);

function edit_step_Callback(hObject, eventdata, handles)
h=get(hObject);
handles.tstep=str2num(h.String);
handles.output = hObject;
guidata(hObject, handles);

function edit_fft_Callback(hObject, eventdata, handles)
h=get(hObject);
handles.fftlen=str2num(h.String);
handles.output = hObject;
guidata(hObject, handles);

% --- Executes on selection change in listbox_manner.
function listbox_manner_Callback(hObject, eventdata, handles)
h=get(hObject);
handles.vmanner=h.Value;
handles.output = hObject;
guidata(hObject, handles);
updateAOK(handles);
% --------------------------------------------------------------------

% --- Executes on selection change in listbox_var.
function listbox_var_Callback(hObject, eventdata, handles)
sig=get_var_names(handles);
sig=sig(:);
handles.sig=sig;
handles.slen=length(sig);
handles.begin=1;
handles.end=handles.slen;
set(handles.edit_b,'String',num2str(handles.begin));
set(handles.edit_e,'String',num2str(handles.end));

if imag(sig)==0,
    axes(handles.ax_wav);
    plot([0:length(sig)-1]/handles.fs,sig);axis tight;ylabel('WaveForm');
    axes(handles.ax_pow);
    p=( abs(fftshift(fft(sig))) );
    plot(p(length(p)/2+1:end),linspace(0,0.5*handles.fs,length(p)/2));
else
    axes(handles.ax_wav);
    plot([0:length(sig)-1]/handles.fs,[real(sig) imag(sig)]);axis tight;ylabel('WaveForm');
    axes(handles.ax_pow);
    p=( abs(fftshift(fft(sig))) );
    plot(p,linspace(-0.5*handles.fs,0.5*handles.fs,length(p)));
end

handles.output = hObject;
guidata(hObject, handles);

function sig = get_var_names(handles)
list_entries = get(handles.listbox_var,'String');
index_selected = get(handles.listbox_var,'Value');
sig = list_entries{index_selected(1)};
sig=evalin('base',sig);

% --- Executes on button press in pushbutton_update.
function pushbutton_update_Callback(hObject, eventdata, handles)
vars = evalin('base','who');
set(handles.listbox_var,'String',vars);

% --- Executes during object creation, after setting all properties.

function edit_fs_Callback(hObject, eventdata, handles)
h=get(hObject);
handles.fs=str2num(h.String);
handles.output = hObject;
guidata(hObject, handles);

function updateAOK(handles)
t=handles.t;
f=handles.f;
if handles.realf==1,
    len=ceil(length(f)/2);
    tfr=handles.tfr(len:end,:);
    f=f(len:end);
else
    tfr=handles.tfr;
end
pt=0.005*2^handles.times;
if handles.vmanner==1,
    tfr=tfr.^pt;
else
    tfr=10*log10(tfr.^pt);
end
axes(handles.ax_aok);imagesc(t,f,tfr);xlabel('Time(s)');axis xy;ylabel('Frequency(Hz)');title('Time Frequency Representation');
%axes(handles.ax_aok);imagesc(t,f,tfr);xlabel('Time(s)');axis xy;ylabel('Frequency(Hz)');title('AOK Time-Frequency Representation');

% --- Executes on slider movement.
function slider_times_Callback(hObject, eventdata, handles)
h=get(hObject);
handles.times=h.Value;
updateAOK(handles);
handles.output = hObject;
guidata(hObject, handles);

% --- Executes on slider movement.
function edit_res_Callback(hObject, eventdata, handles)
h=get(hObject);
handles.res=str2num(h.String);
handles.output = hObject;
guidata(hObject, handles);

% --- Executes on slider movement.
function edit_b_Callback(hObject, eventdata, handles)
h=get(hObject);
handles.begin=str2num(h.String);
handles.output = hObject;
guidata(hObject, handles);
% --- Executes on slider movement.
function edit_e_Callback(hObject, eventdata, handles)
h=get(hObject);
handles.end=str2num(h.String);
handles.output = hObject;
guidata(hObject, handles);

function edit_cmd_Callback(hObject, eventdata, handles)
% hObject    handle to edit_cmd (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of edit_cmd as text
%        str2double(get(hObject,'String')) returns contents of edit_cmd as a double
evalin('base',get(hObject,'String'));
set(hObject,'String','');
vars = evalin('base','who');
set(handles.listbox_var,'String',vars);

function axis_wav_Callback(hObject, eventdata, handles)
set(handles.edit_b,'String',num2str(handles.begin));
set(handles.edit_e,'String',num2str(handles.end));
handles.output = hObject;
guidata(hObject, handles);

% --- Executes on button press in pushbutton3.
function pushbutton3_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton3 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
[ri,ci]=ridges(handles.tfr,12);
ri=handles.f(ri);
ci=handles.t(ci);
axes(handles.ax_aok);hold on;plot(ci,ri,'r.');hold off;
handles.ri=ri;handles.ci=ci;
handles.output = hObject;
guidata(hObject, handles);

function [ri,ci] = ridges(m,par)
 if nargin < 2,    par=3;  end;
 m = abs(m);
 [nrows,ncols] = size(m);
 ridges   = zeros(size(m));
 t      = 1:nrows;
 tplus  =[nrows 1:nrows-1 ];% rshift(t);
 tminus =[2:nrows 1];% lshift(t);
for i = 1:ncols,
 	x = m(:,i)';
    for j = 1:par,
		x=max([x(t); x(tplus); x(tminus)]);
    end;
	x = x(:);
	thresh = trimmean(x,5);
    ridges(:,i) = (~(m(:,i)<x)).*(m(:,i)>0.01*thresh);
 end;
 [ri,ci]=find(ridges>0);

% --- Executes on button press in pushbutton_load.
function pushbutton_load_Callback(hObject, eventdata, handles)
[fn, pn]=uigetfile('*.*', 'Mat or Ascii File to Load:');
if fn==0, return; end;
evalin('base', ['load(''' pn fn ''');']);
vars = evalin('base','who');
set(handles.listbox_var,'String',vars);

% --- Executes on button press in checkbox_real.
function checkbox_real_Callback(hObject, eventdata, handles)
% hObject    handle to checkbox_real (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
h=get(hObject);
handles.realf=h.Value;
handles.output = hObject;
guidata(hObject, handles);

% Hint: get(hObject,'Value') returns toggle state of checkbox_real


function [eddy] = thresholdBU(cyc, block_bottom_index, block_top_index, block_left_index, block_right_index, ...
        ssh, extrema, extrema_lat_index, extrema_lon_index, thresh, threshold_step, last_step, previous, ...
        lat, lon, R, areamap, min_pixel_size, is_padding, cyc_ssh)
% THRESHOLDBU Get an eddy by bottom up method
%   cyc: 1 for anticyclonic and -1 for cyclonic
%   block_bottom(top/left/right)_index: index of the bottom/top/left/right of the block that will be used for
%   thresholding
%   ssh: ssh data(extended if is_padding is true)
%   extrema: logical index of ssh extrema
%   extrema_lat/lon_index: lat/lon index of the extremum that is being used to find an eddy
%   thresh: current threshold that is being used to find an eddy
%   threshold_step: the step to increase/decrease threshold value, based on eddy type
%   last_step: the last step was used for thresholding
%   previous: 2d logical array of the connected component that contains the extremum in the last thresholdBU call
%   lat: 1d array of latitudes of the ssh grid
%   lon: 1d array of longitudes of the ssh grid
%   R: the georasterref object for SSH grid
%   areamap: 1D or 2D array of reference to area of each pixel in SSH grid
%   min_pixel_size: minimum number of pixels for an eddy
%   is_padding: whether or not the SSH data is padded

    switch cyc
        case 1
            intensity = 'MaxIntensity';
        case -1
            intensity = 'MinIntensity';
        otherwise
            error('Invalid cyc');
    end

    if block_bottom_index < 1 || block_top_index > size(ssh, 1) || ...
            block_left_index < 1 || block_right_index > size(ssh, 2)
        edgeOfWorld = true;

        while block_bottom_index < 1 || block_top_index > size(ssh, 1) || ...
            block_left_index < 1 || block_right_index > size(ssh, 2)
            % Make sure that the block is inside the grid

            block_bottom_index = block_bottom_index + 1;
            block_top_index = block_top_index - 1;
            block_left_index = block_left_index + 1;
            block_right_index = block_right_index - 1;
            if block_top_index <= block_bottom_index + 2 || block_right_index <= block_left_index + 2
                % If the block is too small, just return an empty eddy
                eddy = new_eddy();
                return;
            end
        end

        block = ssh(block_bottom_index:block_top_index, block_left_index:block_right_index);

        extremaBlock = extrema(block_bottom_index:block_top_index, block_left_index:block_right_index);

    else
        edgeOfWorld = false;
        block = ssh(block_bottom_index:block_top_index, block_left_index:block_right_index);
        extremaBlock = extrema(block_bottom_index:block_top_index, block_left_index:block_right_index);
    end

    if isnan(last_step)
        step = threshold_step;
    else
        step = last_step;
    end

    iter = 1;
    while true
        iter = iter+1;
        if iter > 5000

            perim = imdilate(logical(current), ones(3)) & ~logical(current);
            if all(isnan(block(perim)))
                eddy = new_eddy();
                return;
            end
            disp('potential infinite loop')
        end

        bw = cyc .* block >= cyc .* thresh;
        labels = bwlabel(bw);

        extrema_label = labels(extrema_lat_index - block_bottom_index + 1, extrema_lon_index - block_left_index + 1);
        current = labels == extrema_label;
        currentExtrema = extremaBlock(current);

        existing_pixel_at_box_edge = outterRing(labels, extrema_label);

        if sum(currentExtrema) > 1 || ( edgeOfWorld && existing_pixel_at_box_edge)

            if step ~= threshold_step
                % Go back to last threshold
                thresh = thresh + cyc*step;
                step = threshold_step;
                thresh = thresh - cyc*step;
                continue;
            end

            if size(block, 1) ~= size(previous(block_bottom_index:block_top_index, block_left_index:block_right_index), 1)
                prevBlock = block(2:end-1, 2:end-1);
            else
                prevBlock = block;
            end

            perim = imdilate(logical(previous(block_bottom_index:block_top_index, block_left_index:block_right_index)), ones(3)) ...
                & ~logical(previous(block_bottom_index:block_top_index, block_left_index:block_right_index));
            nan = isnan(prevBlock(perim));
            if sum(nan) / length(nan) > .3
                %if more than half of your perimeter is land, then throw it out.
                eddy = new_eddy();
                return;
            end

            if sum(previous(:)) < min_pixel_size
                    eddy = new_eddy();
                    return;
            end

            perim = bwperim(previous);
            meanPerim = mean(ssh(logical(perim)));
            amp = cyc * (ssh(extrema_lat_index, extrema_lon_index)-meanPerim);

            stats = regionprops(previous, ssh, 'Area', 'Extrema',...
                'PixelIdxList', intensity, 'ConvexImage', 'PixelList', ...
                'Solidity', 'Extent', 'Orientation', 'MajorAxisLength', ...
                'MinorAxisLength');

            stats.Intensity = stats.(intensity);
            stats = rmfield(stats, intensity);

            if is_padding
                [idx, r, c] = extidx2original(stats.PixelIdxList, [length(lat) length(lon)], size(ssh));
                stats.PixelIdxList = idx;
            else
                [r, c] = ind2sub(size(ssh), stats.PixelIdxList);
            end

            stats.PixelList = [r, c];

            % Getting geodesic speed
            if is_padding
                geoSpeed = mean_geo_speed(ssh(:, 201:end-200), stats.PixelIdxList, lat, lon);
                if ~isempty(R)
                    [elat, elon] = weighted_centroid(cyc_ssh(:, 201:end-200), stats.PixelList, stats.PixelIdxList, R);
                else
                    [elat, elon] = weighted_centroid_irregular_grid(cyc_ssh(:, 201:end-200), stats.PixelList, stats.PixelIdxList, lat, lon);
                end
            else
                geoSpeed = mean_geo_speed(ssh, stats.PixelIdxList, lat, lon);
                if ~isempty(R)
                    [elat, elon] = weighted_centroid(cyc_ssh, stats.PixelList, stats.PixelIdxList, R);
                else
                    [elat, elon] = weighted_centroid_irregular_grid(cyc_ssh, stats.PixelList, stats.PixelIdxList, lat, lon);
                end
            end

            % weighted_centroid returns lon from 0-360, fix this
            % TODO: should we also fix lat lon -270 to 80?
            elon = (elon > 180).*(elon - 360) + (elon <= 180).*elon;

            % Getting surface area of the eddy
            if all(size(areamap) == [length(lat) length(lon)])
                % area is 2D array for areas of pixels at [lat, lon]
                sarea = sum(areamap(stats.PixelIdxList));
            elseif any(size(areamap) == [1 1]) && length(areamap) == length(lat)
                % Area is 1D array for areas of pixels at a specific latitude
                sarea = sum(areamap(stats.PixelList(:, 1)));
            else
                % Invalid areamap
                sarea = NaN;
            end

            eddy = new_eddy(rmfield(stats, 'PixelList'), amp, elat, elon, thresh, sarea, cyc, geoSpeed, 'ESv2');

            return
        end

        if existing_pixel_at_box_edge
            %disp('expanding size');
            eddy = thresholdBU(cyc, block_bottom_index-1, block_top_index+1, block_left_index-1,...
                block_right_index+1, ssh, extrema, extrema_lat_index, extrema_lon_index, thresh, threshold_step, ...
                step, previous, lat, lon, R, areamap, min_pixel_size, ...
                is_padding, cyc_ssh);
            return
        end

        previous(block_bottom_index:block_top_index, block_left_index:block_right_index) = current;

        step = step * 2; % double the step for less number of iterations
        thresh = thresh - cyc*step;
    end

end

function [res] = outterRing(box, val)
    ring = [box(1, 1:end)'; box(end, 1:end)'; box(1:end, 1); box(1:end, end)];
    res = any(ring == val);
end


function res = randomSol(model)
    res = randperm(model.city+model.veh-1);
end