function [Gamma,Gammasum,Xi,LL] = hsinference_batched(T,hmm,residuals,XX)

N = length(T);
K = hmm.K;

setstateoptions;
rangeK = 1:K;
ndim = size(residuals,2);

% Cache shared results for use in obslike
for k = rangeK
    hmm.cache.train{k} = train;
    if k == 1 && strcmp(train.covtype,'uniquediag') || strcmp(train.covtype,'shareddiag')
        ldetWishB = 0;
        PsiWish_alphasum = 0;
        for n = 1:ndim
            if ~regressed(n), continue; end
            ldetWishB = ldetWishB+0.5*log(hmm.Omega.Gam_rate(n));
            PsiWish_alphasum = PsiWish_alphasum+0.5*psi(hmm.Omega.Gam_shape);
        end
        C = hmm.Omega.Gam_shape ./ hmm.Omega.Gam_rate;
    elseif k == 1 && strcmp(train.covtype,'uniquefull') || strcmp(train.covtype,'sharedfull')
        ldetWishB = 0.5*logdet(hmm.Omega.Gam_rate(regressed,regressed));
        PsiWish_alphasum = 0;
        for n = 1:sum(regressed)
            PsiWish_alphasum = PsiWish_alphasum+psi(hmm.Omega.Gam_shape/2+0.5-n/2);
        end
        PsiWish_alphasum=PsiWish_alphasum*0.5;
        C = hmm.Omega.Gam_shape * hmm.Omega.Gam_irate;
        for kk = rangeK
            [hmm.cache.WishTrace{kk},hmm.cache.codevals] = computeWishTrace(hmm,regressed,XX,C,kk);
        end
    elseif strcmp(train.covtype,'diag')
        ldetWishB=0;
        PsiWish_alphasum = 0;
        for n = 1:ndim
            if ~regressed(n), continue; end
            ldetWishB = ldetWishB+0.5*log(hmm.state(k).Omega.Gam_rate(n));
            PsiWish_alphasum = PsiWish_alphasum+0.5*psi(hmm.state(k).Omega.Gam_shape);
        end
        C = hmm.state(k).Omega.Gam_shape ./ hmm.state(k).Omega.Gam_rate;
        if episodic, iC = hmm.state(k).Omega.Gam_rate / hmm.state(k).Omega.Gam_shape; end
    elseif strcmp(train.covtype,'full')
        ldetWishB = 0.5*logdet(hmm.state(k).Omega.Gam_rate(regressed,regressed));
        PsiWish_alphasum = 0;
        for n = 1:sum(regressed)
            PsiWish_alphasum = PsiWish_alphasum+0.5*psi(hmm.state(k).Omega.Gam_shape/2+0.5-n/2);
        end
        C = hmm.state(k).Omega.Gam_shape * hmm.state(k).Omega.Gam_irate;
        if episodic, iC = hmm.state(k).Omega.Gam_rate / hmm.state(k).Omega.Gam_shape; end
        [hmm.cache.WishTrace{k},hmm.cache.codevals] = computeWishTrace(hmm,regressed,XX,C,k);
    end
    % Set up cache
    if ~isfield(train,'distribution') || strcmp(train.distribution,'Gaussian')
        hmm.cache.ldetWishB{k} = ldetWishB;
        hmm.cache.PsiWish_alphasum{k} = PsiWish_alphasum;
        hmm.cache.C{k} = C;
    end
end

Gamma = cell(N,1);
LL = cell(N,1);
Xi = cell(N,1);

for j = 1:N

    t0 = sum(T(1:j-1)) - order*(j-1);
    if order > 0
        R = [zeros(order,size(residuals,2)); residuals(t0+1:t0+T(j)-order,:)];
    else
        R = residuals(t0+1:t0+T(j),:);
    end

    Tj = size(R,1);

    L = obslike([],hmm,residuals,XX,hmm.cache);
    L(L<realmin) = realmin;
    L(L>realmax) = realmax;
    L = embeddata_batched(L,Tj,hmm.train.embeddedlags_batched);
    L = permute(mean(L,2),[1,3,2]);

    [Gamma{j},Xij,LL{j}] = fb_Gamma_inference_sub(L,hmm.P,hmm.Pi,size(L,1),order);

    Xi{j} = reshape(Xij,size(Xij,1),K,K);

end

Gamma = cell2mat(Gamma);
Xi = cell2mat(Xi);
LL = cell2mat(LL);
Gammasum = sum(Gamma);

end


function [globalOpt, options, optionsDyn, initXOptions] = ...
    hsvargplvmRegressionInitX(globalOpt, options, optionsDyn, inpX, Ytr, stackedOpt)

if nargin < 6 || isempty(stackedOpt)
    stackedOpt = [];
end

% ---- Potential special initialisations for X -----
if ~iscell(globalOpt.initX) && strcmp(globalOpt.initX, 'inputs')
    options = rmfield(options, 'initX');
    for i=1:options.H
        options.initX{i} = inpX;
    end
    optionsDyn.initX = inpX;
    globalOpt.initX = options.initX;
end

% Initialise half of the latent spaces with inputs, half with PCA on outputs
if ~iscell(globalOpt.initX) && strcmp(globalOpt.initX, 'inputsOutputs')
    options = rmfield(options, 'initX');
    if iscell(globalOpt.Q)
        oldQ = globalOpt.Q{end};
    else
        oldQ = globalOpt.Q;
    end
    for i=options.H:-1:floor(options.H/2)+1
        options.initX{i} = inpX;
        Q{i} = size(inpX,2);
    end
    optionsDyn.initX = inpX;

    YtrScaled = scaleData(Ytr{1}, options.scale2var1);
    Xpca  = ppcaEmbed(YtrScaled, oldQ);
    for i=1:floor(options.H/2)
        options.initX{i} = Xpca;
        Q{i} = oldQ;
    end
    options.Q = Q;
    globalOpt.Q = Q;
    globalOpt.initX = options.initX;
end

% Just rewrite all options into a struct of cells
optionsAll = hsvargplvmCreateOptions(Ytr, options, globalOpt);
% Don't mind the following for loop... it just gives the extra possibility
% of initialising the latent space with Bayesian GPLVM or GPLVM (see
% hsvargplvm_init on how to activate this).
initXOptions = cell(1, options.H);
for h=1:options.H
    if strcmp(optionsAll.initX, 'vargplvm') | strcmp(optionsAll.initX, 'fgplvm')
        initXOptions{h}{1} = optionsAll;
        % DOn't allow the D >> N trick for layers > 1
        if h~=1
            if isfield(initXOptions{h}{1}, 'enableDgtN')
                initXOptions{h}{1}.enableDgtN = false;
            end
        end
        initXOptions{h}{1}.latentDim = optionsAll.Q{h};
        initXOptions{h}{1}.numActive = optionsAll.K{h}{1};
        initXOptions{h}{1}.kern = optionsAll.kern{h}{1};
        initXOptions{h}{1}.initX = 'ppca';
        initXOptions{h}{1}.initSNR = 90;
        initXOptions{h}{1}.numActive = 50;
        initXOptions{h}{2} = 160;
        initXOptions{h}{3} = 30;
        if isfield(stackedOpt, 'stackedInitVardistIters'),  initXOptions{h}{2} = stackedOpt.stackedInitVardistIters;   end
        if isfield(stackedOpt, 'stackedInitIters'), initXOptions{h}{3} = stackedOpt.stackedInitIters;   end
        if isfield(stackedOpt, 'stackedInitSNR'), initXOptions{h}{1}.initSNR = stackedOpt.stackedInitSNR; end
        if isfield(stackedOpt, 'stackedInitK'), initXOptions{h}{1}.numActive = stackedOpt.stackedInitK; end
    else
        initXOptions{h} = {};
    end
end


function h = rgb2hsv(m)

% RGB2HSV converts red-green-blue colors to hue-saturation-value.
%
% this code is based on the comments in
% http://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both

if isvector(m) && length(m)==3
  r = m(1);
  g = m(2);
  b = m(3);
elseif ismatrix(m) && size(m,2)==3
  r = m(:,1);
  g = m(:,2);
  b = m(:,3);
elseif ndims(m)==3
  r = m(:,:,1);
  g = m(:,:,2);
  b = m(:,:,3);
end

% ensure these to be double precision column vectors
r = double(r(:));
g = double(g(:));
b = double(b(:));

minrgb = min([r g b], [], 2);
maxrgb = max([r g b], [], 2);
delta  = maxrgb - minrgb;

h = nan(size(delta)); % will be determined further down
v = maxrgb;
s = delta./maxrgb;

% set for each element in the array the proper hue, depending on whether red, green or blue is the largest value
% the 0, 2 and 4 are there to end up in the right corner of the color circle
sel = (r==maxrgb);
hue = 0.0 + (g-b)./delta; % between yellow & magenta
h(sel) = hue(sel);
sel = (g==maxrgb);
hue = 2.0 + (b-r)./delta; % between cyan & yellow
h(sel) = hue(sel);
sel = (b==maxrgb);
hue = 4.0 + (r-g)./delta; % between magenta & cyan
h(sel) = hue(sel);

% these should not be NaN
h(delta==0) = 0;
s(delta==0) = 0;

% convert to degrees between 0 and 360
h = h * 60;
h = mod(h, 360);

% convert to a fraction between 0 and 1
h = h/360;

if nargout==3
  % return the three output arguments separately
else
  % combine the hue-saturation-value in a single array
  h = reshape([h(:) s(:) v(:)], size(m));
  clear s v
end


classdef ShFunWithElasticPdes < ShapeFunctional

    properties (Access = protected)
        interpolation
        physicalProblem
    end

    properties (Access = private)
        orientationUpdater
        alpha
    end

    properties (Access = public)
        regDesignVariable
    end

    methods (Access = public)

        function computeFunctionAndGradient(obj)
            obj.updateAlpha();
            obj.computeFunction();
            obj.updateAlpha();
            obj.computeGradient();
            obj.updateAlpha();
        end

        function computeFunction(obj)
            obj.updateHomogenizedMaterialProperties();
            obj.solveState();
            obj.computeFunctionValue();
            obj.normalizeFunction();
        end

        function computeGradient(obj)
            obj.solveAdjoint();
            obj.computeGradientValue();
            obj.filterGradient();
            obj.normalizeGradient();
        end

        function f = getPhysicalProblems(obj)
            f{1} = obj.physicalProblem;
        end

        function f = getRegularizedDesignVariable(obj)
            f = obj.regDesignVariable{1:end-1};
        end

        function q = getQuad(obj)
            q = obj.physicalProblem.getQuadrature();
        end

    end

    methods (Access = protected)

        function createOrientationUpdater(obj)
            cParams.type = 'MinimumEigenValue';
            obj.orientationUpdater = OrientationUpdater.create(cParams);
        end

        function createEquilibriumProblem(obj,fileName)
            a.fileName = fileName;
            s = FemDataContainer(a);
            obj.physicalProblem = FEM.create(s);
            obj.initPrincipalDirections();
        end

        function updateHomogenizedMaterialProperties(obj)
            obj.filterDesignVariable();
            obj.homogenizedVariablesComputer.computeCtensor(obj.regDesignVariable);
        end

        function filterDesignVariable(obj)
            nx = length(obj.designVariable.value)/obj.designVariable.nVariables;
            x  = obj.designVariable.value;
            xf = cell(obj.designVariable.nVariables,1);
            for ivar = 1:obj.designVariable.nVariables
                i0 = nx*(ivar-1) + 1;
                iF = nx*ivar;
                xs = x(i0:iF);
                xf{ivar} = obj.filter.getP0fromP1(xs);
            end
            xf{ivar+1} = obj.designVariable.alpha;
            obj.regDesignVariable = xf;
        end

        function filterGradient(obj)
            g = obj.gradient;
            gf = zeros(size(obj.Msmooth,1),obj.nVariables);
            for ivar = 1:obj.nVariables
                gs = g(:,:,ivar);
                gf(:,ivar) = obj.filter.getP1fromP0(gs);
            end
            gf = obj.Msmooth*gf;
            g = gf(:);
            obj.gradient = g;
        end

        function v = getPdeVariableToPrint(obj,p)
            cParams.physicalProblem = p;
            g = PdeVariableToPrintGetter(cParams);
            v = g.compute();
        end

        function fP = addHomogPrintVariablesNames(obj,fP)
            fH = obj.homogenizedVariablesComputer.createPrintVariables();
            nP = numel(fP);
            for i = 1:numel(fH)
                fP{nP+i} = fH{i};
            end
        end

      function updateAlpha(obj)
          if isequal(obj.designVariable.type,'MicroParams')
            if isfield(obj.physicalProblem.variables,'principalStress')
            cParams.pD = obj.physicalProblem.variables.principalDirections;
            cParams.pS = obj.physicalProblem.variables.principalStress;
            obj.orientationUpdater.compute(cParams);
            alpha = obj.orientationUpdater.alpha;
            obj.designVariable.alpha = alpha;
            end
          end
      end

      function fP = addHomogVariables(obj,fP)
          fH = obj.homogenizedVariablesComputer.addPrintableVariables(obj.designVariable);
          for i = 1:numel(fH)
              fP{end+1} = fH{i};
          end
      end

    end

    methods (Access = private)

        function s = createFEMparameters(obj, file)
            gidParams = obj.createGiDparameters(file);
            s.dim       = gidParams.pdim;
            s.type      = gidParams.ptype;
            s.scale     = gidParams.scale;
            s.mesh      = gidParams.mesh;
            s.dirichlet = gidParams.dirichlet;
            s.pointload = gidParams.pointload;
        end

        function gidParams = createGiDparameters(obj,file)
            gidReader = FemInputReader_GiD();
            gidParams = gidReader.read(file);
        end

        function initPrincipalDirections(obj)
            if isempty(obj.designVariable.alpha)
                dim = obj.physicalProblem.getDimensions();
                nelem = size(obj.dvolu,1);
                ndim = dim.ndimf; %dim.ndim
                alpha0 = zeros(ndim,nelem);
                alpha0(1,:) = 1;
                obj.designVariable.alpha = alpha0;
            end
            obj.physicalProblem.variables.principalDirections = obj.designVariable.alpha;
        end

    end

    methods (Access = protected, Abstract)
        computeFunctionValue(obj)
        computeGradientValue(obj)
        solveState(obj)
        solveAdjoint(obj)
    end
end


function varargout = SIGN(varargin)
%SIGN (overloaded)

switch class(varargin{1})

    case 'double'
        error('Overloaded SDPVAR/SIGN CALLED WITH DOUBLE. Report error')

    case 'sdpvar'
        varargout{1} = InstantiateElementWise(mfilename,varargin{:});

    case 'char'
        switch varargin{1}
            case {'graph','exact'}

                t = varargin{2};
                X = varargin{3};

                d1 = binvar(1);
                d2 = binvar(1);
                d3 = binvar(1);
                [M,m] = derivebounds(X);
                if isequal(getbase(X),[0 1]) && ismember(getvariables(X),yalmip('tempintvariables'))
                    % Numerically unstable case with integer X
                    % d1: Negative <= -1
                    % d2: 0
                    % d3: Postive >= 1
                    F = [X >= m*d1, X <= M*d3, X <= (1-d1)*(M+1)-1,X >=(1-d3)*(m-1)+1, m*(1-d2) <= X <= M*(1-d2), t == -d1 + d3,d1+d2+d3==1];
                else
                    % Numerically unstable case with continuous X
                    F = [X >= m*d1, X <= M*d3, X <= (1-d1)*M,X >=(1-d3)*m, m*(1-d2) <= X <= M*(1-d2), t == -d1 + d3,d1+d2+d3==1];
                end

                varargout{1} = F;
                varargout{2} = struct('convexity','none','monotonicity','none','definiteness','none');
                varargout{3} = X;

            otherwise
                error('SDPVAR/SIGN called with CHAR argument?');
        end
    otherwise
        error('Strange type on first argument in SDPVAR/SIGN');
end


% NSA v1 (Aybat et al. 2011)
% process_video('RPCA', 'NSA1', 'dataset/demo.avi', 'output/demo_NSA1.avi');
stdev = 1;
tol = 5e-6; % optimality tolerance for stopping_type 1
L = nsa_v1(M,stdev,tol,1);
S = M - L;


function F = coth(F, varargin)
%COTH   Hyperbolic cotangent of a CHEBFUN.
%   COTH(F) computes the hyperbolic cotangent of the CHEBFUN F.
%
%   COTH(F, PREF) does the same but uses the CHEBFUNPREF object PREF when
%   computing the composition.
%
% See also ACOTH.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

% Call the compose method:
F = compose(F, @coth, varargin{:});

end


function varargout = waterfall(varargin)
%WATERFALL   Waterfall plot of a DISKFUN.
%   WATERFALL(F) displays the waterfall plot of F.
%
%   WATERFALL(F, S) displays the column and row chebfuns of F that are used
%   for its approximation. This is a 3D version of plot(f, S), where S is a
%   string (see PLOT).
%
%   WATERFALL(F, S, 'nslices', N) displays the first min(N, length(f))
%   column and rows.
%
%   WATERFALL supports passing options to the plot, similar to standard
%   Matlab plot commands. The options supported are:
%       'color':      Color of lines and markers plotted.
%       'marker':     Marker for pivot points.
%       'markersize': Size of markers plotted at pivot points.
%
%   H = WATERFALL(...) returns a handle to a waterfall plot object.
%
% See also DISKFUN/PLOT.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

%switch to polar
f = varargin{1};
f = cart2pol(f, 'cdr');

[varargout{1:nargout}] = waterfall@separableApprox(f,varargin{2:end});

end


%% 3D Model Demo
% This is short demo that loads and renders a 3D model of a human femur. It
% showcases some of MATLAB's advanced graphics features, including lighting and
% specular reflectance.

% Copyright 2011 The MathWorks, Inc.

%% Load STL mesh
% Stereolithography (STL) files are a common format for storing mesh data. STL
% meshes are simply a collection of triangular faces. This type of model is very
% suitable for use with MATLAB's PATCH graphics object.

% Import an STL mesh, returning a PATCH-compatible face-vertex structure
fv = stlread('femur.stl');

%% Render
% The model is rendered with a PATCH graphics object. We also add some dynamic
% lighting, and adjust the material properties to change the specular
% highlighting.

patch(fv,'FaceColor',       [0.8 0.8 1.0], ...
         'EdgeColor',       'none',        ...
         'FaceLighting',    'gouraud',     ...
         'AmbientStrength', 0.15);

% Add a camera light, and tone down the specular highlighting
camlight('headlight');
material('dull');

% Fix the axes scaling, and set a nice view angle
axis('image');
view([-135 35]);


function disp_(u,str)
%DISP_        Display of slope variables in "_" notation
%
%  disp_(u)
%

%Second parameter name for internal purposes: display full structure
%

% written  06/04/09     S.M. Rump
% modified 02/28/10     S.M. Rump  vector output and multi-dimensional arrays
% modified 08/26/12     S.M. Rump  global variables removed
%

  INTLAB_SLOPE = getappdata(0,'INTLAB_SLOPE');

  loose = strcmp(get(0,'FormatSpacing'),'loose');

  numvar = size(u.s,2);
  if numvar~=INTLAB_SLOPE.NUMVAR
    warning('**** number of dependent variables in slope expansion inconsitent')
  end

  if nargin==2
    if isequal(str,'internal')
      disp([ 'slope range (internal structure) ' inputname(1) '.r = ' ])
      display(u.r,'',1);
      disp([ 'slope slope ' inputname(1) '.s = ' ])
      display(u.s,'',1);
      return
    else
      error('Invalid call of slope disp_')
    end
  end

  if loose, disp(' '); end
  disp([ 'slope intval center ' inputname(1) '.c = ' ])
  if loose, disp(' '); end
  ur = u.r(:,1);
  disp_( reshape(ur,u.size) , '' , 1 )
  if loose, disp(' '); end

  if loose, disp(' '); end
  disp([ 'slope intval range ' inputname(1) '.r = ' ])
  if loose, disp(' '); end
  ur = u.r(:,INTLAB_SLOPE.NUMVAR+1);
  disp_( reshape(ur,u.size) , '' , 1 )
  if loose, disp(' '); end

  if loose, disp(' '); end
  disp([ 'slope intval slope ' inputname(1) '.s = ' ])
  if loose, disp(' '); end
  if ( length(u.size)==2 ) & ( u.size(2)==1 )
    disp_( reshape(u.s,[u.size(1) numvar]) , '' , 1 )
  else
    disp_( reshape(u.s,[u.size numvar]) , '' , 1 )
  end
  if loose, disp(' '); end


function f = restrict(f, dom)
% RESTRICT    Restrict the domain of a CHEBFUN3.
%
%   F = RESTRICT(F, DOM) returns a
%   - CHEBFUN3 on the domain DOM that approximates F on that domain if DOM
%     is a nondegenarate cuboid,
%   - CHEBFUN2 that approximates F on the domain if DOM is a plane, and
%   - CHEBFUN that approximates F on the domain if DOM is a line.
%   DOM should be a vector of length 6 specifying the underlying cuboid.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

if ( isa(dom, 'double') )
    if ( numel(dom) == 6 )                   % Restrict to DOM.
        xlen = diff(dom(1:2));
        ylen = diff(dom(3:4));
        zlen = diff(dom(5:6));

        if ( ( xlen == 0 ) && ( ylen == 0) && ( zlen == 0 ) )
            % DOM is a point.
            f = feval(f, dom(1), dom(3), dom(5));

        elseif ( ( xlen ~= 0 ) && ( ylen == 0 ) && ( zlen == 0 ) )
            % DOM is a vertical line (corresponding to a column).
            cols = restrict(f.cols, dom(1:2));
            rows = feval(f.rows, dom(3));
            tubes = feval(f.tubes, dom(5));
            core = chebfun3.txm(chebfun3.txm(f.core, rows, 2), tubes, 3);
            f = chebfun(cols*core);

        elseif ( ( xlen == 0 ) && ( ylen ~= 0 ) && ( zlen == 0 ) )
            % DOM is a horizontal line (corresponding to a row).
            cols = feval(f.cols, dom(1));
            rows = restrict(f.rows, dom(3:4));
            tubes = feval(f.tubes, dom(5));
            core = chebfun3.txm(chebfun3.txm(f.core, cols, 1), tubes, 3);
            f = chebfun(rows*core.');

        elseif ( ( xlen == 0 ) && ( ylen == 0 ) && ( zlen ~= 0 ) )
            % DOM is an oblique line (corresponding to a tube).
            cols = feval(f.cols, dom(1));
            rows = feval(f.rows, dom(3));
            tubes = restrict(f.tubes, dom(5:6));
            core = squeeze(chebfun3.txm(chebfun3.txm(f.core, cols, 1), ...
                rows, 2));
            f = chebfun(tubes*core);

        elseif ( ( xlen == 0 ) && ( ylen ~= 0 ) && ( zlen ~= 0 ) )
            % DOM is a horizontal plane (corresponding to a horizontal slice).
            cols = feval(f.cols, dom(1));
            rows = restrict(f.rows, dom(3:4));
            tubes = restrict(f.tubes, dom(5:6));
            core = squeeze(chebfun3.txm(f.core, cols, 1));
            f = chebfun2(tubes*core.'*rows.');

        elseif ( ( xlen ~= 0 ) && ( ylen == 0 ) && ( zlen ~= 0 ) )
            % DOM is a lateral plane (corresponding to a lateral slice).
            cols = restrict(f.cols, dom(1:2));
            rows = feval(f.rows, dom(3));
            tubes = restrict(f.tubes, dom(5:6));
            core = squeeze(chebfun3.txm(f.core, rows, 2));
            f = chebfun2(tubes*core.'*cols.');

        elseif ( ( xlen ~= 0 ) && ( ylen ~= 0 ) && ( zlen == 0 ) )
            % DOM is a frontal plane (corresponding to a frontal slice).
            cols = restrict(f.cols, dom(1:2));
            rows = restrict(f.rows, dom(3:4));
            tubes = feval(f.tubes,dom(5));
            core = chebfun3.txm(f.core, tubes, 3);
            f = chebfun2(rows*core.'*cols.');

        else
            % DOM is not degenerate
            f.cols = restrict(f.cols, dom(1:2));
            f.rows = restrict(f.rows, dom(3:4));
            f.tubes = restrict(f.tubes, dom(5:6));
            f.domain = dom;
        end
    else
        error('CHEBFUN:CHEBFUN3:restrict:domain', 'Domain not determined.');
    end

else
    error('CHEBFUN:CHEBFUN3:restrict:domain', 'Unrecognizable domain.');
end

end


function pi = CPD_to_pi(CPD, msg_type, n, ps, msg, evidence)
% CPD_TO_PI Compute the pi vector (gaussian)
% function pi = CPD_to_pi(CPD, msg_type, n, ps, msg, evidence)

switch msg_type
 case 'd',
  error('gaussian_CPD can''t create discrete msgs')
 case 'g',
  dps = ps(CPD.dps);
  k = evidence{dps};
  if isempty(k)
    error('gmux node must have observed discrete parent')
  end
  m = msg{n}.pi_from_parent{k};
  B = CPD.weights(:,:,k);
  pi.mu = CPD.mean(:,k) + B * m.mu;
  pi.Sigma = CPD.cov(:,:,k) + B * m.Sigma * B';
end


function [p,priors]=edo_params()
% Conversion of Dynare file [Dynare_edo.mod] into RISE file [edo.rs]
%
% Done 22-Jul-2017 19:19:44.
%
% Remarks:
% - The parameters and shocks variances or
%   standard deviations found in the dynare file are assigned.
% - Shock standard deviations not assigned in the
%   dynare file get a value of 0 following dynare's convention
% - RISE will set all other parameters without a value to nan

p=struct();

p.h=0.715162417869797;
p.r_inf=1.46344163969035;
p.r_y=0.263123294207851;
p.phi_pc=3.54471453295450;
p.phi_H=3.22894079106560;
p.phi_wc=5.49395755514723;
p.phi_ic=0.253308786976374;
p.phi_cd=0.470089385005009;
p.phi_ech=9.13986886546163;
p.gam_pc=0.314488926051065;
p.gam_wc=-0.230018833252054;
p.sigman=39.4075260618789;
p.sigmah=21.8859803402692;
p.rho_R=0.833200065745674;
p.rho_XiL=0.263567746111198;
p.rho_lpref=0.979092048897712;
p.rho_B=0.895267027146152;
p.rho_STAR=0.909187927454138;
p.rho_EFFK=0.937829274540004;
p.rho_EFFECD=-0.240286975088701;
p.rho_HG=0.582395471123139;
p.rho_EFFECH=0.877235725078934;
p.tp2=0.000307314910763576;
p.sig_HG=0.579315931803017;
p.sig_XiL=2.49313873916751;
p.sig_lpref=5.66476748114241;
p.sig_R=0.124100461010359;
p.sig_MUZK=0.936167718269030;
p.sig_MUZM=0.597390920898135;
p.sig_PMKC=0.451830653200989;
p.sig_PMKK=0.685376191952156;
p.sig_EFFECH=0.514704527091087;
p.sig_EFFECD=9.11199585973990;
p.sig_EFFK=0.402779878811407;
p.sig_B=0.295232712196573;
p.sig_STAR=0.104877885500673;
p.r_dy=0;
p.ONE=1;
p.MUZKSS=1.009250;
p.MUZMSS=1.001000;
p.gam_ic=1.0;
p.gam_icd=1.0;
p.r_dinf=0;
p.rpr=0.965;
p.phi_u=1;
p.rho_MUZK=0;
p.rho_MUZM=0;
p.pbeta=0.99862;
p.delta_=0.03;
p.h_cd=0.0;
p.h_ch=0.0;
p.delta_cd=0.055;
p.delta_ch=0.0035;
p.alpha_=0.26;
p.theta_c=7;
p.theta_k=7;
p.unempSS=.06;
p.g_y=0.0;
p.a_ks=0.2;
p.s_AS=0.2;
p.gam_h=1;
p.gam_ech=1;
p.icoef=3;
p.betarl=.958;
p.std_eHG=p.sig_HG;
p.std_eXiL=p.sig_XiL;
p.std_eLpref=p.sig_lpref;
p.std_eR=p.sig_R;
p.std_eMUZK=p.sig_MUZK;
p.std_eMUZM=p.sig_MUZM;
p.std_ePMKC=p.sig_PMKC;
p.std_ePMKK=p.sig_PMKK;
p.std_eEFFECH=p.sig_EFFECH;
p.std_eEFFECD=p.sig_EFFECD;
p.std_eEFFK=p.sig_EFFK;
p.std_eB=p.sig_B;
p.std_eSTAR=p.sig_STAR;

priors=struct();

priors.h={.673, -1, 1};

priors.r_inf={1.461, 1.5000, 0.0625000, 'normal', -999, 999};

priors.r_y={0.214, 0.125, 0.125000, 'normal', -999, 999};

priors.phi_pc={3.126, 4.0000, 4.0000^.5, 'gamma', 0, 999};

priors.phi_H={4.064, 4.0000, 4.0000^.5, 'gamma', 0, 999};

priors.phi_wc={5.119, 4.0000, 4.0000^.5, 'gamma', 0, 999};

priors.phi_ic={.325, 4.0000, 4.0000^.5, 'gamma', 0, 999};

priors.phi_cd={.651, 4.0000, 4.0000^.5, 'gamma', 0, 999};

priors.phi_ech={10.948, 4.0000, 4.0000^.5, 'gamma', 0, 999};

priors.gam_pc={0.386, 0.000, 0.250, 'normal', -999, 999};

priors.gam_wc={0.213, 0.000, 0.250, 'normal', -999, 999};

priors.sigman={1.25, 1.25, 12.5^.5, 'gamma', 0, 999};

priors.sigmah={10, 10, 100^.5, 'gamma', 0, 999};

priors.rho_R={0.654, 0.5, 0.25, 'normal', -1, 1};

priors.rho_XiL={0.654, 0.5, 0.25, 'normal', -1, 1};

priors.rho_lpref={0.954, 0.5, 0.25, 'normal', -1, 1};

priors.rho_B={0.825, 0, 0.5, 'normal', -1, 1};

priors.rho_STAR={0.825, 0, 0.5, 'normal', -1, 1};

priors.rho_EFFK={0.850, 0, 0.5, 'normal', -1, 1};

priors.rho_EFFECD={.230, 0, 0.5, 'normal', -1, 1};

priors.rho_HG={0.596, 0.5, 0.015^.5, 'beta'};

priors.rho_EFFECH={0.844, 0, 0.5, 'normal', -1, 1};

priors.tp2={0.001, 0.0, 0.0005, 'normal', -999, 999};

priors.std_eHG={.745, 1.772454, 4, 'inv_gamma', 0.0001, 999};

priors.std_eXiL={3.621, 1.772454, 4, 'inv_gamma', 0.0001, 999};

priors.std_eLpref={1.621, 1.772454, 4, 'inv_gamma', 0.0001, 999};

priors.std_eR={0.165, 0.354491, 4, 'inv_gamma', 0.0001, 999};

priors.std_eMUZK={.834, 0.443113, 4, 'inv_gamma', 0.0001, 999};

priors.std_eMUZM={.484, 0.443113, 4, 'inv_gamma', 0.0001, 999};

priors.std_ePMKC={.391, 0.354491, 4, 'inv_gamma', 0.0001, 999};

priors.std_ePMKK={.552, 0.354491, 4, 'inv_gamma', 0.0001, 999};

priors.std_eEFFECH={.526, 1.772454, 4, 'inv_gamma', 0.0001, 999};

priors.std_eEFFECD={13.349, 1.772454, 4, 'inv_gamma', 0.0001, 999};

priors.std_eEFFK={.499, 1.772454, 4, 'inv_gamma', 0.0001, 999};

priors.std_eB={0.5, 1.772454, 4, 'inv_gamma', 0.0001, 999};

priors.std_eSTAR={0.05, 0.354491, 4, 'inv_gamma', 0.0001, 999};


function [MI, sequences, indexes, mini, sds, mn, sd] = motionCompDetectMotionMI(view,ROI,scans,plotMI,histogramClip)

%    [MI, sequences, indexes, mini, sds, mn, sd] = motionCompDetectMotionMI(view, [ROI], [scans], [plotMI], [histogramClip])
%
% gb 01/31/05
%
% Remove outliers within a scan and returns an array 'sequences' whose rows
% are the sequences between the outliers. The error computed is based on
% mutual information.
%
% Input arguments :
%       - view : current inplane
%       - ROI : Region of interest where the error has to be computed
%           Default = ones
%       - scan : scan to analyse.
%           Default = current scan
%       - plotMI : indicates if the user wants a plot of the Mutual Information.
%       Should be the value '1' if so.
%           Default = 1
%       - histogramClip : sets the clipping value of the histogram
%           Default = 0.1
%
% It returns :
%       - MI = Mutual Information between consecutive frames
%       - sequences = array representing the resulting sequences between the outliers
%       - indexes = indexes corresponding to the outliers
%       - mini = minimum of MI
%       - sds = array representing the standard deviations of each sequence
%       - mn = mean of MSE after having been clipped
%       - sd = standard deviation of MSE after having been clipped

global dataTYPES

% Initializes arguments and variables
if ieNotDefined('histogramClip')
    histogramClip = .1;
end

if ieNotDefined('scans')
    scans = selectScans(view);
end

if ieNotDefined('ROI')
    ROI = '';
end

curDataType = viewGet(view,'currentdatatype');
MI = [];
lastFrame = 0;
h = mrvWaitbar(0,'Computing Mutual Information...');

for scan = scans

    mrvWaitbar((scan - 1)/scans(end),h,['Computing Mutual Information for scan ' num2str(scan)]);

    clear tSeriesAllSlices;

	tSeriesAllSlices = motionCompLoadImages(view,scan);
	nFrames = size(tSeriesAllSlices,1);
    nSlices = size(tSeriesAllSlices,4);

    % Computes the Mutual Information when changing scans
    firstFrame = tSeriesAllSlices(1,:,:,:);
    if isequal(lastFrame,0)
        MI = [MI;0];
    else
        MI = [MI;motionCompMI(firstFrame,ROI,lastFrame)];
    end
    lastFrame = tSeriesAllSlices(nFrames,:,:,:);

    % Computes the Mutual Information
	MI = [MI;motionCompMI(tSeriesAllSlices,ROI)];

end
mrvWaitbar(1,h)

MI(1) = MI(2);

% Clips the histogram to calculate the mean and the standard deviation
% of MI without taking into account the outliers
histClip = mrAnatHistogramClip(MI,histogramClip,1,0);

% Computes the mean and the standard deviation of the clipped MI
mn = mean(histClip);
sd =  std(histClip);

% Finds the outliers. Are considered outliers all the values above the mean
% - two standard deviations
indexes = (find(MI < mn - 2*sd));
mini = min(MI);

% Finds the resulting sequences between the outliers.
sequences = horzcat([1;indexes + 2],[indexes - 2;nFrames - 1]);
sequences = sequences(find(sequences(:,2) - sequences(:,1) > 5),:);

% Computes all the standard deviations
sds = zeros(size(sequences,1),1);
for i = 1:size(sequences,1)
    sds(i) = std(MI(sequences(i,1):sequences(i,2)));
end

% Plots the curves
if ieNotDefined('plotMI')
    plotMI = 0;
end

if plotMI > 0
    figure
    title(['MI for ' view.sessionCode]);

    plot(MI)
    hold on
    plot(1:length(MI),mn*ones(1,length(MI)),'-.')
    plot([1 length(MI)],[mn - 2*sd, mn - 2*sd],'r')

    % Another measure can be used. Sometimes we can assume that the signal
    % is equally distributed around its mean. The explicit measure is :
    % mn - (max(MI) - mn)
    %
    % plot([1 nFrames],[2*mn - max(MI),2*mn - max(MI)],'black')

    for scanIndex = 1:(length(scans) - 1)
        plot([nFrames*scanIndex nFrames*scanIndex],[mini max(MI)],'-.','Color','m');
    end
end

close(h);


classdef TraceData
   %TraceData   Handles the data associated with timeseries.
   %
   %   TraceData contains the functionality associated with data
   %   manipulation, including dealing with units.
   %
   %   TraceData might be considered a "light" version of MATLAB's timeseries
   %   class. Whereas the timeseries class has lots of functionality, it
   %   suffers (at the time of this writing) from much slower execution times.
   %
   % About TraceData vs waveform
   %
   % TraceData Properties:
   %       data       - column of evenly sampled data
   %       samplerate - number of samples per second
   %       units      - units for the data, ex. 'counts', 'm / sec'
   %       duration   - time between first and last samples
   %       hasnan     - true if any value is nan
   %
   % TraceData Methods:
   %
   %    Derived properties:
   %       nyquist - Nyquist frequency (samplerate / 2)
   %       period - Period  (1/samplerate)
   %       formattedduration - retrieve duration as formatted text
   %
   %    additional Methods:
   %       nsamples  - return number of data samples
   %
   %    Mathamatical operations:
   %       plus - (+)addition
   %       minus - (-)subtraction
   %       times - (.*) element multiplication
   %       mtimes - (*) matrix multiplication
   %       rdivide - (./) element division
   %
   %       uminus - (-A) unary minus
   %       sign - signum of data (returns array of +1, 0, or -1)
   %       abs - Absolute value
   %
   %       forEach - apply a function element-wise Tnew(n) = f(T(n), values(n))
   %
   %    Binary Operators:
   %       eq - (A==B) true if data, samplerate and units match.
   %       ne - (A~=B) false if data, samplerate and units match.
   %
   %    Statistics (returns a single value for each trace):
   %       min - Minimum value of data
   %       max - Maximum  value of data
   %       mean - Average value of data
   %       median - Median value of data
   %       var - Variance of data
   %       std - Standard Deviation of data
   %
   %    Advance Mathamatical operations:
   %       diff - Difference and approximate derivative for traces
   %       integrate - cumulative sums of data
   %
   %       hilbert - Hilbert envelope (real only)
   %       taper - Apply a taper to the data
   %       resample - Resample the data
   %       demean - Remove the mean
   %       detrend - Remove trend from data
   %       clip - Clip the data
   %
   %       extract - Retrieve a subset of the data
   %
   %    Conversion operations:
   %       double - retrieve data as 1xN array of double
   %
   %       stack - stack all waveforms
   %       binStack - stack N waveforms at a time (with optional overlap)
   %
   %       compatibleWith - Compare units, samplerate and datalength
   %       assertCompatibleWith - Error if units, samplerate and datalength do not match
   %
   %       fillgaps - replace nan values (can replace other values)
   %       zero2nan - Replace values close to zero with nans
   %       amplitude_spectrum
   %       setlength - adjust length of data to allow batch processing
   %
   % See also Seismictrace, waveform, timeseries

   % Error recovery and trapping with traces
   % trying new tactic. I won't try to anticipate all the various ways
   % someone can provide incompatible data. Instead, I'm going to provide a
   % comment with my expectations which will show up automatically in the
   % displayed error.

   % Waveform functions included in Tracedata:
   %  - functions that manipulate the data itself
   %
   % Waveform functions NOT added to Tracedata:
   %  - functions that require knowledge of time
   %  - functions that require knowledge of location
   %  - function that access user defined fields
   %  - functions that access history
   %  - additinal not-so-sure-we-need-these functions
   %    : getpeaks

   properties
      data = []% time-series data, kept in a column
      samplerate  = NaN % in samples/sec
      units = 'none' % text description of data units
   end

   properties(Dependent)
      duration % duration in seconds. To get matlab duration, divide by 86400
      hasnan;
   end

   properties(Hidden=true)
      % when trust_assignments is false, then data
      trust_assignments = false; % if not trusted, then slows down computations somewhat, but is useful for debugging.
      debug_level
   end

   methods
      function obj = TraceData(varargin)
         %TraceData construct a TraceData object
         switch nargin
            case 1
               if isa(varargin{1}, 'waveform')
                  obj.samplerate = get(varargin{1},'freq');
                  obj.data = get(varargin{1},'data');
                  obj.units = get(varargin{1}, 'units');

               elseif isa(varargin{1},'TraceData') && ~strcmp(class(varargin{1}),'TraceData')
                  if numel(varargin{1})==1;
                  obj.data = varargin{1}.data;
                  obj.samplerate = varargin{1}.samplerate;
                  obj.units = varargin{1}.units;
                  else
                     for n=1:numel(varargin{1})
                        obj(n) = TraceData(varargin{1}(n));
                     end
                     reshape(obj,size(varargin{1}));
                  end
               else
                  error('Unknown conversion');
               end
            case 3 % TraceData(data, samplerate, units);
               obj.data = varargin{1};
               obj.samplerate = varargin{2};
               obj.units = varargin{3};
         end %switch
      end

      function tf = get.hasnan(obj)
         %get.hasnan   functional hasnan allows for
         % NOTE: technically, hasnan could be set as data is entered.
         %   any([T.hasnan])
         tf = any(isnan(obj.data));
      end
      function obj = set.data(obj, values)
         %set.data   Assign values to data as a column
         obj.data = values(:);
      end

      function N = nyquist(T)
         %nyquist   the nyquist frequency calculated as (samplerate / 2)
         N=[T.samplerate] ./ 2;
         reshape(N,size(T));
      end

      function p = period(T)
         %period   Period, calculated as (1 / samplerate)
         p = 1 ./ [T.samplerate];
         % NOT reshaped
      end

      function val = sampletimes(obj)
         %sampletimes  MATLAB time offset of each sample.
         %
         % equivalent to waveform's get(w,'timevector');
         assert(numel(obj) == 1, 'only works on one TraceData at a time');
         val = (0:(numel(obj.data)-1)) .* obj.period / 86400;
         val = val(:);
      end

      function secondsOfData = get.duration(obj)
         %secondsOfData   Duration of samples, in seconds
         if isempty(obj.data) || isempty(obj.samplerate)
            secondsOfData = 0;
         else
            secondsOfData = numel(obj.data) / obj.samplerate;
         end
      end

      function n = nsamples(obj)
         %nsamples   number of samples in the trace(s)
         %   n = nsamples(traces) will return the number of samples for
         %   each trace in an array of the same size as traces
         %
         %   See also numel
         n = zeros(size(obj));
         for m=1:numel(obj)
            n(m) = numel(obj(m).data);
         end
      end

      function s = formattedduration(obj, fmt)
         %formattedduration   Duration as a formatted string
         %  s = trace.formattedduration() retrieves the duration in the
         %  default format as 'dd:hh:mm:ss.SSS'
         %  s = trace.formattedduration(fmt) retrieves duration in format
         %  specified.
         %
         %  depends upon the duration class, introduced in r2014b
         %
         %  See also duration
         secsOfData = obj.duration;
         if exist('duration','class') %available in recent r2014b and later of matlab
            if exist('fmt','var') && ~isempty(fmt)
               s = char(duration(0,0,secsOfData,'Format',fmt));
            else
               s = char(duration(0,0,secsOfData,'Format','dd:hh:mm:ss.SSS'));
            end
         else
            error('advanced duration functions supported in r2014b and later');
         end
      end

      %% Mathamatical - BASIC OPERATIONS
      function A = plus(A, B)
         %+   Plus.
         %   C=A+B add something to the TraceData's data.
         %
         %   valid combinations
         %      TraceData + NumericVector; % same length as TraceData.data
         %      TraceData + Scalar;
         %
         %  To avoid ambiguity with the metadata, two traces are added
         %  together by explicitly adding the data from one to the other:
         %
         %      % assertCompatiblewith(TraceData1, TraceData2); % for debug
         %      TraceData1 + TraceData2.data
         %
         % See also minus, arrayApply, compatiblewith, assertCompatiblewith

         if ~isa(A, 'TraceData')
            [A, B] = deal(B, A); % swap values
         end

         % A is guaranteed to be TraceData
         if isnumeric(B)
            for n = 1: numel(A)
               A(n).data = A(n).data + B; % add to either a scalar or a COLUMN of numbers (same length as TraceData's data)
            end
         elseif isa(B,'TraceData')
            error('TraceData:plus:ambiguousOperation',...
               ['Adding two TraceData objects results in ambiguous metadata.'...
               '\nInstead, add the data explicitly to the Trace whose'...
               ' metadata you wish to keep.\nEx. T = T1 + T2.data']);
         else
            error('TraceData:plus:unknownClass','do not know how to add a %s to a TraceData object', class(B));
         end
      end

      function A = minus(A, B)
         %-  Subtract something from the Trace's data,
         %   C=A-B This will return a TraceData object
         %
         %   valid combinations
         %      TraceData - NumericVector; % same length as TraceData.data
         %      TraceData - Scalar;
         %
         %   To avoid ambiguity with the metadata, two traces are subtracted
         %   by explicitly subtracting the one's data from the other:
         %
         %      % assertCompatiblewith(TraceData1, TraceData2); % for debug
         %      TraceData1 - TraceData2.data
         %
         %   See also plus, arrayApply, compatiblewith, assertCompatiblewith

         if isnumeric(B)
            % A is guaranteed to be a TraceData
            for n = 1:numel(A)
               A(n).data = A(n).data - B; % subtract either a scalar or a COLUMN of numbers (same length as TraceData's data)
            end
         elseif isa(B,'TraceData')
            error('TraceData:minus:ambiguousOperation',...
               ['Subtracting a Trace from a constant is not supported.\n'...
               'For equivalent functionality, add the negative.\nEx. ans = 5 + (-T)']);
         else
            error('TraceData:minus:unknownClass','do not know how to subtract a %s from a %s', class(B), class(A));
         end
      end

      function A = times(A,B)
         %.*   Elementwise Trace data multiplication
         %   C=A.*B or C=B.*A when A is a TraceData object
         %   Either A or B can be a scalar, or a vector of same size as the
         %   data elements of the TraceData object.
         %
         %   To avoid ambiguity with the metadata, two traces are multiplied
         %   by explicitly multiplying one's data with the other:
         %
         %      % assertCompatiblewith(TraceData1, TraceData2); % for debug
         %      TraceData1 .* TraceData2.data
         %
         %  See also arrayApply, mtimes, compatiblewith, assertCompatiblewith
         if isnumeric(B)
            for n=1:numel(A)
               A(n).data = A(n).data .* B; % B should be either scalar or same size as obj.data
            end
         elseif isnumeric(A)
            [A, B] = deal(B, A); % swap values
            for n=1:numel(A)
               A(n).data = A(n).data .* B; % B should be either scalar or same size as obj.data
            end
         else
            error('TraceData:times:unknownClass','do not know how to multiply a %s with a TraceData object', class(B));
         end
      end

      function C = mtimes(A, B)
         %*   Matrix multiplication against data within a trace
         %   C=A*B matrix multiplication against data within a trace
         %   result is a matrix, vector, or scalar. (NOT a TraceDataObject)
         %
         %   See also times, arrayApply
         if isa(A,'TraceData')
            C = A.data * B;
         else
            C = A * B.data;
         end
      end

      function A = rdivide(A, B)
         %./  Divide data elements of A by B
         %   C=A./B performs elementwise division on trace data
         %   A must be a TraceData object
         %   B can be either a scalar or vector of numbers the same size as A.data
         %
         %   To avoid ambiguity with the metadata, two traces are multiplied
         %   by explicitly dividing one's data from the other:
         %
         %   % assertCompatiblewith(TraceData1, TraceData2); % for debug
         %   TraceData1 ./ TraceData2.data
         %
         %   See also times, mtimes, arrayApply, compatiblewith, assertCompatiblewith

         if isnumeric(B)
            % A is guaranteed to be a TraceData
            for n=1:numel(A)
               A(n).data = A(n).data ./ B; % subtract either a scalar or a COLUMN of numbers (same length as TraceData's data)
            end
         else
            error('TraceData:rdivide:unknownClass','do not know how to divide a %s from a TraceData object', class(B));
         end
      end

      function A = power(A, B)
         %.^   Array power for TraceData
         %   C=A.^B raises each data element of A to the power B and then
         %   returns the resulting trace(s)
         %
         %   See also power, arrayApply

         assert(isa(A,'TraceData'),'TraceData:power:invalidType',...
            'for A .^ B, B cannot be a TraceData object');
         assert(isnumeric(B),'TraceData:power:invalidType',...
            'for A .^ B, B must be numeric');
         for n=1:numel(A)
            A(n).data = A(n).data .^ B; % B should be scalar or same length as A
         end
      end

      function A = uminus(A)
         %-   Unary minus.
         %   -A negates the data in A and returns the resulting trace(s)
         %
         %   see also uminus
         for n=1:numel(A)
            A(n).data = -A(n).data;
         end
      end

      function trace = abs(trace)
         %Absolute value of trace data
         %  T = abs(trace) returns traces containing the absolute values of
         %  the data.
         %
         %See also abs, sign
         for n=1:numel(trace)
            trace(n).data = abs(trace(n).data);
         end
      end

      function trace = sign(trace)
         %sign   Convert each data point to its signum (+1, 0, +1)
         % T = sign(trace) returns a a trace containing the signs of the
         % data, instead of the data.
         %
         % See also sign
         for n=1:numel(trace)
            trace(n).data = sign(trace(n).data);
            %trace(n).units = ['sign(', trace(n).units, ')'];
         end
      end

      %% more complicated
      function T = diff(T, varargin)
         %diff   Difference and approximate derivative for traces
         %  A = diff(trace)
         %  A = diff(trace, options) see the builtin diff for details on
         %  available options.
         %
         %  trace must have samplerate and data assigned, otherwise you may
         %  get "a Matrix dimensions must agree" error
         %
         %  units are automatically changed. Assuming the sample rate is
         %  samples/sec, then the new trace is in currentunits / sec.
         %
         %  See also diff
         if isempty(varargin)
            for I=1:numel(T)
               T(I).data = diff(T(I).data) .* T(I).samplerate; % must have data and sample rate
            end
         else
            error('not implemented yet');
         end
         for I=1:numel(T)
            tempUnits = T(I).units;
            whereInUnits = strfind(tempUnits,' * sec');
            if isempty(whereInUnits)
               T(I).units = [tempUnits, ' / sec'];
            else
               tempUnits(whereInUnits(1) :whereInUnits(1)+5) = [];
               T(I).units = tempUnits;
            end
         end
      end

      function T = integrate (T,method)
         %integrate   Integrate a tracedata signal
         %   trace = trace.integrate([method])
         %   goes from Acceleration -> Velocity, and from Velocity -> displacement
         %
         %   tr = trace.integrate()
         %   tr = integrate(trace,'cumsum') performs integration by summing the
         %   data points with the cumsum function, taking into account time interval
         %   and updating the units as appropriate.
         %
         %   tr = trace.integrate('trapz') as above, but uses matlab's
         %   cumtrapz function to perform the integration.
         %
         %   Input Arguments
         %       trace: tracedata   N-DIMENSIONAL
         %       METHOD: either 'cumtrapz' or 'cumsum'  [default is cumsum]
         %
         %   Actual implementation  merely does a cumulative sum of the trace's
         %   samples, and updates the units accordingly. These units may be a
         %   little kludgey.
         %
         %   See also cumsum, cumtrapz, diff

         Nmax = numel(T);
         allfreq = [T.samplerate];

         if ~exist('method','var')
            method = 'cumsum';
         end

         switch lower(method)
            case 'cumsum'
               integratefn = str2func('cumsum');
            case 'trapz'
               integratefn = str2func('cumtrapz');
            otherwise
               error('TraceData:integrate:unknownMethod',...
                  'Unknown integration method. Valid methods are ''cumsum'' and ''trap''');
         end

         for I = 1 : Nmax
            T(I).data = integratefn(T(I).data) ./ allfreq(I);
            tempUnits = T(I).units;
            whereInUnits = strfind(tempUnits,' / sec');
            if isempty(whereInUnits)
               T(I).units = [tempUnits, ' * sec'];
            else
               tempUnits(whereInUnits(1) :whereInUnits(1)+5) = [];
               T(I).units = tempUnits;
            end
         end
      end

      function A = demean(A)
         %demean   Remove the average from TraceData
         %   A = demean(A) will subtract the mean of a trace from its data.
         %
         %   See also demean
         for n=1:numel(A);
            A(n) = A(n) - mean(A(n).data(~isnan(A(n).data)));
         end
      end

      function A = detrend(A, varargin)
         %detrend   Remove the trend from TraceData
         %   A = detrend(A) will subtract the trend of a trace from its
         %   data.
         %   A = detrand(A, ...) allows for additional options.  For an
         %   explanation of these, see MATLAB's builtin detrend.
         %
         %   See also detrend
         for n=1:numel(A);
            A(n).data = detrend(A(n).data,varargin{:});
         end
      end

      function val = bulkCalculate(T, F)
         %bulkCalculate   Run a function against the data
         %  vals = T.bulkCalculate(funcHandle) will against the data field
         %  of each element in T shape is preserved, and all empty
         %  traces return nan FH must return a single value
         %
         %  basically, this will run:
         %    funcHandle(T.data)
         %
         %  for each trace in T
         %
         %  See also max, min, mean, median

         val = nan(size(T));
         for n=numel(T) : -1 : 1
            hasdata(n) = ~isempty(T(n).data);
         end
         val(hasdata) = arrayfun(F,T(hasdata));
      end

      function T = forEach(T, f, values, varargin)
         %forEach  applies a function element-wise to an array B(n) = f(T(n), values(n))
         %   VALUES must be a numeric array of the same size (shape) as T.
         %   Either T or VALUES could also be individual values.
         %
         %   When numel(T)==1:
         %   the output will be an array of T the same size as VALUES.
         %
         %   When numel(V)==1,
         %   you might as well use the standard operator instead.
         %       eg.  T = T + VALUE;
         %
         %  the function f can either be a function handle, string name of
         %  a function  (such as 'plus'), or the valid representation of a
         %  simple mathamatical function, such as: '.*'  './'  '+'  '-'  '.^'
         %
         %  This means that
         %       Tsq = forEach(T, @power, valueArray);
         %  is equivelent to
         %       Tsq = T.forEach('power', valueArray);
         %  which is equivelent to
         %       Tsq = T.forEach('.^', valueArray);
         %
         %
         %  apply(...,'loose') ignores the size restriction, but
         %  enforces the number of elements.  Most useful in getting around
         %  applying something 1xN to something Nx1
         %
         %  example:
         %    % add offset to each trace
         %    offsets = 1:numel(T);
         %    Toffset = T.apply('+', offsets, 'loose');
         %
         %  example:
         %    % you can also create your own function of the form f(T,x):
         %    myfn = @(T, x) T .* x + x;
         %    newT = T.apply(T, myfn, values)
         %
         % See also times, rdivide, plus, minus, power
         TisScalar = numel(T)==1;
         VisScalar = numel(values)==1;
         eitherIsScalar = TisScalar || VisScalar;
         ignoreShape = eitherIsScalar || (~isempty(varargin) && strcmpi(varargin{end},'loose'));
         if ignoreShape
            assert(eitherIsScalar || numel(values)==numel(T), ...
               'Both the traces and values must have the same number of elements T:[%d] vs values:[%d',...
               numel(T), numel(values) );
         else
            assert(eitherIsScalar || all(size(values)==size(T)),...
               ['Both the traces and the values must be the same size.'...
               'T:[%s] vs values:[%s]\n',...
               'Use arrayApply(...,''loose'') if only the number of elements matters'],...
               TraceData.size2str(T), TraceData.size2str(values));
         end
         if ischar(f)
            f=str2func(f);
         end

         if VisScalar
            T = f(T, values); % not necessary to use arrayApply when either is a scalar
            return
         elseif TisScalar
            T = repmat(T,size(values));
            for n=1:numel(values)
               T(n) = f(T(n), values(n));
            end
            return
         end

         for n=1:numel(T)
            T(n) = f(T(n), values(n));
         end
      end

      function val = max(T)
         %max   Maximum value for trace data
         %   maxVals = max(traces);
         %
         %   See also max
         F = @(X) max(X.data);
         val = T.bulkCalculate(F);
      end
      function val = min(T)
         %min   Minimum value for trace data
         %   minVals = min(traces);
         %
         %   See also min
         F = @(X) min(X.data);
         val = T.bulkCalculate(F);
      end
      function val = mean(T)
         %mean   Average or mean value for trace data
         %   meanVals = mean(traces);
         %
         %   See also mean
         F = @(X) mean(X.data(~isnan(X.data)));
         val = T.bulkCalculate(F);
      end
      function val = median(T)
         %median   Median value for trace data
         %   medianVals = median(traces);
         %
         %   See also median
         F = @(X) median(X.data(~isnan(X.data)));
         val = T.bulkCalculate(F);
      end
      function val = std(T, varargin)
         %std   standard deviation for traces
         %  vals = std(traces) retrieves the std from each trace, returning
         %  a traces array of the same shape as T.
         %  vals = std(traces, options); lets you declare options as per the
         %  builtin version of std
         %  useful option:
         %
         %     vals = T.std('omitnan') % or 'includenan'
         %
         %  See also std, bulkCalculate
         if exist('varargin','var')
            F = @(X) std(X.data,varargin{:});
         else
            F = @(X) std(X.data);
         end
         val = T.bulkCalculate(F);
      end
      function val = var(T, varargin)
         %var   calulate variance for traces
         %  vals = var(traces);
         %  vals = var(traces,options); lets you declare options as per the
         %  builtin version of var.
         %  useful option:
         %    vals = traces.var(taces,'omitnan') % or 'includenan'
         %
         %  See also var, bulkCalculate
         if exist('varargin','var')
            F = @(X) var(X.data,varargin{:});
         else
            F = @(X) var(X.data);
         end
         val = T.bulkCalculate(F);
      end
      %% extended functionality
      [A, phi, f] = amplitude_spectrum(td)

      function obj = clip(obj, vals)
         %clip   clips a trace's data at a particular max/min value range
         %   clippedtraces = clip(traces, values)
         %
         %   Input Arguments
         %       TRACES: an N-dimensional TraceData object
         %       VALUES: a number. If a scalar, then amplitudes will be
         %           clipped at +/- value. If a pair, eg. [Max, Min] then
         %           traces will be clipped between these two values
         %
         %   All values beyond maximum ranges will be set to the maximum range

         if nargin < 2,
            vals = [];
         end

         switch numel(vals)
            case 0
               warning('TraceData:clip:noClipValue',...
                  'No values given, TraceData remains unclipped');
               return

            case 1 % clip at +/- input value
               if ~isnumeric(vals)
                  error('TraceData:clip:invalidClipValue','Non-numeric clip value');
               end
               vals = abs(vals);
               disp(['Clipping at +/- ' num2str(vals)]);
               vals = [-vals vals];

            case 2
               if ~isnumeric(vals)
                  error('TraceData:clip:invalidClipValue','Non-numeric clip value');
               end
               if vals(1) > vals(2)
                  error('TraceData:clip:reversedValues',...
                     'Clipping values are  reversed: Value1 %f > Value2 %f', vals(1),vals(2));
               end
               %everything is AOK
            otherwise
               warning('TraceData:clip:invalidClipValue',...
                  'Invalid clip values. TraceData remains unclipped. specify [min max] values');
               return
         end

         for N = 1: numel(obj)
            d = obj(N).data;
            d(d < vals(1)) = vals(1);
            d(d > vals(2)) = vals(2);
            obj(N).data = d;
         end
      end

      function d = double(obj,option)
         %double   TraceData data as double
         %   d = double(T) returns the data within T as a column. If T is
         %   an array with N elements, then data is returned in array with
         %   size N x maximum_data_length_in_T.
         %
         %   d = double(T, fillfunction) allows you to specify how the array
         %   is filled. FILLFUNCTION is a handle or name of any function
         %   that can accept (row, col) arguments, and return an array of some
         %   value. By default, the array is filled with zeros.
         %
         %   Example. Retrieve array using nan as filler
         %   d = double(T, @nan);
         %
         %   See also zeros, nan

         if nargin == 1
            createDefaultArray = @zeros;
         else
            if ischar(option)
               createDefaultArray = str2func(option);
            elseif isa(option,'function_handle')
               createDefaultArray = option;
            else
               error('TraceData:double:invalidOption',...
                  '''option'' must be either a function handle or function name.');
            end
         end
         dlens = obj.nsamples();
         maxlen = max(dlens(:));
         d = createDefaultArray(maxlen, numel(obj));
         for n = 1:numel(obj)
            d(1:dlens(n),n) = double(obj(n).data);
         end
      end

      function tf = eq(A, B)
         %== Equal for TraceData
         %  eq(A,B) is called for A==B when A or B is a TraceData object.
         %  will return equal if the data , samplerate, and units match.
         %
         %  See also ne
         tf = all(A.data == B.data) && A.samplerate==B.samplerate && strcmp(A.units, B.units);
      end

      function tf = ne(A,B)
         %~=   Not equal for TraceData.
         %  A~=B compares the data, samplerate, and units
         %
         %  C = ne(A,B) is called for the syntax 'A ~= B' when A or B is a
         %  TraceData object.
         %  See also eq
         tf = ~eq(A,B);
      end;

      function outT = extract(Tr, method, startPos, endPos)
         %extract   Retrieve subset of TraceData
         %
         %    subTraces = extract(traces, 'index', startPos, endPos)
         %
         %
         %   waveform = T.extract('INDEX', startPos, endPos)
         %       returns traces with the subset of data from startIndex to
         %       endIndex.  Essentially, this is equivelent to
         %       T.data = T.data(startPos, endPos)
         %
         %       data into an array, as in D = get(W,'data'), then returning a
         %       waveform with the subset of data,
         %       ie. waveform = set(waveform,'data', D(startIndex:endIndex));
         %
         %    See also SeismicTrace/extract
         switch lower(method)
            case 'index'
               assert(numel(startPos) == numel(endPos), 'number of start and end indices must match');
               outT = repmat(TraceData,numel(Tr),numel(startPos));
               for n=1:numel(T);
                  for t=1:numel(startPos)
                     outT(n,t) = Tr(n);
                     outT(n,t).data = Tr(n).data(startPos(t), endPos(t));
                  end
               end
         end
      end

      function td = fillgaps(td,value, gapvalue)
         %fillgaps   fill missing data with values of your choice
         %  T = T.fillgaps(value) fills data with the number of your choice
         %  VALUE can also be nan or inf or -inf
         %
         %  T = T.fillgaps([]) removes missing data from trace. Warning, the
         %  resulting timing issues are NOT corrected for!
         %
         %  T = T.fillgaps('method') replaces data using an interpolation method of
         %  your choice. Valid methods are:
         %
         %    'meanall' - replace missing values with the mean of the whole
         %    dataset
         %
         %    'number' - replace missing value with a numeric value of your
         %    choice (can also be Inf, -Inf, NaN)
         %
         %    'interp' - assuming missing values are marked by NaN, this will use
         %    cubic interpolation to estimate the missing values
         %
         %  FILLGAPS is designed to replace NaN values. However, if if you
         %  use T = T.fillgaps(number, gapvalue), then ALL data points with
         %  the value GAPVALUE will be replaced by NUMBER.

         if ~(isnumeric(value) && (isscalar(value) || isempty(value)) || ischar(value))
            warning('TraceData:fillgaps:invalidGapValue',...
               'Value to replace data with must be string or scalar or []');
         end

         if ~exist('gapvalue','var') || isnan(gapvalue)
            getgaps = @(x) isnan(x.data);
         else
            getgaps = @(x) x.data == gapvalue;
         end;

         if ischar(value)
            fillmethod = lower(value);
         else
            fillmethod = 'number';
         end

         switch fillmethod
            case 'meanall'
               for N = 1:numel(td);
                  allgaps = getgaps(td(N));
                  % do not include the values to be replaced
                  meanVal = mean(td(N).data(~allgaps));
                  if isnan(meanVal)
                     meanVal = 0;
                  end
                  td(N).data(allgaps) = meanVal;
               end
            case 'number'
               for N = 1:numel(td);
                  td(N).data(getgaps(td(N))) = value;
               end
            case 'interp' % blame Glenn, inspired by http://www.mathworks.com/matlabcentral/fileexchange/8225-naninterp by E Rodriguez
               for N = 1:numel(td);
                  X = td(N).data;
                  X(isnan(X)) = interp1(find(~isnan(X)), X(~isnan(X)), find(isnan(X)),'cubic');
                  td(N).data = X;
               end
            otherwise
               error('TraceData:fillgaps:unimplementedMethod',...
                  'Unimplemented fillgaps method [%s]', fillmethod);
         end
      end

      function T = zero2nan(T,mgl)
         %zero2nan   replaces zeros with nan values.
         % Should be replaced with T.fillgaps(nan, 0)
         % however, it was designed to have a minimum gap length Perhaps this
         % should be added to fillgaps
         %
         %This function replaces gaps that have been filled with zeros and
         %converts them to NaN values. This is the inverse of T =
         %T.fillgaps(0). An input mgl defines the minimum gap length to be
         %converted to NaN gaps, i.e. if only 5 consecutive zero values
         %exist in a given small gap, they will be converted to NaN values
         %if mgl <= 5 and left as zero values if mgl > 5
         %
         %USAGE: T = T.zero2nan(mgl)
         %
         %REQUIRED INPUTS:
         %   mgl - minimum gap length (datapoints) to convert to NaN values
         %
         %OUTPUTS: w - trace with gaps converted to NaN
         %
         %See also nan, fillgaps

         % Author: Dane Ketner, Alaska Volcano Observatory
         % Modified: Celso Reyes: rewrote algorithm to elimenate looping (2x faster)
         %                        results differ because old method converted
         %                        5 zeros only if mgl <5 (not <=5)

         for nw = 1:numel(T)
            closeToZero = abs(T(nw).data) < 0.1; % 0.1 was already chosen -CR

            % --- the logic below should be pulled into a new function, since it is
            % shared across a couple different areas, such as trace/clean -- %
            firstZeros = find(diff([false; closeToZero(:)]) == 1);
            lastZeros = find(diff([closeToZero(:); false]) == -1);
            assert(numel(firstZeros) == numel(lastZeros));
            nContiguousZeros = lastZeros - firstZeros + 1;
            firstZeros(nContiguousZeros < mgl) = [];
            lastZeros(nContiguousZeros < mgl) = [];

            for c=1:numel(firstZeros)
               T(nw).data(firstZeros(c) : lastZeros(c)) = NaN;
            end
         end
      end

      function t = setlength(t, maxlen)
         %setlength   adjust length of trace data to allow batch processing
         %   trace = traces.setlength()
         %       adjusts all traces to the length of the largest, while
         %       zero-padding all shorter traces
         %
         %   trace = traces.setlength(maxlength)
         %       sets all data lengths to maxlength, padding with zero or
         %       truncating as necessary.
         %
         %  examples
         %       % let traces be a 1x2 TraceData object
         %       % 3000 samples in traces(1)
         %       % 10025 samples in traces(2)
         %
         %       % set both waves' data to a length of to 10025 while padding the
         %       % smaller of the two with zeroes.
         %       outTraces = traces.setlength
         %
         %       % set both sample lengths to 500 truncating both of them...
         %       outTraces = traces.setlength(500)
         datalengths = arrayfun(@(x) numel(x.data), t);
         if ~exist('maxlen','var')
            maxlen = max(datalengths);
         end

         for n=find(datalengths < maxlen)
            t(n).data(maxlen) = 0;
         end

         for n=find(datalengths > maxlen);
            t(n).data = t(n).data(1:maxlen);
         end
      end

      function T = hilbert(T, n)
         %hilbert   Discrete-time analytic Hilbert transform for traces.
         %   trace = trace.hilbert()
         %   trace = trace.hilbert(N);
         %
         % THIS version only returns the abs value in the trace. If you
         % want to keep the imaginary values, then you should use the
         % built-in hilbert transform. ie. Don't feed it a trace, feed it
         % a vector... - CR
         %
         % See also FFT, IFFT, HILBERT

         if nargin==2
            T = arrayfun(@myHilbertN,T);
         else
            T = arrayfun(@myHilbert,T);
         end

         function Tr = myHilbert(Tr)
            Tr.data = abs(hilbert(Tr.data));
            Tr.units = 'abs(hilbert)';
         end

         function Tr = myHilbertN(Tr)
            Tr.data = abs(hilbert(Tr.data, n));
            Tr.units = 'abs(hilbert)';
         end
      end

      function T = resample(T, method, crunchFactor)
         %resample   Resample a trace over a specified interval
         %   T = trace.resample(method, crunchfactor)
         %
         %   Input Arguments
         %       Trace: TraceData or Trace       N-dimensional
         %
         %       METHOD: which method of sampling to perform within each sample
         %                window
         %           'max' : maximum value
         %           'min' : minimum value
         %           'mean': average value
         %           'median' : median value
         %           'rms' : rms value (added 2011/06/01)
         %           'absmax': absolute maximum value (greatest deviation from zero)
         %           'absmin': absolute minimum value (smallest deviation from zero)
         %           'absmean' : mean deviation from zero (added 2011/06/01)
         %           'absmedian' : median deviation from zero (added 2011/06/01)
         %           'builtin': Use MATLAB's built in resample routine
         %
         %       CRUNCHFACTOR : the number of samples making up the sample window
         %
         % For example, T.resample('max',5) would grab the max value of every 5
         % samples and return that in a trace with an adjusted frequency. as a
         % result, the trace will have 1/5 of the samples
         %
         %
         % To use matlab's built-in RESAMPLE method...
         %       % assume T is an existing trace
         %       D = double(T);
         %       ResampleD = D.resample(P,Q);  % see matlab's RESAMPLE for specifics
         %
         %       %put back into trace, but don't forget to update the frequency
         %       T.data = ResampleD;
         %       T.samplerate = NewFrequency;
         %
         % See also RESAMPLE, MIN, MAX, MEAN, MEDIAN.

         % AUTHOR: Celso Reyes, Glenn Thompson

         persistent STATS_INSTALLED;
         if isempty(STATS_INSTALLED)
            STATS_INSTALLED = ~isempty(ver('stats'));
         end

         if ~(round(crunchFactor) == crunchFactor)
            disp ('val needs to be an integer');
            return;
         end;
         method = lower(method);

         % determine which function to use on the data. This will
         % automatically determine whether it can use the NaN-safe version
         if ~strcmp(method,'builtin')
            if STATS_INSTALLED
               if numel(method) > 3 && strcmpi(method(1:3),'ABS')
                  methodfn = str2func(['nan' method(4:end)]);
               else
                  methodfn = str2func(['nan', method]);
               end
            else
               if numel(method) > 3 && strcmpi(method(1:3),'ABS')
                  methodfn = str2func(method(4:end));
               else
                  methodfn = str2func(method);
               end
            end
         end

         for i=1:numel(T)
            nRows = ceil(length(T(i).data) / crunchFactor);
            totVals = nRows * crunchFactor; % total number of values that can be accomodated
            if length(T(i).data) < totVals
               T(i).data(end+1:totVals) = mean(T(i).data((nRows-1)*totVals : end)); %pad it with the avg value
            end;

            d = reshape(T(i).data,crunchFactor,nRows); % produces ( val x rowcount) matrix
            switch upper(method)
               case {'MAX', 'MIN', 'RMS'}
                  T(i).data = methodfn(d, [], 1);
               case {'MEAN', 'MEDIAN'}
                  T(i).data = methodfn(d, 1);
               case {'ABSMAX', 'ABSMIN'}
                  T(i).data = methodfn(abs(d),[],1);
               case {'ABSMEAN', 'ABSMEDIAN'}
                  T(i).data = methodfn(abs(d), 1);
               case 'BUILTIN'
                  % assume T is an existing trace
                  ResampleD = resample(T(i).data,1,crunchFactor);  % see matlab's RESAMPLE for specifics
                  T(i).data = ResampleD(:);
               otherwise
                  error('TraceData:resample:UnknownSampleMethod',...
                     'Don''t know what you mean by resample via %s', method);
            end;
            T(i).samplerate = T(i).samplerate ./ crunchFactor;
         end
      end

      function A = smooth(A, varargin)
         %smooth   Smooth response data
         %  A = smooth(T) smooths the Trace's data using a moving average
         %  filter.
         %
         %  smooth requires the signal fitting toolbox.  For additional
         %  options, see that smooth
         % See also smooth
         for n = 1:numel(A)
            A(n).data = smooth(A(n).data,varargin{:});
         end
      end

      function T = taper(T, style, R)
         %taper   apply a taper to a trace
         % trace = trace.taper() applies a cosine (tukey) taper to the ends
         % of a trace with a default taper to the first and last 10% of the
         % trace. This is same as trace.taper('tukey', 0.2)
         %
         % trace = trace.taper(style) applies the tapering window function
         % STYLE to the trace. STYLE can be any valid windowing function
         % some possible taper styles include hanning, tukey, and gaussian.
         % see help for WINDOW for a more complete list.
         %
         % trace = trace.taper(style, R)
         % R varies in meaning according to the window style. For the
         % default cosine (tukey) taper, R is the ratio of tapered to
         % constant sections and is between 0 and 1. For example, if R =
         % 0.1 then the taper at each end of the trace is 5% of the total
         % trace length. R can be either a scalar or the same size as
         % TRACE. If R is a scalar, it is applied uniformly to each
         % trace.
         %
         % for a tukey taper, setting R ito 1 results in a hanning taper
         %
         % All tapers require the signal processing toolbox.
         %
         % See also window
         % AUTHOR: Michael West
         % Modified: Celso Reyes
         a=ver;
         HAVE_SIGBOX = ismember('Signal Processing Toolbox',{a.Name});
         if ~HAVE_SIGBOX
            error('TraceData:taper:signalToolboxNotInstalled',...
               'Using a taper requires access to the Signal Processing Toolbox');
         end
         if ~exist('style','var') || isempty(style) || strcmpi(style,'cosine')
            style = 'tukeywin';
         end
         if exist(lower(style))
            taperfun = str2func(lower(style));
         else
            error('TraceData:taper:invalidTaperType',...
               'This style of taper is not recognized.');
         end

         %% massage R into place
         if strcmpi(style,'tukeywin') && (~exist('R','var') || isempty(R))
            R = 0.2; %assign default taper
         end
         if exist('R','var') &&  ~isnumeric(R)
            error('TraceData:taper:InvalidRValue',...
               'R, if specified, must be numeric');
         end

         if isscalar(R)
            R = repmat(R,size(T));
         end

         if (isvector(R) && isvector(T)) && numel(R) == numel(T)
            if all(size(T)) ~= size(R)
               % same number of elements, but R is Nx1 and w is 1xN or vice-versa
               warning('TraceData:taper:columnsVsRows',...
                  ['One input (either R or the wavform) is arranged in '...
                  'columns while the other is arranged in Rows. While they '...
                  'should be the same shape, taper is continuing with R''']);
               R = R';
            end
         end

         if ~all(size(T) == size(R))
            error('TraceData:taper:InvalidRSize',...
               'R must either be a scalar value, or must be the same size as the input traces');
         end
         nsamples = T.nsamples();
         %% Do the window processing
         if exist('R','var')
            for N=1:numel(T)
               T(N) = T(N) .* window(taperfun, nsamples(N), R(N));
            end
         else
            for N=1:numel(T)
               T(N) = T(N) .* window(taperfun, nsamples(N));
            end
         end

      end

      function [tf, msg] = compatiblewith(A, B)
         %compatiblewith   confirm units, samplerate, and data length match
         %  tf = A.compatiblewith(B) will make sure that A and B have
         %  matching units, sample frequencies, and data length.
         %  If units are empty for either A or B, then units will pass
         %  If samplerate is empty for either A or B, then samplerate will
         %  pass. samplerate is compared within a tolerance of 10e-2
         %
         %  [tf, msg] = A.compatiblewith(B) will also return a message
         %  describing how the test failed.
         %
         %  sample usage:
         %    % assume A & B are TraceData
         %    if A.compatiblewith(B)
         %       dosomething(A, B)
         %    end
         %
         % See also assertCompatiblewith
         TOL = 10e-2;
         if ~(numel(A.data) == numel(B.data))
            tf = false;
            msg = 'Data lengths do not match';
         elseif ~(isempty(B.units) ||isempty(A.units) || strcmp(A.units, B.units))
            tf = false;
            msg = sprintf('Units do not match [%s] vs [%s]', A.units, B.units);
         elseif ~(isempty(A.samplerate) || isempty(B.samplerate) || isnan(A.samplerate) || isnan(B.samplerate) || ismembertol(A.samplerate,B.samplerate, TOL))
            tf = false;
            msg = sprintf('Frequencies do not match [%f] vs [%f]',A.samplerate, B.samplerate);
         else
            tf = true;
            msg = '';
         end
      end

      function assertCompatiblewith(A, B)
         %assertCompatiblewith  asserts units, samplerate, and data length match
         %  assertCompatiblewith(A, B) will error unless A and B have
         %  matching units, sample frequencies, and data length. The error
         %  message will describe what is wrong
         %
         %  use this within a try-catch, or when debugging
         %
         % sample debugging usage:
         %   % assume A & B are TraceData
         %   A.assertCompatiblewith(B)
         %   C = A + B.data;
         %
         % sample prduction usage:
         %   try
         %     A.assertCompatiblewith(B)
         %     C = A + B.data;
         %   catch er
         %     % handle this failure somehow
         %   end
         %
         % See also compatiblewith
         [tf, msg] = compatiblewith(A, B);
         assert(tf, 'TraceData:compatabilityCheckFailed', msg);
      end

      %% stacking functions
      function out = stack(T)
         %stack  stacks data from array of traces
         %   StackedTraces = stack(traces)
         %   ASSUMES frequencies are the same. data does not need to be the same
         %   length, but shorter traces will be padded with zeros at the end
         %   prior to stacking.
         %
         %   Stacks all traces, regardless of dimension
         %
         %   Data is summed, but the average is not taken, nor is it normalized. You
         %   may wish to change the station and/or channel names to reflect the
         %   properties of this trace. Possibly change the units, also, if that
         %   makes sense.
         %
         %   Output retains the same info as the very first trace (minus history)
         %   the station name becomes the original name with "- stack (N)" tacked onto
         %   the end.
         %
         %   To ensure frequency and time matching, use ALIGN
         %
         %   See also trace.align

         out = T(1);
         out.station = [out.station ' - stack (' num2str(numel(T)) ')'];
         out.data = sum(double(T),2);
      end
      function stackedTraces = binStack(T,nBins,binOverlap)
         %binStack   Stack traces with specified number of traces per stack.
         %
         %USAGE: stk = binStack(T,nBins,binOverlap)
         %    If input T contains 100 traces then:
         %    stk = binStack(T,20,0) % stk has 5 stacks of 20 traces
         %    stk = binStack(T,5,0)  % stk has 20 stacks of 5 traces
         %    stk = binStack(T,20,10)  % stk has 9 stacks of 20 traces
         %
         %OUTPUTS: stk - Array of stacked traces

         % Author: Dane Ketner, Alaska Volcano Observatory

         nw = numel(T);
         inc = nBins - binOverlap;
         n=1;
         while 1
            if (n-1)*inc+nBins > nw
               return
            else
               stackedTraces(n) = stack(T((n-1)*inc+1:(n-1)*inc+nBins));
               n=n+1;
            end
         end
      end
      function info(T)
            fprintf('[%s] TraceData array with:\n', TraceData.size2str(T));
            fprintf('  nSaples  sampleRate      Units Duration(sec)   min      max   hasnan?\n');
         for n=1:numel(T)
            if T(n).hasnan; hnt = 'Y'; else hnt = 'N';end
            fprintf('%8d    %f %10s   %8.3f  %8.3f  %8.3f     %s \n',...
               T(n).nsamples, T(n).samplerate, T(n).units, T(n).duration, min(T(n)), max(T(n)), hnt);
         end
      end
       %}
   end

   %% protected methods
   methods(Static, Access=protected)
      function s = size2str(A)
         sz = size(A);
         s = num2str(sz(1));
         for n=2:numel(sz)
            s = [s, 'x', num2str(sz(n))];
         end
      end
   end

   methods(Static)
      function setParameter(name, val)
         %setParameter  controlstate behavior for the TraceData objects
         %
         %     TRUST_ASSIGNMENTS
         %     set_parameter('trust_assignments', true) will verify the
         %     shapes and types of each calculation before storing the data
         %     in the object
         %     set_parameter('trust_assignments', false) will not perform
         %     size/class checks. Use this only when you are looking for
         %     extra speed and tightly control the inputs to this class.
         %
         %     DEBUG_LEVEL
         disp(val)
         disp('not active yet');
         switch lower(name)
            case 'trust_assignments'
               % set the parameter trust_assignments to logical(val);
            case 'debug_level'
               % set the parameter debug_level to numerical val
            otherwise
         end
      end

      newunit = autoscale(axishandle, oldunit);

   end
end


clear;clc;
util;
addpath(genpath('jsonlab-master'));
dataset = {};

%% pre-defined paramters
walllabel = 'wall';
floorlabel = 'floor';

%% load the scene list
scenedir = dir(house_folder);
for i = 3:length(scenedir)
    scenelist{i-2} = scenedir(i).name;
end

%% binary label vectors
labelset = load(labelsetname); % 'entirelabelset.mat' is a list of all fine-grained labels
labelset = labelset.labelset;

%% process each scene(house)
for i = 1:length(scenelist)
    scenename = scenelist{i};
    filename = [house_folder, filesep, scenename];
    filename = [filename, filesep, 'house.json'];
    % load the scene as a list of rooms
    try
        roomlist = parsehouse(filename);
        [ roomlist ] = query_obj_metadata( roomlist, scenename ); % fill in the object info (label, orientation, etc)
    catch
        fprintf([scenename,': ERROR in parsing house.json!\n']);
        continue;
    end

    for j = 1:length(roomlist)
        room = roomlist{j};
        roomname = room.roomname;
        try
            % only preserve the rooms meet our requirements
            [ iscontinue, floorobb, wallobblist, wallnum ] = selectroom( room, wcf_folder, roomtype );
            if(iscontinue)
                % transform the objects into [obb+label] format vector
                % and remove the objects with labels not in labelset
                room = convert_room_rep(room,labelset);

                % add wall objects to the room
                wallidx = strmatch(walllabel,labelset,'exact');
                wallonehot = zeros(length(labelset),1);
                wallonehot(wallidx) = 1;
                for v = 1:size(wallobblist,2)
                    room.labellist{length(room.labellist)+1} = walllabel;
                    room.obblist(1:size(room.obblist,1),size(room.obblist,2)+1) = [wallobblist(:,v);wallonehot];
                end

                % add floor to the room
                room.labellist{length(room.labellist)+1} = floorlabel;
                flooridx = strmatch(floorlabel,labelset,'exact');
                flooronehot = zeros(length(labelset),1);
                flooronehot(flooridx) = 1;
                room.obblist(1:size(room.obblist,1),size(room.obblist,2)+1) = [floorobb(:);flooronehot];

                % align the rooms, the floor is located at [0,0,0]
                room = alignroom( room );

                % extract the object-object relations, and relative
                % distance between objects
                [ Rmat, Dmat, sur ] = build_relationgraph( room.obblist', RELATIONS, length(labelset) );

                % add room to the dataset
                room.Rmat = Rmat;
                room.Dmat = Dmat;
                room.sur = sur;
                dataset{length(dataset)+1} = room;

                fprintf([num2str(length(dataset)), ':', scenename,', ',roomname, '\n']);
            end
        catch
            fprintf([scenename,',', roomname,': ERROR in parsing organizing room! \n']);
            continue;
        end
    end

end
save(output_filename, 'dataset');


function [ res ] = run_KCF_RANSAC( seq, res_path, bSaveImage )
%UNTITLED Summary of this function goes here
%   Detailed explanation goes here
project_dir = fileparts(fileparts(fileparts(mfilename('fullpath'))));
addpath(fullfile(project_dir, 'trackers', 'KCF'));
addpath(fullfile(project_dir, 'trackers', 'KCF', 'mex'));

kernel_type = 'gaussian';
kernel.type = kernel_type;

features.gray = false;
features.hog = false;

padding = 1.5;  %extra area surrounding the target
lambda = 1e-4;  %regularization
output_sigma_factor = 0.1;  %spatial bandwidth (proportional to target)

interp_factor = 0.02;

kernel.sigma = 0.5;

kernel.poly_a = 1;
kernel.poly_b = 9;

features.hog = true;
features.hog_orientations = 9;
cell_size = 4;

target_sz = seq.init_rect(1,[4,3]);
pos = seq.init_rect(1,[2,1]) + floor(target_sz/2);
img_files = seq.s_frames;
video_path = [];
visualization = 0;

%call tracker function with all the relevant parameters
positions = tracker_ransac(video_path, img_files, pos, target_sz, ...
    padding, kernel, lambda, output_sigma_factor, interp_factor, ...
    cell_size, features, visualization);

%return results to benchmark, in a workspace variable
rects = [positions(:,2) - target_sz(2)/2, positions(:,1) - target_sz(1)/2];
rects(:,3) = target_sz(2);
rects(:,4) = target_sz(1);
res.type = 'rect';
res.res = rects;

end


function display(f,varargin)
% standard output

refSystems = [char(f.CS,'compact') ' ' getMTEXpref('arrowChar') ' ' char(f.SS,'compact')];

displayClass(f,inputname(1),varargin{:},'moreInfo',refSystems);

if length(f)~=1, disp([' size: ' size2str(f)]); end

% display symmetry
%dispLine(f.CS);
%dispLine(f.SS);

if f.antipodal, disp(' antipodal: true'); end
disp(' ');

if length(f)~=1, return; end

disp(['  h || r: ' char(round(f.h)) ' || (' char(round(f.r)) ')']);

% display starting and end orientation
if angle(f.o2,f.o1,'noSymmetry')>0
  disp([' o1 ' getMTEXpref('arrowChar') ' o2: ' char(f.o1) ' ' getMTEXpref('arrowChar') ' ' char(f.o2)]);
end

end


%MAXPOOLING implements a max-pooling operation for 4D tensors shaped as:
% (rows, cols, channels, samples) and returns the pooled data with the
% corresponding indices.
%
%   [m, idx] = MaxPooling(IM, [2 2])
%
% IM can also be a 2D tensor, the missing dims are set to 1.

% AUTORIGHTS
% Copyright (C) 2011 Jonathan Masci <jonathan@idsia.ch>
%
% This file is available under the terms of the
% GNU GPLv2.


function[]=yoffset(i1,i2)
%YOFFSET  Offsets lines in the y-direction after plotting.
%
%   YOFFSET allows data to be manipulated after it has been plotted, by
%   operating on the data stored in the figure itself.  This may be used
%   only with 2-D line plots (not symbol plots, contour plots, etc.).
%
%   YOFFSET offsets all lines in the current axes a specified amount.
%
%   YOFFSET(N) or YOFFSET N, where N is a *real* number, offsets each
%   column of the Y-data by an amount N from the previous column.  N must
%   be a number, not a variable whose value is a number.
%
%   YOFFSET(N) or YOFFSET N, where N is an *imaginary* number, offsets
%   each column of the Y-data by an amount imag(N)*DY from the previous
%   column, where DY is the Y-axis length of the original (unoffset) plot.
%
%   YOFFSET(M,N) or YOFFSET M N, applies the same offsets to each of M
%   groups of lines. For example, for complex-valued data Z use UVPLOT(Z)
%   followed by YOFFSET 2 N.
%
%   YOFFSET with no arguments returns the data to its original (unoffset)
%   orientation [as do YOFFSET(0) and YOFFSET(0i)].
%
%   YOFFSET also allow multiple axes to be manipulated simultaneously.
%
%   YOFFSET LOCK and YOFFSET UNLOCK lock and unlock all Y-data in the
%   current figure. When LOCK is on, calls to YOFFSET are applied to each
%   subplot individually.
%
%   See also YOFFSET, LINESTYLE.
%   __________________________________________________________________
%   This is part of JLAB --- type 'help jlab' for more information
%   (C) 2000--2015 J.M. Lilly --- type 'help jlab_license' for details

if strcmpi(i1,'--t')
    return
end

bcontinue=1;
if nargin==1;
  N=10000;  %Very large number of lines
end
if nargin==2
  N=i1;
  i1=i2;
  if ischar(N)
    N=str2double(N);
  end
end

if nargin>0
   if ischar(i1)
      if isempty(str2double(i1))
           i1=deblank(i1);
           i1=fliplr(deblank(fliplr(i1)));
           if strcmpi(i1,'lock')
               if isappdata(gca,'lastyoffset')
                    lastoff=getappdata(gca,'lastyoffset');
                    setappdata(gcf,'yoffsetlock',1)
                    yoffsetloop(0,N);
                    yoffsetloop(lastoff,N);
               else
                    setappdata(gcf,'yoffsetlock',1)
               end
               bcontinue=0;
           end
           if strcmpi(i1,'unlock')
               setappdata(gcf,'yoffsetlock',0)
               bcontinue=0;
           end
      end
   end
end

if bcontinue
   if nargin>0
      delta=i1;
   else
      delta=0;
   end

   h=linehandles;
   if plotmodified(h)
   %If the plot has been changed, the old "lastyoffset" may no
   %longer be correct.  If so, we set it to zero
       setappdata(gca,'lastyoffset',0)
   end
   yoffsetloop(delta,N);
end

function[]=yoffsetloop(delta,N)

h=gca;
if isappdata(gcf,'yoffsetlock')
   if getappdata(gcf,'yoffsetlock')
      h=axeshandles(gcf);
   end
end

for i=1:length(h)
    axes(h(i))
    if isappdata(gca,'lastyoffset')
       lastdelta=getappdata(gca,'lastyoffset');
       yoffsetapply(-1*lastdelta,N);
       setappdata(gca,'lastyoffset',0)
    end
    yoffsetapply(delta,N);
end

axes(h(1))

function[]=yoffsetapply(delta,N)
h=linehandles;

if ischar(delta),delta=str2double(delta);end
yy=get(h,{'ydata'});

if length(delta)==1 && ~isreal(delta)
   ax=axis;
   dy=ax(4)-ax(3);
   delta=dy.*imag(delta)/100;
end

if length(delta)==1
   for i=length(yy):-1:1
       yy{i}=yy{i}+delta*(mod(length(yy)-i,round(length(yy)/N)));
   end
elseif length(delta)==length(h)
   for i=length(yy):-1:1
       yy{i}=yy{i}+delta(i);
   end
else
   error('Number of line handles does not equal offset array length.')
end

set(h,{'ydata'},yy);
setappdata(gca,'lastyoffset',delta)
setappdata(gca,'lasthandles',h)

function[b]=plotmodified(h)
b=0;
if isappdata(gca,'lasthandles')
  b=1;
  h2=getappdata(gca,'lasthandles');
  if length(h2)==length(h)
      if all(h2==h)
          b=0;
      end
  end
end


function [LCpL,Q,sumLCpL,QE,Cy,M,Cp,Cq,Lq] = spm_eeg_assemble_priors(L,Qp,Qe,ploton,h)
% Predict sensor level impact of sources in Qp given sensor noise Qe
% FORMAT [LCpL,Q,sumLCpL,QE,Cy,M,Cp,Cq,Lq] = spm_eeg_assemble_priors(L,Qp,Qe,ploton,h)
% L       - lead fields
% Qp      - priors on source level dipole moment nAm/(mm2) per sample
% Qe      - sensor level variance in fT^2 per sample
% h       - optional hyperparameters that scale the variance components in
%           Qe and Qp (assume sensor followed by source level parameters)

% LCpL    - sensor level covariance components corresponding to the source
%           priors Qp
% Q       - sparse array over sources holding dipole moment density nAm/(mm2)
% sumLCpL - predicted sensor level variance due to sources (in fT^2)
% QE      - predicted sensor level noise variance (in fT^2)
% Cy      - total sensor noise covariance predicted : Cy = QE+sumLCpL
% M       - MAP estimator : M = Cp*L'*inv(Qe + L*Cp*L'))
% Cp      - total source covariance matrix
% Cq      - conditional source covariance - need to implement
% Lq      - cell array of the L*q (impact of each source component at sensor level)
%__________________________________________________________________________
% Copyright (C) 2010-2017 Wellcome Trust Centre for Neuroimaging

% Gareth Barnes
% $Id: spm_eeg_assemble_priors.m 7132 2017-07-10 16:22:58Z guillaume $

if nargin < 4
    ploton = ~spm('CmdLine');
end

if nargin < 5
    h=[];
end

Ne = length(Qe);
if iscell(Qp)
    Np = length(Qp); % number of source components
else
    Np = size(Qp,2);
end

if isempty(h)
    h = ones(Ne+Np,1);
end

if length(h)~=Ne+Np
    error('There must be as many hyperparameters as priors.');
end

he = h(1:Ne); % sensor level
hp = h(Ne + (1:Np)); % source level

Ns = size(L,2); % number sources

Q = sparse(Ns,Np);
Lq = {};

fprintf('Assembling %d prior components\n',Np);
for i = 1:Np
    if iscell(Qp)
        if isfield(Qp{i},'q')
            %Q(:,i) = Qp{i}.q; % patch amplitudes can be positive or negative
            q = Qp{i}.q;
            v = 1;
            if isfield(Qp{i},'v')
                v = sqrt(Qp{i}.v);
            end

            Q(:,i) = q*v;

            % Lq is the sensor level projection of the prior Q{i}.q
            Lq{i}.q = L*Q(:,i); %  supply an eigen mode in q
        else % no .q field, check it is 2D
            if size(Qp{i},1)~=size(Qp{i},2)
                disp('making Qp 2D');
                Qp{i} = diag(sparse(Qp{i}));
            end
        end
    end
end

%-Assemble empirical priors
%==========================================================================

LCpL  = {};

sumLCpL = zeros(size(L,1),size(L,1));

Cp  = sparse(0);
LCp = sparse(0);

for i = 1:Np

    if isfield(Qp{i},'q') % sparse diagonbal representation

        Q(:,i) = Q(:,i)*sqrt(hp(i)); % update moment by sqrt of variance scaling

        LQp = L*Q(:,i);
        LCpL{i} = LQp*LQp';
        Cp  = Cp + Q(:,i)*Q(:,i)'; %% Q is already scaled by root hp
        %LCp = LCp+LQp;
        LCp = LCp+L*Cp;
    else % full matrix version
        Qtmp = Qp{i}*hp(i);
        LCpL{i} = L*Qtmp*L';
        Cp  = Cp + Qtmp;
       % Q(:,i)=diag(Qtmp);
    end

    sumLCpL = sumLCpL + LCpL{i};

end

QE = zeros(size(Qe{1}));
for i=1:length(Qe)
    QE = QE + Qe{i}*he(i);
end

Cy = sumLCpL + QE;

% This is equivalent to M = Cp*UL'*inv(Qe + UL*Cp*UL'))
% with Cp the posterior source covariance (with optimal h values)
%Qsum=sum(Q(:,i).^2); % diagonal of posterior source cov matrix
%Cp=diag(Qsum);
M = Cp*L'/Cy;

% conditional variance (leading diagonal)
% Cq    = Cp - Cp*L'*iC*L*Cp;
%----------------------------------------------------------------------
%Cq    = Cp - sum(LCp.*M')'; in original

Cq = diag(Cp) - sum(LCp.*M')';

disp('end assemble');

if ploton
    subplot(3,1,1);
    imagesc(sumLCpL);colorbar;
    title('source prior');
    subplot(3,1,2);
    imagesc(QE);colorbar;
    title('sensor noise prior');
    subplot(3,1,3);
    imagesc(Cy);colorbar;
    title('Sensor covariance per sample (fT^2)');
end


function cS = rutile

%
cs_Rt = crystalSymmetry('4/mmm',[1 1 0.644]);
N = Miller({1,0,0},{1,1,0},{1,0,1},cs_Rt);
dist= [0.35, 0.5, 1];
cS = crystalShape(N./dist);