function gpcf = gpcf_squared(varargin)
%GPCF_SQUARED  Create a squared (dot product) covariance function
%
%  Description
%    GPCF = GPCF_SQUARED('PARAM1',VALUE1,'PARAM2,VALUE2,...) creates
%    a squared (dot product) covariance function structure in which
%    the named parameters have the specified values. Any unspecified
%    parameters are set to default values. The squared covariance function
%    corresponds to x.^2 mean function and the respective covariance matrix
%    is given as C = x.^2*diag(gpcf.coeffSigma2)*(x'.^2);
%
%    GPCF = GPCF_SQUARED(GPCF,'PARAM1',VALUE1,'PARAM2,VALUE2,...)
%    modify a covariance function structure with the named
%    parameters altered with the specified values.
%
%    Parameters for squared (dot product) covariance function
%      interactions      - twoway interactions (default off)
%      coeffSigma2       - prior variance for regressor coefficients [10]
%                          This can be either scalar corresponding
%                          to a common prior variance or vector
%                          defining own prior variance for each
%                          coefficient.
%      coeffSigma2_prior - prior structure for coeffSigma2 [prior_logunif]
%      selectedVariables - vector defining which inputs are used [all]
%
%    Note! If the prior is 'prior_fixed' then the parameter in
%    question is considered fixed and it is not handled in
%    optimization, grid integration, MCMC etc.
%
%  See also
%    GP_SET, GPCF_*, PRIOR_*, MEAN_*
%
% Copyright (c) 2007-2016 Jarno Vanhatalo
% Copyright (c) 2008-2010 Jaakko Riihimäki
% Copyright (c) 2010 Aki Vehtari
% Copyright (c) 2014 Arno Solin

% This software is distributed under the GNU General Public
% License (version 3 or later); please refer to the file
% License.txt, included with the software, for details.

  ip=inputParser;
  ip.FunctionName = 'GPCF_SQUARED';
  ip.addOptional('gpcf', [], @isstruct);
  ip.addParamValue('interactions', 'off', @(x) ismember(x,{'on' 'off'}))
  ip.addParamValue('coeffSigma2',10, @(x) isvector(x) && all(x>0));
  ip.addParamValue('coeffSigma2_prior',prior_logunif, @(x) isstruct(x) || isempty(x));
  ip.addParamValue('selectedVariables',[], @(x) isvector(x) && all(x>0));
  ip.parse(varargin{:});
  gpcf=ip.Results.gpcf;

  if isempty(gpcf)
    init=true;
    gpcf.type = 'gpcf_squared';
  else
    if ~isfield(gpcf,'type') && ~isequal(gpcf.type,'gpcf_squared')
      error('First argument does not seem to be a valid covariance function structure')
    end
    init=false;
  end

  if init || ~ismember('interactions',ip.UsingDefaults)
    gpcf.interactions=ip.Results.interactions;
  end

  % Initialize parameter
  if init || ~ismember('coeffSigma2',ip.UsingDefaults)
    gpcf.coeffSigma2=ip.Results.coeffSigma2;
  end

  % Initialize prior structure
  if init
    gpcf.p=[];
  end
  if init || ~ismember('coeffSigma2_prior',ip.UsingDefaults)
    gpcf.p.coeffSigma2=ip.Results.coeffSigma2_prior;
  end
  if ~ismember('selectedVariables',ip.UsingDefaults)
    selectedVariables=ip.Results.selectedVariables;
    if ~isempty(selectedVariables)
      gpcf.selectedVariables = selectedVariables;
    end
  end

  if init
    % Set the function handles to the subfunctions
    gpcf.fh.pak = @gpcf_squared_pak;
    gpcf.fh.unpak = @gpcf_squared_unpak;
    gpcf.fh.lp = @gpcf_squared_lp;
    gpcf.fh.lpg = @gpcf_squared_lpg;
    gpcf.fh.cfg = @gpcf_squared_cfg;
    gpcf.fh.cfdg = @gpcf_squared_cfdg;
    gpcf.fh.cfdg2 = @gpcf_squared_cfdg2;
    gpcf.fh.ginput = @gpcf_squared_ginput;
    gpcf.fh.ginput2 = @gpcf_squared_ginput2;
    gpcf.fh.ginput3 = @gpcf_squared_ginput3;
    gpcf.fh.ginput4 = @gpcf_squared_ginput4;
    gpcf.fh.cov = @gpcf_squared_cov;
    gpcf.fh.trcov  = @gpcf_squared_trcov;
    gpcf.fh.trvar  = @gpcf_squared_trvar;
    gpcf.fh.recappend = @gpcf_squared_recappend;
    gpcf.fh.cf2ss = @gpcf_squared_cf2ss;
  end

end

function [w, s, h] = gpcf_squared_pak(gpcf, w)
%GPCF_squared_PAK  Combine GP covariance function parameters into one vector
%
%  Description
%    W = GPCF_squared_PAK(GPCF) takes a covariance function
%    structure GPCF and combines the covariance function
%    parameters and their hyperparameters into a single row
%    vector W. This is a mandatory subfunction used for
%    example in energy and gradient computations.
%
%       w = [ log(gpcf.coeffSigma2)
%             (hyperparameters of gpcf.coeffSigma2)]'
%
%  See also
%    GPCF_squared_UNPAK

  w = []; s = {}; h =[];
  if ~isempty(gpcf.p.coeffSigma2)
    w = log(gpcf.coeffSigma2);
    if numel(gpcf.coeffSigma2)>1
      s = [s; sprintf('log(squared.coeffSigma2 x %d)',numel(gpcf.coeffSigma2))];
    else
      s = [s; 'log(squared.coeffSigma2)'];
    end
    h = [h ones(1, numel(gpcf.coeffSigma2))];
    % Hyperparameters of coeffSigma2
    [wh, sh, hh] = gpcf.p.coeffSigma2.fh.pak(gpcf.p.coeffSigma2);
    sh=strcat(repmat('prior-', size(sh,1),1),sh);
    w = [w wh];
    s = [s; sh];
    h = [h 1+hh];
  end
end

function [gpcf, w] = gpcf_squared_unpak(gpcf, w)
%GPCF_squared_UNPAK  Sets the covariance function parameters
%                   into the structure
%
%  Description
%    [GPCF, W] = GPCF_squared_UNPAK(GPCF, W) takes a covariance
%    function structure GPCF and a hyper-parameter vector W, and
%    returns a covariance function structure identical to the
%    input, except that the covariance hyper-parameters have been
%    set to the values in W. Deletes the values set to GPCF from
%    W and returns the modified W. This is a mandatory subfunction
%    used for example in energy and gradient computations.
%
%    Assignment is inverse of
%       w = [ log(gpcf.coeffSigma2)
%             (hyperparameters of gpcf.coeffSigma2)]'
%
%  See also
%   GPCF_squared_PAK

  gpp=gpcf.p;

  if ~isempty(gpp.coeffSigma2)
    i2=length(gpcf.coeffSigma2);
    i1=1;
    gpcf.coeffSigma2 = exp(w(i1:i2));
    w = w(i2+1:end);

    % Hyperparameters of coeffSigma2
    [p, w] = gpcf.p.coeffSigma2.fh.unpak(gpcf.p.coeffSigma2, w);
    gpcf.p.coeffSigma2 = p;
  end
end

function lp = gpcf_squared_lp(gpcf)
%GPCF_squared_LP  Evaluate the log prior of covariance function parameters
%
%  Description
%    LP = GPCF_squared_LP(GPCF) takes a covariance function
%    structure GPCF and returns log(p(th)), where th collects the
%    parameters. This is a mandatory subfunction used for example
%    in energy computations.
%
%  See also
%   GPCF_squared_PAK, GPCF_squared_UNPAK, GPCF_squared_LPG, GP_E

% Evaluate the prior contribution to the error. The parameters that
% are sampled are from space W = log(w) where w is all the "real" samples.
% On the other hand errors are evaluated in the W-space so we need take
% into account also the  Jacobian of transformation W -> w = exp(W).
% See Gelman et al. (2013), Bayesian Data Analysis, third edition, p. 21.
  lp = 0;
  gpp=gpcf.p;

  if ~isempty(gpp.coeffSigma2)
    lp = gpp.coeffSigma2.fh.lp(gpcf.coeffSigma2, gpp.coeffSigma2) + sum(log(gpcf.coeffSigma2));
  end
end

function lpg = gpcf_squared_lpg(gpcf)
%GPCF_squared_LPG  Evaluate gradient of the log prior with respect
%                 to the parameters.
%
%  Description
%    LPG = GPCF_squared_LPG(GPCF) takes a covariance function
%    structure GPCF and returns LPG = d log (p(th))/dth, where th
%    is the vector of parameters. This is a mandatory subfunction
%    used for example in gradient computations.
%
%  See also
%    GPCF_squared_PAK, GPCF_SQUARED_UNPAK, GPCF_SQUARED_LP, GP_G

  lpg = [];
  gpp=gpcf.p;

  if ~isempty(gpcf.p.coeffSigma2)
    lll=length(gpcf.coeffSigma2);
    lpgs = gpp.coeffSigma2.fh.lpg(gpcf.coeffSigma2, gpp.coeffSigma2);
    lpg = [lpg lpgs(1:lll).*gpcf.coeffSigma2+1 lpgs(lll+1:end)];
  end
end

function DKff = gpcf_squared_cfg(gpcf, x, x2, mask, i1)
%GPCF_SQUARED_CFG  Evaluate gradient of covariance function
%                 with respect to the parameters
%
%  Description
%    DKff = GPCF_SQUARED_CFG(GPCF, X) takes a covariance function
%    structure GPCF, a matrix X of input vectors and returns
%    DKff, the gradients of covariance matrix Kff = k(X,X) with
%    respect to th (cell array with matrix elements). This is a
%    mandatory subfunction used in gradient computations.
%
%    DKff = GPCF_SQUARED_CFG(GPCF, X, X2) takes a covariance
%    function structure GPCF, a matrix X of input vectors and
%    returns DKff, the gradients of covariance matrix Kff =
%    k(X,X2) with respect to th (cell array with matrix
%    elements). This subfunction is needed when using sparse
%    approximations (e.g. FIC).
%
%    DKff = GPCF_SQUARED_CFG(GPCF, X, [], MASK) takes a covariance
%    function structure GPCF, a matrix X of input vectors and
%    returns DKff, the diagonal of gradients of covariance matrix
%    Kff = k(X,X2) with respect to th (cell array with matrix
%    elements). This subfunction is needed when using sparse
%    approximations (e.g. FIC).
%
%    DKff = GPCF_SQUARED_CFG(GPCF,X,X2,MASK,i) takes a covariance
%    function structure GPCF, a matrix X of input vectors and
%    returns DKff, the gradient of covariance matrix Kff =
%    k(X,X2), or k(X,X) if X2 is empty, with respect to ith
%    hyperparameter. This subfunction is needed when using
%    memory save option in gp_set.
%
%  See also
%   GPCF_SQUARED_PAK, GPCF_SQUARED_UNPAK, GPCF_SQUARED_LP, GP_G

  if nargin>2 && ~isempty(x2)
      if size(x,2) ~= size(x2,2)
          error('gpcf_squared -> _cfg: the number of columns of X1 and X2 has to be same')
      end
  end

  if isfield(gpcf, 'selectedVariables')
      x = x(:,gpcf.selectedVariables);
  end
  [n, m] =size(x);
  h = x.^2;
  if isequal(gpcf.interactions,'on')
      for xi1=1:m
          for xi2=xi1+1:m
              h = [h x(:,xi1).*x(:,xi2)];
          end
      end
  end

  DKff = {};

  if nargin==5
    % Use memory save option
    savememory=1;
    if i1==0
      % Return number of hyperparameters
      DKff=0;
      if ~isempty(gpcf.p.coeffSigma2)
        DKff=length(gpcf.coeffSigma2);
      end
      return
    end
  else
    savememory=0;
  end

  % Evaluate: DKff{1} = d Kff / d coeffSigma2
  % NOTE! Here we have already taken into account that the parameters are transformed
  % through log() and thus dK/dlog(p) = p * dK/dp

  % evaluate the gradient for training covariance
  if nargin == 2 || (isempty(x2) && isempty(mask))

      if ~isempty(gpcf.p.coeffSigma2)
          if length(gpcf.coeffSigma2) == 1
              DKff{1}=gpcf.coeffSigma2*h*(h');
          else
              if isa(gpcf.coeffSigma2,'single')
                  epsi=eps('single');
              else
                  epsi=eps;
              end
              if ~savememory
                  i1=1:length(gpcf.coeffSigma2);
              end
              DKff=cell(1,length(i1));
              for ii1=i1
                  DD = gpcf.coeffSigma2(ii1)*h(:,ii1)*(h(:,ii1)');
                  DD(abs(DD)<=epsi) = 0;
                  DKff{ii1}= (DD+DD')./2;
              end
          end
      end

    % Evaluate the gradient of non-symmetric covariance (e.g. K_fu)
  elseif nargin == 3 || isempty(mask)

      error('this part of the subfunction has not been tested')

      if isfield(gpcf, 'selectedVariables')
          x2 = x2(:,gpcf.selectedVariables);
      end
      h2 = x2.^2;
      if isequal(gpcf.interactions,'on')
          for xi1=1:m
              for xi2=xi1+1:m
                  h2 = [h2 x2(:,xi1).*x2(:,xi2)];
              end
          end
      end

      if ~isempty(gpcf.p.coeffSigma2)
          if length(gpcf.coeffSigma2) == 1
              DKff{1}=gpcf.coeffSigma2*h*(h2');
          else
              if ~savememory
                  i1=1:m;
              end
              for ii1=i1
                  DKff{ii1}=gpcf.coeffSigma2(ii1)*h(:,ii1)*(h2(:,ii1)');
              end
          end
      end
      % Evaluate: DKff{1}    = d mask(Kff,I) / d coeffSigma2
    %           DKff{2...} = d mask(Kff,I) / d coeffSigma2
  elseif nargin == 4 || nargin == 5

      error('this part of the subfunction has not been tested')

      if ~isempty(gpcf.p.coeffSigma2)
        if length(gpcf.coeffSigma2) == 1
          DKff{1}=gpcf.coeffSigma2*sum(h.^2,2); % d mask(Kff,I) / d coeffSigma2
        else
          if ~savememory
            i1=1:m;
          end
          for ii1=i1
            DKff{ii1}=gpcf.coeffSigma2(ii1)*(h(:,ii1).^2); % d mask(Kff,I) / d coeffSigma2
          end
        end
      end
  end
  if savememory
    DKff=DKff{i1};
  end
end

function DKff = gpcf_squared_cfdg(gpcf, x, x2, dims)
%GPCF_SQUARED_CFDG  Evaluate gradient of covariance function, of
%                  which has been taken partial derivative with
%                  respect to x, with respect to parameters.
%
%  Description
%    DKff = GPCF_SQUARED_CFDG(GPCF, X) takes a covariance function
%    structure GPCF, a matrix X of input vectors and returns
%    DKff, the gradients of derivatived covariance matrix
%    dK(df,f)/dhyp = d(d k(X,X)/dx)/dhyp, with respect to the
%    parameters
%
%    Evaluate: DKff{1:m} = d Kff / d coeffSigma2
%    m is the dimension of inputs. This subfunction is needed when using
%    derivative observations.
%
%    Note! When coding the derivatives of the covariance function, remember
%    to double check them. See gp_cov for lines of code to check the
%    matrices
%
%  See also
%    GPCF_SQUARED_GINPUT

[~,m]=size(x);
if nargin<3
    x2=x;
end
if nargin < 4 || isempty(dims)
    dims = 1:m;
end
ii1=0;
DKff={};
if isfield(gpcf,'selectedVariables')
    selVars = gpcf.selectedVariables;
else
    selVars = 1:m;
end
c = gpcf.coeffSigma2;

h = x.^2;
h2 = x2.^2;

ii1=0;
DKff={};
if ~isempty(gpcf.p.coeffSigma2)
  if length(gpcf.coeffSigma2)==1
    % One coeffSigma2
    for i1=dims
      if isfield(gpcf, 'selectedVariables') && sum(gpcf.selectedVariables==i1)==0
        DK{i1}=zeros(size(x,1),size(x2,1));
      else
        DK{i1}=c(1).*2*x(:,i1)*h2(:,i1)';
        if isequal(gpcf.interactions,'on')
            for xi2=selVars
                if xi2~=i1
                    DK{i1} = DK{i1} + c(1)*x(:,xi2)*(x2(:,i1).*x2(:,xi2))';
                end
            end
        end
      end
    end
    ii1=ii1+1;
    DKff{ii1}=cat(1,DK{1:end});
  else
      % vector of coeffSigma2s
      for i1=1:length(selVars)
          for j=dims
              if selVars(i1)~=j %|| (isfield(gpcf, 'selectedVariables') && sum(gpcf.selectedVariables==i1)==0)
                  DK{j}=zeros(size(x,1),size(x2,1));
              else
                  DK{j}=c(i1).*2*x(:,j)*h2(:,j)';
              end
          end
          ii1=ii1+1;
          DKff{ii1}=cat(1,DK{1:end});
      end
      if isequal(gpcf.interactions,'on')
          for xi1=1:length(selVars)
              for xi2=xi1+1:length(selVars)
                  i1=i1+1;
                  for j=dims
                      if j==xi1
                          DK{j} = c(i1)*x(:,xi2)*(x2(:,xi1).*x2(:,xi2))';
                      elseif j==xi2
                          DK{j} = c(i1)*x(:,xi1)*(x2(:,xi1).*x2(:,xi2))';
                      else
                          DK{j}=zeros(size(x,1),size(x2,1));
                      end
                  end
                  ii1=ii1+1;
                  DKff{ii1}=cat(1,DK{1:end});
              end
          end
      end
  end
end

end

function DKff = gpcf_squared_cfdg2(gpcf, x, x2, dims1, dims2)
%GPCF_SQUARED_CFDG2  Evaluate gradient of covariance function, of which has
%                    been taken partial derivatives with respect to both
%                    input variables x, with respect to parameters.
%
%  Description
%    DKff = GPCF_SQUARED_CFDG2(GPCF, X) takes a covariance
%    function structure GPCF, a matrix X of input vectors and
%    returns DKff, the gradients of derivative covariance matrix
%    dK(df,df)/dhyp = d(d^2 k(X1,X2)/dX1dX2)/dhyp with respect to
%    the parameters
%
%    Evaluate: DKff{1:m} = d K(df,df) / d coeffSigma
%    m is the dimension of inputs.  This subfunction is needed when using
%    derivative observations.
%
%    Note! When coding the derivatives of the covariance function, remember
%    to double check them. See gp_cov for lines of code to check the
%    matrices
%
%  See also
%   GPCF_SQUARED_GINPUT, GPCF_SQUARED_GINPUT2

[~, m] =size(x);
if nargin <3 || isempty(x2)
    x2=x;
end
if nargin < 4 || isempty(dims1)
    %dims1 = 1:m;
    error('dims1 needs to be given')
end
if nargin < 5 || isempty(dims2)
    %dims2 = 1:m;
    error('dims2 needs to be given')
end
if isfield(gpcf,'selectedVariables')
    selVars = gpcf.selectedVariables;
else
    selVars = 1:m;
end
% NOTICE. AS OF NOW we assume that dims1 and dims2 are scalars

ii1=0;
if length(gpcf.coeffSigma2)==1
    c=repmat(gpcf.coeffSigma2,1,(1+length(selVars))*length(selVars)/2);
else
    c=gpcf.coeffSigma2;
end
if length(gpcf.coeffSigma2)==1
    % One coeffSigma2
    if dims1~=dims2 %|| (isfield(gpcf, 'selectedVariables') && (sum(gpcf.selectedVariables==j)==0 || sum(gpcf.selectedVariables==k)==0))
        DK=zeros(size(x,1),size(x2,1));
        if isequal(gpcf.interactions,'on') && (sum(selVars==dims1)>0 || sum(selVars==dims2)>0)
            DK = c(1)*x(:,dims1)*x2(:,dims2)';
        end
    else
        if sum(selVars==dims1)==0
            DK=zeros(size(x,1),size(x2,1));
        else
            DK=c(1).*4.*x(:,dims1)*x2(:,dims2)';
        end
        if isequal(gpcf.interactions,'on') && sum(selVars==dims1)>0
            for xi2=selVars
                if xi2~=dims1
                    DK = DK + c(1)*x(:,xi2)*x2(:,xi2)';
                end
            end
        end
    end
    ii1=ii1+1;
    DKff{ii1}=DK;
else
    % vector of coeffSigma2s
    for i1=1:length(selVars)
        if dims1~=dims2 || dims2~=selVars(i1)
            DK=zeros(size(x,1),size(x2,1));
        else
            DK=c(i1).*4.*x(:,dims1)*x2(:,dims2)';
        end
        ii1=ii1+1;
        DKff{ii1}=DK;
    end
    if isequal(gpcf.interactions,'on')
        for xi1=1:length(selVars)
            for xi2=xi1+1:length(selVars)
                i1=i1+1;
                %if k==xi1 && j==xi2
                if dims1==xi1 && dims2==xi2
                    DK = c(i1)*x(:,xi2)*x2(:,xi1)';
                %elseif k==xi2 && j==xi1
                elseif dims1==xi2 && dims2==xi1
                    DK = c(i1)*x(:,xi1)*x2(:,xi2)';
                %elseif k==j && k==xi1
                elseif dims1==dims2 && dims1==xi1
                    DK = c(i1)*x(:,xi2)*x2(:,xi2)';
                %elseif k==j && k==xi2
                elseif dims1==dims2 && dims1==xi2
                    DK = c(i1)*x(:,xi1)*x2(:,xi1)';
                else
                    DK=zeros(size(x,1),size(x2,1));
                end
                ii1=ii1+1;
                DKff{ii1}=DK;
            end
        end
    end
end

end

function DKff = gpcf_squared_ginput(gpcf, x, x2, i1)
%GPCF_SQUARED_GINPUT  Evaluate gradient of covariance function with
%                    respect to x.
%
%  Description
%    DKff = GPCF_SQUARED_GINPUT(GPCF, X, X2) takes a covariance function
%    structure GPCF, a matrix X of input vectors and returns DKff, the
%    gradients of covariance matrix Kff = k(X,X2) with respect to X (cell
%    array with matrix elements). If called with only two inputs
%    GPCF_SQUARED_GINPUT(GPCF, X), X2=X. This subfunction is needed when
%    computing gradients with respect to inducing inputs in sparse
%    approximations.
%
%    DKff = GPCF_SQUARED_GINPUT(GPCF, X, X2, i) takes a covariance
%    function structure GPCF, a matrix X of input vectors and
%    returns DKff, the gradients of covariance matrix Kff =
%    k(X,X2) with respect to ith covariate in X (matrix).
%    This subfunction is needed when using memory save option
%    in gp_set.
%
%    Note! When coding the derivatives of the covariance function, remember
%    to double check them. See gp_cov for lines of code to check the
%    matrices
%
%  See also
%   GPCF_SQUARED_PAK, GPCF_SQUARED_UNPAK, GPCF_SQUARED_LP, GP_G

if isfield(gpcf, 'selectedVariables')
    error('The selectedVariables option has not yet been implemented for gpcf_squared with derivobs=''on'' ')
    % notice, some parts of the code already take into account the
    % selectedVariables but the code has not been checked
end

[n, m] =size(x);

if nargin==4
    % Use memory save option
    savememory=1;
    if i1==0
        % Return number of covariates
        DKff=m;
        return
    end
else
    savememory=0;
end

if nargin == 2 || isempty(x2)

    xx = x.^2;
    if length(gpcf.coeffSigma2)==1
        s=gpcf.coeffSigma2.*ones(1,(1+m)*m/2);
    else
        s=gpcf.coeffSigma2;
    end
    ii1 = 0;
    if nargin<4
        i1=1:m;
    end
    for j = 1:n
        for i=i1
            DK = zeros(n);
            DK(j,:)=2*s(i)*x(j,i)*xx(:,i)';
            if isequal(gpcf.interactions,'on')
                for xi2=i1
                    if xi2~=i
                        DK(j,:) = DK(j,:) + s(i)*x(j,xi2).*(x(:,i).*x(:,xi2))';
                    end
                end
            end
            DK = DK + DK';
            ii1 = ii1 + 1;
            DKff{ii1} = DK;
        end
    end

elseif nargin == 3 || nargin == 4

    xx2 = x2.^2;
    if length(gpcf.coeffSigma2)==1
        s=gpcf.coeffSigma2.*ones(1,(1+m)*m/2);
    else
        s=gpcf.coeffSigma2;
    end
    ii1 = 0;
    if ~savememory
        i1=1:m;
    end
    for j = 1:n
        for i=i1
            DK = zeros(n, size(x2,1));
            DK(j,:)=2*s(i)*x(j,i)*xx2(:,i)';
            if isequal(gpcf.interactions,'on')
                for xi2=i1
                    if xi2~=i
                        DK(j,:) = DK(j,:) + s(i)*x(j,xi2).*(x2(:,i).*x2(:,xi2))';
                    end
                end
            end
            ii1 = ii1 + 1;
            DKff{ii1} = DK;
        end
    end
end

end

function DKff = gpcf_squared_ginput2(gpcf, x, x2, dims,takeOnlyDiag)
%GPCF_SQUARED_GINPUT2  Evaluate gradient of covariance function with
%                   respect to both input variables x and x2 in
%                   same dimension.
%
%  Description
%    DKff = GPCF_SQUARED_GINPUT2(GPCF, X, X2) takes a covariance
%    function structure GPCF, a matrix X of input vectors and
%    returns DKff, the gradients of twice derivatived covariance
%    matrix K(df,df) = dk(X1,X2)/dX1dX2 (cell array with matrix
%    elements). Input variable's dimensions are expected to be
%    same.  This subfunction is needed when using derivative
%    observations.
%
%    Note! When coding the derivatives of the covariance function, remember
%    to double check them. See gp_cov for lines of code to check the
%    matrices
%
%  See also
%    GPCF_SQUARED_GINPUT, GPCF_SQUARED_GINPUT2, GPCF_SQUARED_CFDG2

[~,m]=size(x);
ii1=0;
if nargin<4 || isempty(dims)
    dims=1:m;
end
if length(gpcf.coeffSigma2)==1
    c=repmat(gpcf.coeffSigma2,1,(1+m)*m/2);
else
    c=gpcf.coeffSigma2;
end
if isfield(gpcf, 'selectedVariables')
    sv = gpcf.selectedVariables;
else
    sv = 1:m;
end

if nargin==5 && isequal(takeOnlyDiag,'takeOnlyDiag')
    for i1=dims
        if ~any(sv==i1)%isfield(gpcf, 'selectedVariables') && sum(gpcf.selectedVariables==i1)==0
            DK=zeros(size(x,1),1);
        else
            DK=c(i1).*4.*(x(:,i1).*x2(:,i1));
            if isequal(gpcf.interactions,'on')
                i2=length(sv);
                for xi1=1:length(sv)
                    for xi2=xi1+1:length(sv)
                        if any(sv==xi1) && any(sv==xi2)
                            i2=i2+1;
                            if i1==xi1
                                DK = DK + c(i2)*x(:,xi2).*x2(:,xi2);
                            elseif i1==xi2
                                DK = DK + c(i2)*x(:,xi1).*x2(:,xi1);
                            end
                        end
                    end
                end
            end
        end
        ii1=ii1+1;
        DKff{ii1}=DK;
    end
else
    for i1=dims
        if ~any(sv==i1)%isfield(gpcf, 'selectedVariables') && sum(gpcf.selectedVariables==i1)==0
            DK=zeros(size(x,1),size(x2,1));
        else
            DK=c(i1).*4.*(x(:,i1)*x2(:,i1)');
            if isequal(gpcf.interactions,'on')
                i2=length(sv);
                for xi1=1:length(sv)
                    for xi2=xi1+1:length(sv)
                        if any(sv==xi1) && any(sv==xi2)
                            i2=i2+1;
                            if i1==xi1
                                DK = DK + c(i2)*x(:,xi2)*x2(:,xi2)';
                            elseif i1==xi2
                                DK = DK + c(i2)*x(:,xi1)*x2(:,xi1)';
                            end
                        end
                    end
                end
            end
        end
        ii1=ii1+1;
        DKff{ii1}=DK;
    end
end
end

function DKff = gpcf_squared_ginput3(gpcf, x, x2, dims1, dims2)
%GPCF_SQUARED_GINPUT3  Evaluate gradient of covariance function with
%                   respect to both input variables x and x2 (in
%                   different dimensions).
%
%  Description
%    DKff = GPCF_SQUARED_GINPUT3(GPCF, X, X2) takes a covariance
%    function structure GPCF, a matrix X of input vectors and
%    returns DKff, the gradients of twice derivatived covariance
%    matrix K(df,df) = dk(X1,X2)/dX1dX2 (cell array with matrix
%    elements). The derivative is calculated in multidimensional
%    problem between input's observation dimensions which are not
%    same. This subfunction is needed when using derivative
%    observations.
%
%    DKff is a cell array with the following elements:
%      DKff{1} = dk(X1,X2)/dX1_1dX2_2
%      DKff{2} = dk(X1,X2)/dX1_1dX2_3
%       ...
%      DKff{m-1} = dk(X1,X2)/dX1_1dX2_m
%      DKff{m} = dk(X1,X2)/dX1_2dX2_3
%       ...
%      DKff{m} = dk(X1,X2)/dX1_(m-1)dX2_m
%    where _m denotes the input dimension with respect to which the
%    gradient is calculated.
%
%    Note! When coding the derivatives of the covariance function, remember
%    to double check them. See gp_cov for lines of code to check the
%    matrices
%
%  See also
%    GPCF_SQUARED_GINPUT, GPCF_SQUARED_GINPUT2, GPCF_SQUARED_CFDG2

[~,m]=size(x);
if nargin < 3
    error('Needs at least 3 input arguments')
end
if nargin<4 || isempty(dims1)
    dims1=1:m;
end
if nargin<5 || isempty(dims2)
    dims2=1:m;
end
if isfield(gpcf, 'selectedVariables')
    sv = gpcf.selectedVariables;
else
    sv = 1:m;
end

ii1=0;
if length(gpcf.coeffSigma2)==1
  c=repmat(gpcf.coeffSigma2,1,(1+m)*m/2);
else
  c=gpcf.coeffSigma2;
end
DK=zeros(size(x,1),size(x2,1));
i2=m;
for i=dims1
    for j=dims2
        ii1=ii1+1;
        if isequal(gpcf.interactions,'on') && any(sv==i) && any(sv==j)
            i2 = min(i,j)*length(sv) - 0.5*min(i,j)*(min(i,j)-1) + max(i,j)-min(i,j);
            DKff{ii1} = c(i2)*x(:,j)*x2(:,i)';
        else
            DKff{ii1}=DK;
        end
    end
end

% i2=m;
% for i=1:m-1
%     for j=i+1:m
%         i2=i2+1;
%         if any(dims1==i) && any(dims2==j)
%             ii1=ii1+1;
%             if isequal(gpcf.interactions,'on') && any(sv==i) && any(sv==j)
% %             if isequal(gpcf.interactions,'on') &&...
% %                     ~(isfield(gpcf, 'selectedVariables') && (sum(gpcf.selectedVariables==i)==0 || sum(gpcf.selectedVariables==j)==0))
%                 DKff{ii1} = c(i2)*x(:,j)*x2(:,i)';
%             else
%                 DKff{ii1}=DK;
%             end
%         end
%     end
% end

end

function DKff = gpcf_squared_ginput4(gpcf, x, x2, dims)
%GPCF_SQUARED_GINPUT  Evaluate gradient of covariance function with respect
%                    to x. Simplified and faster version of squared_ginput,
%                    returns full matrices.
%
%  Description
%    DKff = GPCF_SQUARED_GINPUT4(GPCF, X, X2) takes a covariance function
%    structure GPCF, matrices X and X2 of input vectors and returns DKff,
%    the gradients of covariance matrix Kff = k(X,X2) with respect to X
%    (whole matrix); that is d k(X,X2)/dX. If called with only two inputs
%    GPCF_SQUARED_GINPUT4(GPCF, X), X2=X.
%
%    This subfunction is needed when using derivative observations.
%
%    Note! When coding the derivatives of the covariance function, remember
%    to double check them. See gp_cov for lines of code to check the
%    matrices
%
%  See also
%    GPCF_SQUARED_PAK, GPCF_SQUARED_UNPAK, GPCF_SQUARED_LP, GP_G

% if isfield(gpcf, 'selectedVariables')
%     error('The selectedVariables option has not yet been implemented for gpcf_squared with derivobs=''on'' ')
%     % notice, some parts of the code already take into account the
%     % selectedVariables but the code has not been checked
% end
%
% if isfield(gpcf, 'selectedVariables')
%     m = length(gpcf.selectedVariables);
%     sv = gpcf.selectedVariables;
% else
%     [~,m]=size(x);
%     sv = 1:m;
% end
% if nargin==2
%     x2=x;
% end
% if nargin<4
%     dims=1:size(x,2);
% end
% if length(gpcf.coeffSigma2)==1
%     c=repmat(gpcf.coeffSigma2,1,(1+m)*m/2);
% else
%     % If coeffSigma is vector, we trust it is of rigth length
%     c=gpcf.coeffSigma2;
% end
% h2=x2.^2;
% ii1=0;
% for i=dims
%     if ~any(sv==i) %isfield(gpcf, 'selectedVariables') && sum(gpcf.selectedVariables==i)==0
%         DK=zeros(size(x,1),size(x2,1));
%     else
%         DK=c(i).*2.*x(:,i)*h2(:,i)';
%         if isequal(gpcf.interactions,'on')
%             i2=m;
%             for xi1=sv
%                 sv2 = sv(sv>xi1);
%                 for xi2=sv2 %xi1+1:m
%                     i2 = i2+1;
%                     if i==xi1
%                         DK = DK + c(i2)*x(:,xi2)*(x2(:,i).*x2(:,xi2))';
%                     elseif i==xi2
%                         DK = DK + c(i2)*x(:,xi1)*(x2(:,i).*x2(:,xi1))';
%                     end
%                 end
%             end
%         end
%     end
%     ii1=ii1+1;
%     DKff{ii1}=DK;
% end

[n,m]=size(x);
if nargin<4
    dims=1:m;
end
if isfield(gpcf, 'selectedVariables')
    sv = gpcf.selectedVariables;
else
    sv = 1:m;
end
ii1=0;
if nargin==2
    x2=x;
end
h2=x2.^2;
if length(gpcf.coeffSigma2)==1
    c=repmat(gpcf.coeffSigma2,1,(1+m)*m/2);
else
    c=gpcf.coeffSigma2;
end
for i=dims
    if ~any(sv==i) % isfield(gpcf, 'selectedVariables') && sum(gpcf.selectedVariables==i)==0
        DK=zeros(size(x,1),size(x2,1));
    else
        DK=c(i).*2.*x(:,i)*h2(:,i)';
        if isequal(gpcf.interactions,'on')
            i2=length(sv);
            for xi1=1:length(sv)
                for xi2=xi1+1:length(sv)
                    if any(sv==xi1) && any(sv==xi2)
                        i2=i2+1;
%                        i2 = min(i,j)*length(sv) - 0.5*min(i,j)*(min(i,j)-1) + max(i,j)-min(i,j)
                        if i==xi1
                            DK = DK + c(i2)*x(:,xi2)*(x2(:,i).*x2(:,xi2))';
                        elseif i==xi2
                            DK = DK + c(i2)*x(:,xi1)*(x2(:,i).*x2(:,xi1))';
                        end
                    end
                end
            end
        end
    end
    ii1=ii1+1;
    DKff{ii1}=DK;
end
end

function C = gpcf_squared_cov(gpcf, x1, x2, varargin)
%GP_SQUARED_COV  Evaluate covariance matrix between two input vectors
%
%  Description
%    C = GP_SQUARED_COV(GP, TX, X) takes in covariance function of
%    a Gaussian process GP and two matrixes TX and X that contain
%    input vectors to GP. Returns covariance matrix C. Every
%    element ij of C contains covariance between inputs i in TX
%    and j in X. This is a mandatory subfunction used for example in
%    prediction and energy computations.
%
%  See also
%    GPCF_SQUARED_TRCOV, GPCF_SQUARED_TRVAR, GP_COV, GP_TRCOV

  if isempty(x2)
    x2=x1;
  end
  [n1,m1]=size(x1);
  [n2,m2]=size(x2);
  if m1~=m2
    error('the number of columns of X1 and X2 has to be same')
  end
  if isfield(gpcf, 'selectedVariables')
      x1 = x1(:,gpcf.selectedVariables);
      x2 = x2(:,gpcf.selectedVariables);
  end
  h1 = x1.^2;
  h2 = x2.^2;
  if isequal(gpcf.interactions,'on')
      m=size(x1,2);
      for xi1=1:m
          for xi2=xi1+1:m
              h1 = [h1 x1(:,xi1).*x1(:,xi2)];
              h2 = [h2 x2(:,xi1).*x2(:,xi2)];
          end
      end
  end
  C = h1*diag(gpcf.coeffSigma2)*(h2');
  C(abs(C)<=eps) = 0;

end

function C = gpcf_squared_trcov(gpcf, x)
%GP_SQUARED_TRCOV  Evaluate training covariance matrix of inputs
%
%  Description
%    C = GP_SQUARED_TRCOV(GP, TX) takes in covariance function of
%    a Gaussian process GP and matrix TX that contains training
%    input vectors. Returns covariance matrix C. Every element ij
%    of C contains covariance between inputs i and j in TX. This
%    is a mandatory subfunction used for example in prediction and
%    energy computations.
%
%  See also
%    GPCF_SQUARED_COV, GPCF_SQUARED_TRVAR, GP_COV, GP_TRCOV

  if isfield(gpcf, 'selectedVariables')
      x = x(:,gpcf.selectedVariables);
  end
  h = x.^2;
  if isequal(gpcf.interactions,'on')
      m=size(x,2);
      for xi1=1:m
          for xi2=xi1+1:m
              h = [h x(:,xi1).*x(:,xi2)];
          end
      end
  end
  C = h*diag(gpcf.coeffSigma2)*(h');
  C(abs(C)<=eps) = 0;
  C = (C+C')./2;

end

function C = gpcf_squared_trvar(gpcf, x)
%GP_SQUARED_TRVAR  Evaluate training variance vector
%
%  Description
%    C = GP_SQUARED_TRVAR(GPCF, TX) takes in covariance function
%    of a Gaussian process GPCF and matrix TX that contains
%    training inputs. Returns variance vector C. Every element i
%    of C contains variance of input i in TX. This is a mandatory
%    subfunction used for example in prediction and energy computations.
%
%
%  See also
%    GPCF_SQUARED_COV, GP_COV, GP_TRCOV

  if isfield(gpcf, 'selectedVariables')
      x = x(:,gpcf.selectedVariables);
  end
  h = x.^2;
  if isequal(gpcf.interactions,'on')
      m=size(x,2);
      for xi1=1:m
          for xi2=xi1+1:m
              h = [h x(:,xi1).*x(:,xi2)];
          end
      end
  end
  if length(gpcf.coeffSigma2) == 1
      C=gpcf.coeffSigma2.*sum(h.^2,2);
  else
      C=sum(repmat(gpcf.coeffSigma2, size(x,1), 1).*h.^2,2);
  end
  C(abs(C)<eps)=0;

end

function reccf = gpcf_squared_recappend(reccf, ri, gpcf)
%RECAPPEND Record append
%
%  Description
%    RECCF = GPCF_SQUARED_RECAPPEND(RECCF, RI, GPCF) takes a
%    covariance function record structure RECCF, record index RI
%    and covariance function structure GPCF with the current MCMC
%    samples of the parameters. Returns RECCF which contains all
%    the old samples and the current samples from GPCF. This
%    subfunction is needed when using MCMC sampling (gp_mc).
%
%  See also
%    GP_MC and GP_MC -> RECAPPEND

  if nargin == 2
    % Initialize the record
    reccf.type = 'gpcf_squared';

    % Initialize parameters
    reccf.coeffSigma2= [];

    % Set the function handles
    reccf.fh.pak = @gpcf_squared_pak;
    reccf.fh.unpak = @gpcf_squared_unpak;
    reccf.fh.lp = @gpcf_squared_lp;
    reccf.fh.lpg = @gpcf_squared_lpg;
    reccf.fh.cfg = @gpcf_squared_cfg;
    reccf.fh.cfdg = @gpcf_squared_cfdg;
    reccf.fh.cfdg2 = @gpcf_squared_cfdg2;
    reccf.fh.ginput = @gpcf_squared_ginput;
    reccf.fh.ginput2 = @gpcf_squared_ginput2;
    reccf.fh.ginput3 = @gpcf_squared_ginput3;
    reccf.fh.ginput4 = @gpcf_squared_ginput4;
    reccf.fh.cov = @gpcf_squared_cov;
    reccf.fh.trcov  = @gpcf_squared_trcov;
    reccf.fh.trvar  = @gpcf_squared_trvar;
    reccf.fh.recappend = @gpcf_squared_recappend;
    reccf.p=[];
    reccf.p.coeffSigma2=[];
    if ~isempty(ri.p.coeffSigma2)
      reccf.p.coeffSigma2 = ri.p.coeffSigma2;
    end

  else
    % Append to the record
    gpp = gpcf.p;

    reccf.interactions = gpcf.interactions;

    % record coeffSigma2
    reccf.coeffSigma2(ri,:)=gpcf.coeffSigma2;
    if isfield(gpp,'coeffSigma2') && ~isempty(gpp.coeffSigma2)
      reccf.p.coeffSigma2 = gpp.coeffSigma2.fh.recappend(reccf.p.coeffSigma2, ri, gpcf.p.coeffSigma2);
    end

    if isfield(gpcf, 'selectedVariables')
      reccf.selectedVariables = gpcf.selectedVariables;
    end
  end
end

function [F,L,Qc,H,Pinf,dF,dQc,dPinf,params] = gpcf_squared_cf2ss(gpcf,x)
%GPCF_SQUARED_CF2SS Convert the covariance function to state space form
%
%  Description
%    Convert the covariance function to state space form such that
%    the process can be described by the stochastic differential equation
%    of the form:
%      df(t)/dt = F f(t) + L w(t),
%    where w(t) is a white noise process. The observation model now
%    corresponds to y_k = H f(t_k) + r_k, where r_k ~ N(0,sigma2).
%
%

  % Check arguments
  if nargin < 2 || isempty(x), x = 0; end

  % Scaling
  x0 = min(x);

  % Define the model
  F      = [0 1; 0 0];
  L      = [0; 1];
  Qc     = 0;
  H      = [1 0];
  Pinf   = [x0^2 x0; x0 1]*gpcf.coeffSigma2;
  dF     = zeros(2,2,1);
  dQc    = zeros(1,1,1);
  dPinf  = [x0^2 x0; x0 1];
  params = {};

  % Set params
  params.stationary = false;

  % Check which parameters are optimized
  if isempty(gpcf.p.coeffSigma2), ind(1) = false; else ind(1) = true; end

  % Return only those derivatives that are needed
  dF    = dF(:,:,ind);
  dQc   = dQc(:,:,ind);
  dPinf = dPinf(:,:,ind);

end


% loadtxt() - load ascii text file into numeric or cell arrays
%
% Usage:
%   >> array = loadtxt( filename, 'key', 'val' ...);
%
% Inputs:
%    filename - name of the input file
%
% Optional inputs
%   'skipline' - number of lines to skip {default:0}. If this number is
%                negative the program will only skip non-empty lines
%                (can be usefull for files transmitted from one platform
%                to an other, as CR may be inserted at every lines).
%   'convert'  - 'on' standard text conversion, see note 1
%                'off' no conversion, considers text only
%                'force' force conversion, NaN are returned
%                for non-numeric inputs {default:'on'}
%   'delim'    - ascii character for delimiters. {default:[9 32]
%                i.e space and tab}. It is also possible to enter
%                strings, Ex: [9 ' ' ','].
%   'blankcell' - ['on'|'off'] extract blank cells {default:'on'}
%   'verbose'  - ['on'|'off'] {default:'on'}
%   'convertmethod' - ['str2double'|'str2num'] default is 'str2double'
%   'nlines'   - [integer] number of lines to read {default: all file}
%
% Outputs:
%    array - cell array. If the option 'force' is given, the function
%            retrun a numeric array.
%
% Notes: 1) Since it uses cell arrays, the function can handle text input.
%        The function reads each token and then try to convert it to a
%        number. If the conversion is unsucessfull, the string itself
%        is included in the array.
%        2) The function adds empty entries for rows that contains
%        fewer columns than others.
%
% Author: Arnaud Delorme, CNL / Salk Institute, 29 March 2002

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

function array = loadtxt( filename, varargin );

if nargin < 1
	help loadtxt;
	return;
end;
if ~isempty(varargin)
   try, g = struct(varargin{:});
   catch, disp('Wrong syntax in function arguments'); return; end;
else
    g = [];
end;

g = finputcheck( varargin, { 'convert'   'string'   { 'on';'off';'force' }   'on';
                             'skipline'  'integer'  [0 Inf]          0;
                             'verbose'   'string'   { 'on';'off' }   'on';
                             'uniformdelim' 'string'   { 'on';'off' }   'off';
                             'blankcell' 'string'   { 'on';'off' }   'on';
                             'convertmethod' 'string'   { 'str2double';'str2num' }   'str2double';
                             'delim'     { 'integer';'string' } []               [9 32];
                             'nlines'    'integer'  []               Inf });
if isstr(g), error(g); end;
if strcmpi(g.blankcell, 'off'), g.uniformdelim = 'on'; end;
g.convert = lower(g.convert);
g.verbose = lower(g.verbose);
g.delim = char(g.delim);

% open the file
% -------------
if exist(filename) ~=2, error( ['file ' filename ' not found'] ); end;
fid=fopen(filename,'r','ieee-le');
if fid<0, error( ['file ' filename ' found but error while opening file'] ); end;

index = 0;
while index < abs(g.skipline)
    tmpline = fgetl(fid);
    if g.skipline > 0 | ~isempty(tmpline)
        index = index + 1;
    end;
end; % skip lines ---------

inputline = fgetl(fid);
linenb = 1;
if strcmp(g.verbose, 'on'), fprintf('Reading file (lines): '); end;
while isempty(inputline) | inputline~=-1
     colnb = 1;
     if ~isempty(inputline)
         tabFirstpos = 1;

         % convert all delimiter to the first one
         if strcmpi(g.uniformdelim, 'on')
             for index = 2:length(g.delim)
                 inputline(find(inputline == g.delim(index))) = g.delim(1);
             end;
         end;

         while ~isempty(deblank(inputline))
             if strcmpi(g.blankcell,'off'), inputline = strtrim(inputline); end;
             if tabFirstpos && length(inputline) > 1 && all(inputline(1) ~= g.delim), tabFirstpos = 0; end;
             [tmp inputline tabFirstpos] = mystrtok(inputline, g.delim, tabFirstpos);
             switch g.convert
                case 'off', array{linenb, colnb} = tmp;
                case 'on',
                     if strcmpi(g.convertmethod, 'str2double')
                         tmp2 = str2double(tmp);
                         if isnan( tmp2 )  , array{linenb, colnb} = tmp;
                         else                array{linenb, colnb} = tmp2;
                         end;
                     else
                         tmp2 = str2num(tmp);
                         if isempty( tmp2 )  , array{linenb, colnb} = tmp;
                         else                  array{linenb, colnb} = tmp2;
                         end;
                     end;
                case 'force', array{linenb, colnb} = str2double(tmp);
             end;
             colnb = colnb+1;
         end;
	     linenb = linenb +1;
     end;
     inputline = fgetl(fid);
     if linenb > g.nlines
         inputline = -1;
     end;
     if ~mod(linenb,10) & strcmp(g.verbose, 'on'), fprintf('%d ', linenb); end;
end;
if strcmp(g.verbose, 'on'),  fprintf('%d\n', linenb-1); end;
if strcmp(g.convert, 'force'), array = [ array{:} ]; end;
fclose(fid);

% problem strtok do not consider tabulation
% -----------------------------------------
function [str, strout, tabFirstpos] = mystrtok(strin, delim, tabFirstpos);
    % remove extra spaces at the beginning
    while any(strin(1) == delim) && strin(1) ~= 9 && strin(1) ~= ','
         strin = strin(2:end);
    end;
    % for tab and coma, consider empty cells
    if length(strin) > 1 && any(strin(1) == delim)
        if tabFirstpos || any(strin(2) == delim)
            str = '';
            strout = strin(2:end);
            if strin(2) ~= 9 && strin(2) ~= ','
                tabFirstpos = 0;
                strout = strtrim(strout);
            end;
        else
            [str, strout] = strtok(strin, delim);
        end;
    else
        [str, strout] = strtok(strin, delim);
    end;


function [ output_meta ] = meta2sicd_s1noise( domnode, meta_product )
%META2SICD_S1NOISE Converts Sentinel-1 noise XML file into SICD format
%
% Written by: Wade Schwartzkopf, NGA Research
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

% Setup
xp=javax.xml.xpath.XPathFactory.newInstance.newXPath();

% Compute the first line of each burst in overall TIFF file
first_line = zeros(numel(meta_product),1);
for i = 1:(numel(meta_product)-1)
    first_line(i+1) = first_line(i) + meta_product{i}.ImageData.NumCols;
end
% Read noise parameters from XML
n_str = 'noise';
num_noise_vecs=str2double(xp.evaluate(...
    ['count(noise/' n_str 'VectorList/' n_str 'Vector)'],domnode));
if num_noise_vecs == 0  % Data after March 2018 had different format
    n_str = 'noiseRange';
    num_noise_vecs=str2double(xp.evaluate(...
        ['count(noise/' n_str 'VectorList/' n_str 'Vector)'],domnode));
end
noisevals = cell(num_noise_vecs,1);
pixel = cell(num_noise_vecs,1);
noise_line = zeros(num_noise_vecs,1);
for i = 1:num_noise_vecs
    noise_line(i) = str2double(xp.evaluate(...
        ['noise/' n_str 'VectorList/' n_str 'Vector[' num2str(i) ']/line'],...
        domnode));
    pixel{i} = str2num(xp.evaluate(...
        ['noise/' n_str 'VectorList/' n_str 'Vector[' num2str(i) ']/pixel'],...
        domnode));
    noisevals{i} = str2num(xp.evaluate(...
        ['noise/' n_str 'VectorList/' n_str 'Vector[' num2str(i) ']/' n_str 'Lut'],...
        domnode));
end
mode = char(xp.evaluate('noise/adsHeader/mode',domnode));
fit_tolerance = 0.1; % Simple 1D data for IW should fit quite tightly
noisepoly_order = 6; % For IW, this fits quite tightly
if upper(mode(1))=='S'
    % Average all of the noise values across azimuth for a single 1D
    % polynomial that varies in range.  They are roughly similar.  A
    % precise solution would include a 2D fit.
    pixel = {cell2mat(pixel)};
    noisevals = {cell2mat(noisevals)};
    noise_line = 0;
    % Allow for more slop for SM since we have 2D noise values, but aren't
    % doing a full 2D fit.  Because we average across all azimuth, there is
    % no reason to attempt a tight fit, since it won't match across all
    % lines for any fit.
    fit_tolerance = 0.5;
    noisepoly_order = 3;
% Double check our assumptions about the noise data
elseif any(mod(noise_line(1:(end-1)), ...
        double(meta_product{1}.ImageData.NumCols))~=0)
    warning('META2SICD_S1NOISE:UNEXPECTED_LINE','Expected noise values at beginning of each burst.');
    return;
end
% Compute SICD noise polynomials
output_meta = cell(numel(meta_product),1);
for i = 1:numel(meta_product) % First and last are usually outside bursts
    % Which noise values should we use for this burst?  We use the ones
    % that correspond to the first column of the burst.
    line_ind = find(noise_line>=first_line(i) & ...
        noise_line<(first_line(i)+meta_product{i}.ImageData.NumCols),1);
    if isempty(line_ind), continue, end
    coords_rg_m = (double(0:(meta_product{i}.ImageData.NumRows-1)) - ...
        double(meta_product{i}.ImageData.SCPPixel.Row)) * ...
        meta_product{i}.Grid.Row.SS;
    coords_rg_m = coords_rg_m(pixel{line_ind}(:)+1);
    old_state = warning('off','MATLAB:polyfit:RepeatedPointsOrRescale');
    noisepoly = polyfit(coords_rg_m(:), 10*log10(noisevals{line_ind}(:)), noisepoly_order);
    warning(old_state);
    if any(polyval(noisepoly, coords_rg_m(:)) - ...
            10*log10(noisevals{line_ind}(:)) > fit_tolerance)
        warning('META2SICD_S1NOISE:NOISE_TOLERANCE', ...
            'Noise model does not appear to fit data tightly.');
    end
    % These are typically very close across all bursts, but we compute for
    % each bursts independently anyway.
    output_meta{i}.Radiometric.NoiseLevel.NoiseLevelType = 'ABSOLUTE';
    output_meta{i}.Radiometric.NoiseLevel.NoisePoly = noisepoly(end:-1:1).';
end
% Throw warning for old, potentially inaccurate data
last_az_time = xp.evaluate(...
        ['noise/' n_str 'VectorList/' n_str 'Vector[' num2str(num_noise_vecs) ']/azimuthTime'],...
        domnode);
if datenum(char(last_az_time),'yyyy-mm-ddTHH:MM:SS')<datenum(2015, 11, 25)
    warning('META2SICD_S1NOISE:EARLY_DATE','Sentinel-1 radiometric data prior to November 25, 2015 might not be accurate.');
end

end

% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////


filename='Cantileverbeam_Hexahedra_Linear_Structured_SYM';
ptype = 'MACRO';
method = 'SIMPALL';
materialType = 'ISOTROPIC';
initial_case = 'holes';
cost = {'compliance'};
weights = [1];
constraint = {'volume'};
optimizer = 'HAMILTON-JACOBI';
incrementFactor = 1;
designVariable = 'LevelSet';
filterType = 'P1';
constraint_case = 'INEQUALITY';

nsteps = 10;
Vfrac_final = 0.1;
Perimeter_target=3.5;
optimality_final =1e-3;
constr_final =1e-3;

BCscale_factor = 0.3;
rotation_per_it = 20;
HJiter0 = 1;
e2 = 100;
N_holes = [12 5 5];
R_holes = 0.2;
phase_holes = [0 0 0];

Vfrac_initial = 0.7;
optimality_initial = 5e-2;
constr_initial = 5e-2;

TOL.rho_plus = 1;
TOL.rho_minus = 0;
TOL.E_plus = 1;
TOL.E_minus = 1e-3;

% maxiter = 1;
TOL.nu_plus = 0.3;
TOL.nu_minus = 0.3;


classdef ParadigmFBCSP < ParadigmDataflowSimplified
    % Paradigm for complex oscillatory processes using the filter-bank CSP algorithm.
    % Result = para_multiband_csp(Input-Data, Operation-Mode, Options...)
    %
    % Filter-bank CSP [1,2] is a simple extension of the basic CSP method (see ParadigmCSP), in which for
    % each of several time/frequency filters a set of CSP filters is learned, followed by log-variance
    % feature extraction, concatenation of all features (over all chosen spectral filters) and
    % subsequent machine learning. It is not a general replacement for CSP due to the problem of
    % overfitting, but is very useful whenever oscillatory processes in different frequency bands (and
    % with different spatial topographies) are jointly active, and their concerted behavior must be
    % taken into account for a given prediction task. Filter-bank CSP can also be used to capture
    % oscillations in multiple time windows, instead of frequency windows (for example for the detection
    % of complex event-related dynamics).
    %
    % Since the dimensionality of the feature space is larger than in CSP, and since complex
    % interactions may be present, a more complex classifier than the default LDA may be necessary to
    % learn an appropriate model. On the other hand, more flexibility amplifies the risk of overfitting
    % (especially with only little calibration data), so that the performance should always be compared
    % to standard CSP (and Spec-CSP). Another reason is that complex (relevant) interactions between
    % different frequency bands are seemingly rarely observed in practice. The most important
    % user-configurable parameters are the selection regions in time and frequency and the learner
    % component.
    %
    % Typical applications would be those in which either complex event-related oscillatory dynamics
    % happen (for example when reacting to a particular stimulus) and/or where non-trivial interactions
    % between frequency bands (e.g. alpha/theta) are relevant, such as, for example, in workload
    % measurements.
    %
    % Example: Consider a calibration data set in which a subject is maintaining and updating
    % different number of items in his/her working memory at different times, e.g. while performing
    % the n-Back task [2]. Events with types 'n1','n2','n3' indicate challenge stimuli in which the
    % respective number of items is being processed by the person. The goal is to be able to predict
    % the working-memory load of the person following the presentation of such a memory-related
    % challenge. An epoch of 3 seconds relative to each challenge is selected, and three different
    % regions are chosen, two of them over the entire interval, covering the theta and alpha ryhthm,
    % respectively, and one region that is restricted to a window around the time of heaviest
    % cognitive processing. The three regions are specified as a cell array of flt_select
    % parameters.
    %
    %   data = io_loadset('data sets/mary/nback.eeg')
    %   myapproach = {'FBCSP' 'SignalProcessing',{'EpochExtraction',[-0.5 2.5]}, ...
    %       'Prediction', {'FeatureExtraction',{'FreqWindows',[4 6; 7 15; 7 15],'TimeWindows',[-0.5 2.5; -0.5 2.5; 0.25 1.25]}, ...
    %                      'MachineLearning',{'Learner','logreg'}}}
    %   [loss,model,stats] = bci_train('Data',data, 'Approach','ParadigmFBCSP, 'TargetMarkers',{'n1','n2','n3'})
    %
    % References;
    %   [1] Quadrianto Novi, Cuntai Guan, Tran Huy Dat, and Ping Xue, "Sub-band Common Spatial Pattern (SBCSP) for Brain-Computer Interface"
    %       Proceedings of the 3rd International IEEE EMBS Conference on Neural Engineering Kohala Coast, Hawaii, USA, May 2-5, 2007
    %   [2] Kai K. Ang, Zhang Y. Chin, Haihong Zhang, Cuntai Guan, "Filter Bank Common Spatial Pattern (FBCSP) in Brain-Computer Interface"
    %       In 2008 IEEE International Joint Conference on Neural Networks (IEEE World Congress on Computational Intelligence) (June 2008), pp. 2390-2397.
    %   [3] Owen, A. M., McMillan, K. M., Laird,A. R. & Bullmore, E. "N-back working memory paradigm: A meta-analysis of normative functional neuroimaging studies."
    %       Human Brain Mapping, 25, 46-59, 2005
    %
    % Name:
    %   Filter-Bank CSP
    %
    %                           Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
    %                           2010-04-29

    methods

        function defaults = preprocessing_defaults(self)
            % define the default pre-processing parameters of this paradigm
            defaults = {'EpochExtraction',[0.5 3.5],'Resampling',200};
        end

        function model = feature_adapt(self,varargin)
            % adapt a feature representation using the CSP algorithm
            args = arg_define(varargin, ...
                arg_norep('signal'), ...
                arg({'patterns','PatternPairs'},3,uint32([1 1 64 10000]),'CSP patterns per band (times two).','cat','Feature Extraction'), ...
                arg({'shrinkage_cov','ShrinkageCovariance'},false,[],'Shrinkage covariance estimator. Whether to use shrinkage to estimate the covariance matrices.'), ...
                arg({'robust_cov','RobustCovariance'},false,[],'Robust covariance estimation. Whether to use robust cov estimation.'), ...
                arg({'freqwnds','FreqWindows'},[0.5 3; 4 7; 8 12; 13 30; 31 42],[0 0.5 200 1000],'Frequency bands of interest. Matrix containing one row for the start and end of each frequency band from which CSP patterns shall be computed. Values in Hz.','cat','Feature Extraction'), ...
                arg({'timewnds','TimeWindows'},[],[],'Time windows of interest. Matrix containing one row for the start and end of each time window from which CSP patterns shall be computed. Values in seconds. If both this and the freqwnds parameter are non-empty, they should have the same number of rows.','cat','Feature Extraction'), ...
                arg({'winfunc','WindowFunction'},'rect',{'barthann','bartlett','blackman','blackmanharris','bohman','cheb','flattop','gauss','hamming','hann','kaiser','nuttall','parzen','rect','taylor','triang','tukey'},'Type of window function. Typical choices are rect (rectangular), hann, gauss, blackman and kaiser.'),...
                arg({'winparam','WindowParameter','param'},[],[],'Parameter of the window function. This is mandatory for cheb, kaiser and tukey and optional for some others.','shape','scalar'));

            if args.signal.nbchan == 1
                error('Multi-band CSP does intrinsically not support single-channel data (it is a spatial filter).'); end
            if args.signal.nbchan < args.patterns
                error('Multi-band CSP prefers to work on at least as many channels as you request output patterns. Please reduce the number of pattern pairs.'); end
            if ~isempty(args.freqwnds) && ~isempty(args.timewnds) && size(args.freqwnds,1) ~= size(args.timewnds,1)
                error('If both time and frequency windows are specified, both arrays must have the same number of rows (together they define the windows in time and frequency).'); end
            if isempty(args.timewnds)
                args.timewnds = zeros(size(args.freqwnds,1),0); end
            if isempty(args.freqwnds)
                args.freqwnds = zeros(size(args.timewnds,1),0); end

            filters = [];
            patterns = [];
            % for each window
            for w = 1:max(size(args.freqwnds,1),size(args.timewnds,1))
                % pre-parse arguments for flt_window and flt_spectrum (for fast subsequent online use)
                time_args{w} = arg_report('vals',@flt_window,{'time',{args.timewnds(w,:),args.winfunc,args.winparam}});
                freq_args{w} = arg_report('vals',@flt_spectrum,{'freq',args.freqwnds(w,:)});
                for k=1:2
                    % filter trial subrange in time and frequency
                    data = exp_eval_optimized(flt_spectrum('signal',flt_window('signal',set_picktrials(args.signal,'rank',k),time_args{w}),freq_args{w}));
                    if args.robust_cov
                        covar{k} = hlp_diskcache('featuremodels',@cov_blockgeom,reshape(data.data,size(data.data,1),[])',max([data.nbchan*2,data.srate*2,size(data,3)]));
                    else
                        if args.shrinkage_cov
                            covar{k} = hlp_diskcache('featuremodels',@cov_shrink,reshape(data.data,size(data.data,1),[])');
                        else
                            covar{k} = cov(reshape(data.data,size(data.data,1),[])');
                        end
                    end
                    covar{k}(~isfinite(covar{k})) = 0;
                end
                [V,D] = eig(covar{1},covar{1}+covar{2}); %#ok<NASGU>
                P = inv(V);
                filters = [filters V(:,[1:args.patterns end-args.patterns+1:end])];
                patterns = [patterns P([1:args.patterns end-args.patterns+1:end],:)'];
            end
            model = struct('filters',{filters},'patterns',{patterns},'time_args',{time_args},'freq_args',{freq_args},'chanlocs',{args.signal.chanlocs});
        end

        function features = feature_extract(self,signal,featuremodel)
            W = length(featuremodel.freq_args);
            F = size(featuremodel.filters,2);
            T = size(signal.data,3);
            features = zeros(T,F);
            for w = 1:W
                % filter data in time & frequency
                data = exp_eval_optimized(flt_spectrum('signal',flt_window('signal',signal,featuremodel.time_args{w}),featuremodel.freq_args{w}));
                inds = (w-1)*(F/W)+(1:(F/W));
                for t=1:T
                    features(t,inds) = log(var(data.data(:,:,t)' * featuremodel.filters(:,inds))); end
            end
        end

        function visualize_model(self,varargin) %#ok<*INUSD>
            args = arg_define([0 3],varargin, ...
                arg_norep({'myparent','Parent'},[],[],'Parent figure.'), ...
                arg_norep({'featuremodel','FeatureModel'},[],[],'Feature model. This is the part of the model that describes the feature extraction.'), ...
                arg_norep({'predictivemodel','PredictiveModel'},[],[],'Predictive model. This is the part of the model that describes the predictive mapping.'), ...
                arg({'patterns','PlotPatterns'},true,[],'Plot patterns instead of filters. Whether to plot spatial patterns (forward projections) rather than spatial filters.'), ...
                arg({'weight_scaled','WeightScaled'},false,[],'Scaled by weight. Whether to scale the patterns by weight.'));
            arg_toworkspace(args);

            % find the relevant components
            scores = predictivemodel.model.w;
            scores = sqrt(abs(scores));
            % optionally remove the bias if included in w
            if length(scores) == size(featuremodel.patterns,2)+1
                scores = scores(1:end-1); end
            % frequency labels
            % titles = repmat({'delta','theta','alpha','beta','gamma'},8,1); titles = titles(:);
            % extract relevant patterns
            patterns = featuremodel.patterns(:,find(scores)); %#ok<FNDSB>
            filters = featuremodel.filters(:,find(scores)); %#ok<FNDSB>
            % plot them
            if args.weight_scaled
                if args.patterns
                    topoplot_grid(patterns,featuremodel.chanlocs,'scales',scores(find(scores))/max(scores)*1);
                else
                    topoplot_grid(filters,featuremodel.chanlocs,'scales',scores(find(scores))/max(scores)*1);
                end
            else
                if args.patterns
                    topoplot_grid(patterns,featuremodel.chanlocs);
                else
                    topoplot_grid(filters,featuremodel.chanlocs);
                end
            end
            % figure;
        end

        function layout = dialog_layout_defaults(self)
            % define the default configuration dialog layout
            layout = {'SignalProcessing.Resampling.SamplingRate', 'SignalProcessing.EpochExtraction', '', ...
                'Prediction.FeatureExtraction.FreqWindows', 'Prediction.FeatureExtraction.TimeWindows', ...
                'Prediction.FeatureExtraction.WindowFunction', '', 'Prediction.FeatureExtraction.PatternPairs', '', ...
                'Prediction.MachineLearning.Learner'};
        end

        function tf = needs_voting(self)
            tf = true;
        end
    end
end


%%  Copyright (C) 2011-2012 by Jun He, Laura Balzano, and Arthur Szlam
%
%  This file is part of the GRASTA library.
%  It is provided without any warranty of fitness
%  for any purpose. You can redistribute this file
%  and/or modify it under the terms of the GNU
%  Lesser General Public License (LGPL) as published
%  by the Free Software Foundation, either version 3
%  of the License or (at your option) any later version.
%  (see http://www.opensource.org/licenses for more info)

function [ Unew, STATUSnew, OPTSnew ] = grasta_stream( y_Omega, idx, U0, STATUS,OPTIONS, OPTS)
%  grasta_stream is the streaming version of GRASTA which can be used for
%  online data processing
%
%   [1] Jun He, Laura Balzano, and John C.S. Lui. Online Robust Subspace Tracking from Partial Information
%       http://arxiv.org/abs/1109.3827
%   [2] Jun He, Laura Balzano, and Arthur Szlam. Incremental gradient on the grassmannian for online foreground
%       and background separation in subsampled video. In IEEE Conference on Computer Vision and Pattern Recognition
%       (CVPR), June 2012.
%
%  Usage:
%       [ Unew, STATUSnew, OPTSnew ] = grasta_stream( y_Omega, idx, U0, STATUS, OPTIONS, OPTS)
%   Inputs:
%       y_Omega: current partial observation of a full data vector
%       idx:     the observed indices of y_Omega
%       U0:      the current estimated subspace
%       STATUS:  the current status of GRASTA
%           last_mu: \mu_{t-1} for adaptive step rule
%           step_scale: the estimated step_scale constant for adaptive
%       step-size rule
%           lelve: the current level of the "Multi-Level" adaptive rule
%           last_gamma and last_w: previous gradient = last_gamma*last_w'
%
%       OPTIONS: the options of GRASTA
%           CONSTANT_STEP: default 0, will use multi-level step-size rule; > 0 will
%           use constant step-size rule
%           DIM_M : the ambient dimension
%           RANK  : the estimated low-rank of the underlying system
%           rho : ADMM constant step
%           ITER_MAX: the max_iter for ADMM solver
%           TOL : the stopping tolerance of admm_srp / mex_srp
%
%       OPTS:    the current options for the subproblem of GRASTA
%           refer to mex_srp.cpp or admm_srp.m
%   Outputs:
%       Unew:    the updated subspace
%       STATUSnew: the updated running status
%       OPTSnew: the updated options for the subproblem of GRASTA
%
%  Author: Jun He, Laura Balzano
%  Email:  hejun.zz@gmail.com, sunbeam@ece.wisc.edu
%  Date:   Sept. 01, 2012
%
%

LEVEL_FACTOR        = 2;

if isfield(OPTIONS,'MIN_MU'),
    MIN_MU = OPTIONS.MIN_MU;
else
    MIN_MU = 1;
end

if isfield(OPTIONS,'MAX_MU'),
    MAX_MU = OPTIONS.MAX_MU;
else
    MAX_MU = 15;
end

if isfield(OPTIONS,'USE_MEX'),
    USE_MEX = OPTIONS.USE_MEX;
else
    USE_MEX = 1;
end

if isfield(OPTIONS,'CONSTANT_STEP'),
    CONSTANT_STEP = OPTIONS.CONSTANT_STEP;
else
    CONSTANT_STEP = 0;
end

if isfield(OPTIONS,'DIM_M'),
    DIM_M = OPTIONS.DIM_M;
else
    error('Should specify OPTIONS.DIM_M data ambient dimension!!!\n');
end

if isfield(OPTIONS,'ITER_MIN'),
    MIN_ITER = OPTIONS.ITER_MIN;
else
    MIN_ITER = 5;
end

if isfield(OPTIONS,'ITER_MAX'),
    ITER_MAX = OPTIONS.ITER_MAX;
else
    ITER_MAX = 60;
end

if isfield(OPTIONS,'TOL'),
    TOL = OPTIONS.TOL;
else
    TOL = 1e-6;
end

if isfield(OPTIONS,'MAX_LEVEL'),
    MAX_LEVEL = OPTIONS.MAX_LEVEL;
else
    MAX_LEVEL = 20;
end

if isfield(OPTIONS,'RANK'),
    RANK = OPTIONS.RANK;
else
    error('Should specify OPTIONS.RANK!!!\n');
end

if isfield(OPTIONS,'QUIET'),
    QUIET = OPTIONS.QUIET;
else
    QUIET = 0;
end

DEFAULT_MU_HIGH     = (MAX_MU-1)/2;
DEFAULT_MU_LOW      = MIN_MU + 2;

% If we first call GRASTA_stream then do the following initilization
if STATUS.init == 0,
    STATUS.init         = 1; % Do not enter this initial part any longer
    STATUS.curr_iter    = 0; % For debug

    STATUS.last_mu      = MIN_MU;
    STATUS.level        = 0;
    STATUS.step_scale   = 0;
    STATUS.last_w       = zeros(RANK,1);
    STATUS.last_gamma   = zeros(DIM_M,1);

    OPTS.TOL        = TOL;
    OPTS.MAX_ITER   = MIN_ITER;  % the max iteration of ADMM at level=0
    OPTS.QUIET      = 1;

    if isfield(OPTIONS,'rho'),
        OPTS.RHO = OPTIONS.rho;
    else
        OPTS.RHO = 1.8;
    end

    U0 = orth(randn(DIM_M,RANK));
end

%%%%%%%%%%%%%%%
% main framework of GRASTA
U_Omega = U0(idx,:);

if USE_MEX,
    [s_t, w, ldual] = mex_srp(U_Omega, y_Omega, OPTS);
else
    [s_t, w, ldual] = admm_srp(U_Omega, y_Omega, OPTS);
end

gamma_1 = ldual;% + OPTS.RHO*(U_Omega*w + s_t - y_Omega);
UtDual_omega = U_Omega' * gamma_1;
gamma_2 = U0 * UtDual_omega;
gamma = zeros(DIM_M,1);
gamma(idx) = gamma_1;
gamma = gamma - gamma_2;

gamma_norm = norm(gamma);
w_norm     = norm(w);
sG = gamma_norm * w_norm;

% Here we use the adaptive step-size rule for SGD. The adaptive can work
% well for both dynamic and static subspace tracking tasks

% 1. determine the step scale from the first observation
if ~STATUS.step_scale,
    STATUS.step_scale = 0.5*pi*(1+MIN_MU)/sG;

    if ~QUIET,
        fprintf('Level 0: %.2e\n',STATUS.step_scale);
    end
end

% 2. inner product of previous grad and current grad
grad_ip = trace(STATUS.last_w * (STATUS.last_gamma' * gamma) * w');

%%% avoid inner product too large
normalization = norm(STATUS.last_gamma * STATUS.last_w','fro') * norm(gamma * w','fro');
if normalization == 0,
    grad_ip_normalization = 0;
else
    grad_ip_normalization = grad_ip/normalization;
end
%%%

% 3. if the two consecutive grad in the same direction, we take a larger
% step along the gradient direction, otherwise take a small step along the
% gradient direction
STATUS.last_mu = max(STATUS.last_mu + sigmoid(-grad_ip_normalization) , MIN_MU);

if CONSTANT_STEP > 0,
    t = CONSTANT_STEP;
else
    % should not take a step larger than pi/2
    t = STATUS.step_scale * LEVEL_FACTOR^(-STATUS.level) * sG / (1+STATUS.last_mu);
    if t>=pi/3,
        t = pi/3;
    end

    % Adjust the level
    bShrUpd = 0;
    if STATUS.last_mu <= MIN_MU,
        if STATUS.level > 1,
            bShrUpd = 1;
            STATUS.level = STATUS.level - 1;

            if ~QUIET,
                fprintf('multi-level adaption - decreasing, t:%.2e, vectors: %d, level: %d\n',...
                    t,STATUS.curr_iter, STATUS.level);
            end
            STATUS.curr_iter  = 0;
        end

        STATUS.last_mu    = DEFAULT_MU_LOW;
    elseif STATUS.last_mu > MAX_MU,
        if STATUS.level < MAX_LEVEL,
            bShrUpd = 1;
            STATUS.level = STATUS.level + 1;

            if ~QUIET,
                fprintf('multi-level adaption - increasing, t:%.2e, vectors: %d, level: %d\n',...
                    t, STATUS.curr_iter,  STATUS.level);
            end
            STATUS.curr_iter  = 0;
            STATUS.last_mu    = DEFAULT_MU_HIGH;
        else
            STATUS.last_mu    = MAX_MU;
        end
    end

    if bShrUpd,
        if STATUS.level>=0 && STATUS.level <4,          % [0,4)
            OPTS.MAX_ITER = MIN_ITER;
        elseif STATUS.level>=4 && STATUS.level <7,      % [4,7)
            OPTS.MAX_ITER = min(MIN_ITER*2, ITER_MAX);
        elseif STATUS.level>=7 && STATUS.level <10,     % [7,10)
            OPTS.MAX_ITER = min(MIN_ITER*4, ITER_MAX);
        elseif STATUS.level>=10 && STATUS.level <14,    % [10,14)
            OPTS.MAX_ITER = min(MIN_ITER*8, ITER_MAX);
        else
            OPTS.MAX_ITER = ITER_MAX;               % [14,...)
        end

        if ~QUIET,
            fprintf('Will use %d ADMM iterations in level %d\n',OPTS.MAX_ITER, STATUS.level);
        end
    end

end

% 4. update the gradient for further step size update
STATUS.last_gamma  = gamma;
STATUS.last_w      = w;

STATUS.grad_ip = grad_ip_normalization; % just for debugging

% Take the gradient step along Grassmannian geodesic.
alpha = w/w_norm;
beta  = gamma/gamma_norm;
step = (cos(t)-1)*U0*(alpha*alpha')  - sin(t)*beta*alpha';

U0 = U0 + step;

%%

STATUS.s_t   = s_t;
STATUS.w     = w;
STATUS.ldual = ldual;
STATUS.SCALE = 1;
STATUS.curr_iter = STATUS.curr_iter + 1;

STATUS.grasta_t = t;

%
%%%%%%%%%%%%%%%%%%%%%%

Unew = U0;
STATUSnew = STATUS;
OPTSnew = OPTS;
end

%% Function of Sigmoid

function fval = sigmoid(x)
FMIN = -1; FMAX = 1;
omega = 0.1;

fval = FMIN + (FMAX - FMIN)/(1 - (FMAX/FMIN)*exp(-x/omega));
end


function [predict_label,accuracy] = jdrf(x_train,y_train,x_test,y_test,n_trees)
%%jdrf:packaged TreeBagger from Matlab,just for easier use.
%%==============================================================================
%%input:
%%------x_train,...,y_test  :   training and testing sets.        [required]
%%------n_trees             :   number of trees,default is 10.    [not required]

%%output:
%%------predict_label       :   predicted label vector for test case.
%%------accuracy            :   accuracy
%%==============================================================================
	predict_label = [];
    accuracy = 0;
    switch nargin
        case 4
            tree_para = 10;
        case 5
            tree_para = n_trees;
        otherwise
            fprintf('++++++Fatal error!Please check the input!');
            return
	end
	factor = TreeBagger(tree_para,x_train,y_train);
    [predict_labels,scores] = predict(factor,x_test);
    predictY = str2num(char(predict_labels));
    accuracy = mean(predictY == y_test);
    predict_label = predictY;
end


function view = fixPhase(view, scanNum, sliceNum, shift, scale)
%
% function view = fixPhase(view, [scanNum], [sliceNum], [shift], [scale])
%
%
% Adds specified offset and scale to the phases of the specified coranal.
% Will prompt for offset & scale if not given of empty.
% The current slice will be used if sliceNum not given or empty.
%
% HISTORY:
%   2002.03.08 RFD (bob@white.stanford.edu) wrote it.

global dataTYPES;

if(~exist('scanNum','var') | isempty(scanNum))
    scanNum = getCurScan(view);
end

if(~exist('sliceNum','var') | isempty(sliceNum))
    sliceNum = viewGet(view, 'Current Slice');
end

oldShift = dataTYPES(view.curDataType).atlasParams(scanNum).phaseShift(sliceNum);
oldScale = dataTYPES(view.curDataType).atlasParams(scanNum).phaseScale(sliceNum);

oldPh = view.ph;
% undo the old shift & scale so that we can start anew
view.ph{scanNum}(:,:,sliceNum) = mod((view.ph{scanNum}(:,:,sliceNum) - oldShift)/oldScale, 2*pi);
%refreshView(view);

if(~exist('shift','var')) shift = []; end
if(~exist('scale','var')) scale = []; end
if(isempty(shift) | isempty(scale))
    if(isempty(shift))
        def{1} = num2str(oldShift);
    else
        def{1} = num2str(shift);
    end
    if(isempty(scale))
        def{2} = num2str(oldScale);
    else
        def{2} = num2str(scale);
    end

    ok = 0;
    while(~ok)
        answer = inputdlg({'Phase shift:','Scale Factor:'}, 'Fix Phase', 1, def);
        if(isempty(answer))
            % Cancel all changes
            view.ph = oldPh;
            refreshView(view);
            ok = 1;
            return;
        end
        shift = eval(answer{1});
        scale = eval(answer{2});
        view.ph{scanNum}(:,:,sliceNum) = view.ph{scanNum}(:,:,sliceNum) * scale + shift;
        view.ph{scanNum}(:,:,sliceNum) = phaseStandardize(view.ph{scanNum}(:,:,sliceNum));
        view.ph{scanNum}(:,:,sliceNum) = mod(view.ph{scanNum}(:,:,sliceNum), 2*pi);
        refreshView(view);
        ans = questdlg('Is this OK?', ...
            'Confirm Phase Adjustment', ...
            'Yes','No- try again','Cancel all changes','Yes');

        switch ans,
        case 'Yes',
            saveCorAnal(view);
            ok = 1;
        case 'No- try again',
            refreshView(view);
            def = answer;
            ok = 0;
        case 'Cancel all changes',
            view.ph = oldPh;
            refreshView(view);
            ok = -1;
            return;
        end % switch
    end
else
    view.ph{scanNum}(:,:,sliceNum) = view.ph{scanNum}(:,:,sliceNum) * scale + shift;
    view.ph{scanNum}(:,:,sliceNum) = phaseStandardize(view.ph{scanNum}(:,:,sliceNum));
    view.ph{scanNum}(:,:,sliceNum) = mod(view.ph{scanNum}(:,:,sliceNum), 2*pi);
    refreshView(view);
    saveCorAnal(view);
end
dataTYPES(view.curDataType).atlasParams(scanNum).phaseShift(sliceNum) = shift;
dataTYPES(view.curDataType).atlasParams(scanNum).phaseScale(sliceNum) = scale;
saveSession;
return;

function ph = phaseStandardize(ph)
% wrap neagative phases back up to the 2pi end

l = ph<0;
if(~isempty(l))
    ph(l) = ph(l)+2*pi;
end
return;


% difftopo - compute and plot component decomposition for the difference ERP
%            between two EEG datasets. Plots into the current axis (gca);
%            plot into a new empty figure as below.
% Usage:
%          >> figure; difftopo(ALLEEG,eeg1,eeg2,interval);
% Inputs:
%         ALLEEG - array of leaded EEG datasets
%         eeg1   - index of subtrahend (+) dataset
%         eeg2   - index of minuend (-) dataset
%         interval - [minms maxms] latency interval in which to find
%                  and plot largest contributing components {default: whole epoch}
%         limits - [stms endms] latenc plotting limits (in ms) {default|0: whole epoch}
%         subcomps - array of component indices to remove from data
%                  (e.g. eye movement components) {default|0: none}
%
% Outputs: none
%
% Author: Scott Makeig, SCCN/INC/UCSD 3/28/05

% Copyright (C) Scott Makeig, SCCN/INC/UCSD 3/28/05
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
function difftopo(ALLEEG,eeg1,eeg2,interval,limits,subcomps);

if nargin < 3
   help difftopo
   return
end
if eeg1 < 1 | eeg1 > length(ALLEEG)
   help difftopo
   return
end
if eeg2 < 1 | eeg2 > length(ALLEEG)
   help difftopo
   return
end
if eeg1 == eeg2
   help difftopo
   return
end
if ndims(ALLEEG(eeg1).data) ~=3  | ndims(ALLEEG(eeg2).data) ~=3
  error('EEG datasets must be epoched data');
end

if nargin < 4
   interval = [ALLEEG(eeg1).xmin*999.9 ALLEEG(eeg1).xmax*999.9];
end
if nargin < 5
   limits = 0; % [ALLEEG(eeg1).xmin*1000 ALLEEG(eeg1).xmax*1000];
end
if nargin < 6
   subcomps = [];
end

if ~isfield(ALLEEG(eeg1),'icaweights')
  error('EEG datasets must have icaweights');
end
if length(interval) ~= 2
   help difftopo
   return
end

if ALLEEG(eeg1).pnts ~= ALLEEG(eeg1).pnts
  error('EEG datasets must have the same number of frames per epoch');
end

set(gcf,'Name','difftopo()');
diff = mean(ALLEEG(eeg1).data,3) - mean(ALLEEG(eeg2).data,3);

plottitle = [ ALLEEG(eeg1).setname ' - ' ALLEEG(eeg2).setname];
envtopo(diff,ALLEEG(eeg1).icaweights*ALLEEG(eeg1).icasphere,...
       'chanlocs',ALLEEG(eeg1).chanlocs, ...
       'timerange',[ALLEEG(eeg1).xmin*1000 ALLEEG(eeg1).xmax*1000],...
       'limits',limits,...
       'limcontrib',interval,...
       'title',plottitle, ...
       'subcomps',subcomps);


function [formula, protons] = getFormulaFromInChI(InChI)
% Extracts the chemical formula of a given compound from
% the InChI string provided
%
% USAGE:
%
%    [formula, protons] = getFormulaFromInChI(InChI)
%
% INPUT:
%    InChI:      The Inchi String of the chemical formula (e.g. InChI=
%                extract formula from `InChI = 1S/C3H4O3/c1-2(4)3(5)6/h1H3, (H,5,6)/p-1` for pyruvate
%
% OUTPUTS:
%    formula:    The chemical formula (including the protonation state
%    protons:    The total number of protons

[token,rem] = strtok(InChI, '/');
formula=strtok(rem, '/');

%This could be a composite formula, so combine it.
tokens = strsplit(formula,'.');

%The protonation state can also modify the formula! To get it, we remove
%any reconstruction fields, as they do not influence it.
InChI = regexprep(InChI,'/r.*','');
p_layer = regexp(InChI,'/p(.*?)/|/p(.*?)$','tokens');
protonationProtons = 0;
if ~isempty(p_layer)
    individualProtons = cellfun(@(x) {strsplit(x{1},';')},p_layer);
    protonationProtons = cellfun(@(x) sum(cellfun(@(y) eval(y) , x)), individualProtons);
end

%Calc the coefs for all formulas
if (numel(tokens) > 1) || (~isempty(regexp(formula,'(^[0-9]+)'))) || (~isempty(p_layer))
    CoefLists = cellfun(@(x) calcFormula(x), tokens,'UniformOutput',0);
    if ~isempty(p_layer)
        %CoefLists = [CoefLists;{{'H';protonationProtons}}];%was crashing
        %with formula C62H90N13O14P.Co.H2O
        CoefLists{end+1} = {'H';protonationProtons};
    end
    %and now, combine them.
    Elements = {};
    Coefficients = [];
    for i = 1:numel(CoefLists)
        if isempty(CoefLists{i})
            %This should only happen, if there was no actual formula.
            continue
        end
        currentForm = CoefLists{i};
        Elements = [Elements,setdiff(currentForm(1,:),Elements)];
        current_coefs = cell2mat(currentForm(2,:));
        [A,B] = ismember(Elements,currentForm(1,:));
        %Extend the coefficients if necessary
        Coefficients(end+1:numel(Elements)) = 0;
        Coefficients(A) = Coefficients(A)+current_coefs;
    end

    Coefs = num2cell(Coefficients);
    Coefs(cellfun(@(x) x == 1, Coefs)) = {[]};
    Coefs = cellfun(@(x) num2str(x) , Coefs,'UniformOutput',0);
    if nargout > 1
        protons = Coefficients(ismember(Elements,'H'));
    end
    formula = strjoin([Elements , {''}],Coefs);
else
    %had to add this for some inchi, e.g.
    %InChI=1/C21H30O4/c1-19-8-5-14(23)11-13(19)3-4-15-16(19)6-9-20(2)17(15)7-10-21(20,25)18(24)12-22/h11,15-17,22,25H,3-10,12H2,1-2H3/t15-,16+,17+,19+,20+,21+/m1/s1
    protons = numAtomsOfElementInFormula(formula, 'H',0);
end

zero='0';
indZero=strfind(formula,zero);
if ~isempty(indZero)
    if isletter(formula(indZero-1))
        if 0
            warning('Formula contains a zero with a letter preceeding it, replacing with letter.')
            fprintf('%s%s\n','Formula before:, ', formula)
        end
        formula = strrep(formula, formula(indZero-1:indZero), formula(indZero-1));
        if 0
            fprintf('%s%s\n','Formula after:, ', formula)
        end
    end
end

end

function [CoefList] = calcFormula(Formula)
multiplier = 1;
isReplicated = regexp(Formula,'(^[0-9]+)','tokens');
ElementTokens = regexp(Formula,'([A-Z][a-z]?)([0-9]*)','tokens');
Elements = cellfun(@(x) x{1}, ElementTokens,'UniformOutput',0);
Coefs = cellfun(@(x) str2num(x{2}), ElementTokens,'UniformOutput',0);
Coefs(cellfun(@isempty, Coefs)) = {1};

if ~isempty(isReplicated)
    multiplier = str2num(isReplicated{1}{1});
    Coefs = cellfun(@(x) x*multiplier, Coefs,'UniformOutput',0);
end

CoefList = [Elements;Coefs];
end


function [returns,interval] = realized_return_filter(price,time,timeType,samplingType,samplingInterval,subsamples)
% THESE COMMENTS ARE WRONG!!!
% Computes the Quantile Realized Variance of Christensen, Oomen and Podolskij (2008),
% the MinRV and MedRV estimator of Andersen, Dobrev and Shaumberg and the
% general symmetrized version suggested by Sheppard in a discussion of COP
%
% USAGE:
%   [RETURN,INTERVAL] =  realized_return_filter(PRICE,TIME,TIMETYPE,SAMPLINGTYPE,SAMPLINGINTERVAL,SUBSAMPLES)
%
% INPUTS:
%   PRICE            - m by 1 vector of high frequency prices
%   TIME             - m by 1 vector of times where TIME(i) corresponds to PRICE(i)
%   TIMETYPE         - String describing the way times are measured
%                       'wall'    24-hour clock of the form HHMMSS, e.g. 101543 or 153217
%                       'seconds' Time measured in seconds past midnight on the first day.
%                       'unit'  Unit normalized date format, e.g. .1, .234, .9
%                         Unit normalized times are more general than the other types and can be
%                         applied to data from more than one calendar day
%   SAMPLINGTYPE     - String describing the type of sampling to use when
%                        filtering PRICE
%                        'CalendarTime' - Sample in calendar time using observations separated by
%                          SAMPLINGINTERVAL seconds
%                        'CalendarUniform' - Sample in calendar time using SAMPLINGINTERVAL
%                          observations spread uniformly between TIME(1) and TIME(m)
%                        'BusinessTime' - Sample in business (tick) time using observation separated
%                          by SAMPLINGINTERVALticks
%                        'BusinessUniform' - Sample in business (tick) time using observations
%                          uniformly spaced in business time.
%                        'Fixed' - Sample at specific points in time. When using fixed,
%                          SAMPLINGINTERVAL must be a n by 1 vector of times with the same TIMETYPE
%                          as TIME (i.e. seconds if TIME is in seconds)
%   SAMPLINGINTERVAL - Scalar integer or n by 1 vector whose meaning depends on the selected SAMPLINGTYPE
%   SUBSAMPLES       - [OPTIONAL] Integer value containing the number of subsamples to use when
%                        computing RRSS. It must be the case that SUBSAMPLE<SAMPLESPERBIN. Setting
%                        SUBSAMPLES>0 will produce an estimator based on jittering the starting
%                        point over floor(linspace(0,(SUBSAMPLES)/(SUBSAMPLES+1),SUBSAMPLES+1)*SAMPLESPERBIN)+1
%                        For example, if SUBSAMPLES = 3 and SAMPLESPERBIN = 20, then the starting
%                        points for the four RR estimators will be observations 1, 6, 11 and 16.  If
%                        omitted SUBSAMPLE = 0 and RRSS=RR.
%
% OUTPUTS:
%   RETURNS          - Quantile realized variance vector (k by 1) corresponding to the values in QUANTILES
%   INTERVAL         - Subsample based version of RQ.  RQSS = RQ if SUBSAMPLES = 0
%
% COMMENTS:
%
% EXAMPLES:
%
%

% Copyright: Kevin Sheppard
% kevin.sheppard@economics.ox.ac.uk
% Revision: 1    Date: 5/1/2008

%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% InputChecking
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if nargin<5 || nargin>6
    error('Seven or eight inputs required.')
end

if size(price,2)>size(price,1)
    price=price';
end
if size(price,2)>1
    error('PRICE must be a m by 1 vector.')
end
if size(time,2)>size(time,1)
    time=time';
end
if any(diff(time)<0)
    error('TIME must be sorted and increasing')
end
if size(time,2)>1 || length(time)~=length(price)
    error('TIME must be a m by 1 vector.')
end
% Inserted to protect against inputing integer times
time = double(time);

timeType=lower(timeType);
if ~ismember(timeType,{'wall','seconds','unit'})
    error('TIMETYPE must be one of ''wall'', ''seconds'' or ''unit''.');
end
samplingType=lower(samplingType);
if ~ismember(samplingType,{'calendartime','calendaruniform','businesstime','businessuniform','fixed'})
    error('SAMPLINGTYPE must be one of ''CalendarTime'', ''CalendarUniform'', ''BusinessTime'', ''BusinessUniform'' or ''Fixed''.');
end

m=size(price,1);
t0=time(1);
tT=time(m);
if ismember(samplingType,{'calendartime','calendaruniform','businesstime','businessuniform'})
    % Must be a scalar integer
    if ~isscalar(samplingInterval) || floor(samplingInterval)~=samplingInterval || samplingInterval<1
        error('SAMPLINGINTERVAL must be a positive integer for the SAMPLINGTYPE selected.')
    end
else
    if size(samplingInterval,2)>size(samplingInterval,1)
        samplingInterval=samplingInterval';
    end
    if ~(any(samplingInterval>=t0) && any(samplingInterval<=tT))
        error('At least one sampling interval must be between min(TIME) and max(TIME) when using ''Fixed'' as SAMPLINGTYPE.')
    end
    if any(diff(samplingInterval)<=0)
        error('When using ''Fixed'' as SAMPLINGTYPE the vector of sampling times in SAMPLINGINTERVAL must be sorted and strictly increasing.')
    end
end

% SUBSAMPLES
if nargin==6 && ~isempty(subsamples)
    if ~isscalar(subsamples) || subsamples<0 || floor(subsamples)~=subsamples
        error('SUBSAMPLES must be a non-negative integer.')
    end
else
    subsamples=0;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Input Checking
%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Convert if wall to compute the interval
if strcmp(timeType,'wall')
    time=wall2seconds(time);
    timeType = 'seconds';
end

% Initialize the return cell arrays and the interval vector
returns=cell(subsamples+1,1);
interval=zeros(subsamples+1,1);
% 1. Filter the price
logPrice = log(price);
[filteredLogPrice,filteredTimes] = realized_price_filter(logPrice ,time,timeType,samplingType,samplingInterval);
returns{1} = diff(filteredLogPrice);
interval(1) = 1;

if subsamples>0
    % Initialize the place holder for rvSS and rvAdjustment
    % Get the number of filtered times
    n = size(filteredTimes,1);
    % Compute the length of time used in computing the realized variance to
    % bias adjust the subsample RVs
    baseDifference = filteredTimes(n) - filteredTimes(1);
    switch lower(samplingType)
        case {'calendartime','calendaruniform','fixed'}
            % Uniform sampling in CT so the gap is constant
            gap=diff(filteredTimes);
            % The stepsize is constant
            step = gap /(subsamples+1);
            if ismember(samplingType,{'calendartime','calendaruniform'})
                step = [step;mean(step)];
            else
                step = [step;step(length(step))];
            end
            for i=1:subsamples
                thisSampleTime = filteredTimes;
                % Need to compute times for this subsample
                thisSampleTime = thisSampleTime(1:n)+i*step;
                % Use these times to filter the price
                filteredLogPrice = realized_price_filter(logPrice,time,'unit','fixed',thisSampleTime);
                % Compute returns
                returns{i+1} = diff(filteredLogPrice);
                % Compute the ith subsample RV
                % The adjustment depends on the amount of time used in this
                % subsample relative to the full sample RV
                interval(i+1) = (thisSampleTime(n-1)-thisSampleTime(1))/baseDifference;
            end
        case {'businesstime', 'businessuniform'}
            % Uniform sampling in business time
            if strcmp(samplingType,'businesstime')
                % If BT then samplingInterval contains the number of ticks to skip
                originalIndices = 1:samplingInterval:m;
                if ~ismember(m,originalIndices)
                    originalIndices = [originalIndices m];
                end
                gap=samplingInterval;
            else
                % If businessuniform then gap will be average
                originalIndices = floor(linspace(1,m,samplingInterval));
                if ~ismember(m,originalIndices)
                    originalIndices = [originalIndices m];
                end
                gap = m/samplingInterval;
            end
            % The step size is constant
            step = gap/(subsamples+1);
            for i=1:subsamples
                % The indices indicate which points to use since the
                % sampling is linear in ticks
                indices = floor(originalIndices + step*i);
                indices(indices>m) = m;
                returns{i+1} = diff(logPrice(indices));
                interval(i+1) = (time(max(indices))-time(min(indices)))/baseDifference;
            end
    end
end


report_this_filefun(mfilename('fullpath'));

[lat,lon] = meshgrat(tmap,tmapleg);
%gx = rex(1,:);
%gy = rey(:,1)';

% tmap = km2deg(tmap/1);
% [X , Y]  = meshgrid(gx,gy);

ren = interp2(XB,YB,ZB,lon,lat);

l = ren < -8.8; ren(l) = -8.8;
mi = min(min(ren));

l = isnan(ren);
ren(l) = mi-2;

figure_w_normalized_uicontrolunits('pos',[150 100 600 500])

hold on; axis off
axm1 = axesm('MapProjection','eqaconic','MapParallels',[],...
    'MapLatLimit',[s4_south s3_north],'MapLonLimit',[s2_west s1_east])

meshm(ren,tmapleg,size(tmap),tmap);

daspectm('m',3);
tightmap
view([0 90])
camlight; lighting phong
set(gca,'projection','perspective');

load worldlo
%h = displaym(POline); set(h(1),'color',[0.9 0.9 0.9],'Linewidth',1.7)
% h2 = displaym(PPpoint);
%   h = displaym(PPtext); trimcart(h);

pl = plotm(ms(:,1), ms(:,2),'ow','Linewidth',1.4);
set(pl,'LineWidth',1,'MarkerSize',3,...
    'MarkerFaceColor',[0.8 0.8 0.8 ],'MarkerEdgeColor',[ 0.8 0.8 0.8  ])

plmag = 4.
l = a.Date > t0+4/365 & a.Date < t0+34/365 & a.Magnitude >= plmag & a.Magnitude < 5;

pl = plotm(a(l,2),a(l,1),'ow','Markersize',9);
set(pl,'LineWidth',1,'MarkerSize',6,...
    'MarkerFaceColor',[1 1 1 ],'MarkerEdgeColor',[ 0 0 0  ])

l = a.Date > t0+4/365 & a.Date < t0+34/365 & a.Magnitude >= 5.0 ;
pl = plotm(a(l,2),a(l,1),'^w','Markersize',9);
set(pl,'LineWidth',1,'MarkerSize',10,...
    'MarkerFaceColor',[1 1 1 ],'MarkerEdgeColor',[ 0 0 0  ])

% pl = plotm(a.Latitude,a.Longitude,'+k');
%set(pl,'LineWidth',0.5,'MarkerSize',2,...
%   'MarkerFaceColor','k','MarkerEdgeColor','k')
pl = plotm(main(:,2),main(:,1),'hw');
set(pl,'LineWidth',1,'MarkerSize',20,...
    'MarkerFaceColor','w','MarkerEdgeColor','k')

zdatam(handlem('allline'),2000) % keep line on surface
%zdatam(handlem('alltext'),10000) % keep line on surface
caxis([0.0 0.22])
j = hsv;
%j = j(64:-1:1,:);
j = [ [ 0.9 0.9 0.9] ; j];

colormap(j); brighten(0.0);

axis off; set(gcf,'color','w')

setm(gca,'ffacecolor','w')
setm(gca,'fedgecolor','k','flinewidth',3);
setm(gca,'mlabellocation',0.25)
setm(gca,'meridianlabel','on')
setm(gca,'plabellocation',0.25)
setm(gca,'parallellabel','on')
setm(gca,'Fontcolor','k','Fontweight','normal','FontSize',10,'Labelunits','dm')

h5 = colorbar;
set(h5,'position',[0.71 0.44 0.017 0.45],'TickDir','out','Ycolor','k','Xcolor','k',...
    'Fontweight','bold','FontSize',14,'Ticklength',[0.02 0.08],'Yticklabel',[]);
set(gcf,'Inverthardcopy','off');

sc =   scaleruler('RulerStyle','lines','MajorTick',0:15:30,'Linewidth',1,'color','k',...
    'MajorTickLength',2,'XLoc',-0.003,'YLoc',0.5663,'Zloc',40000,'FontSize',9,'Fontweight','normal',...
    'MinorTick',0:5:10,'color',[0 0 0 ],'TickDir','down')

return

scaleruler

setm(handlem('scaleruler'),'XLoc',-0.0,'YLoc',0.566,'Zloc',4000)
setm(handlem('scaleruler'),'MajorTick',0:10:30,...
    'MinorTick',0:5:10,'TickDir','down',...
    'MajorTickLength',(3),...
    'MinorTickLength',(3),'Linewidth',8)
%setm(handlem('scaleruler'),'RulerStyle','ruler')
setm(handlem('scaleruler1'),'RulerStyle','lines')


function [pE,pC] = spm_L_priors(dipfit,pE,pC)
% prior moments for the lead-field parameters of ERP models
% FORMAT [pE,pC] = spm_L_priors(dipfit)
%
% dipfit    - forward model structure:
%
%    dipfit.type     - 'ECD', 'LFP' or 'IMG'
%    dipfit.symmetry - distance (mm) for symmetry constraints (ECD)
%    dipfit.location - allow changes in source location       (ECD)
%    dipfit.Lpos     - x,y,z source positions (mm)            (ECD)
%    dipfit.Nm       - number of modes                        (IMG)
%    dipfit.Ns       - number of sources
%    dipfit.Nc       - number of channels
%
% pE - prior expectation
% pC - prior covariance
%
% adds spatial parameters
%--------------------------------------------------------------------------
%    pE.Lpos - position                    - ECD
%    pE.L    - orientation                 - ECD
%              coefficients of local modes - Imaging
%              gain of electrodes          - LFP
%    pE.J    - contributing states (length(J) = number of states per source
%
%__________________________________________________________________________
%
% David O, Friston KJ (2003) A neural mass model for MEG/EEG: coupling and
% neuronal dynamics. NeuroImage 20: 1743-1755
%__________________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Karl Friston
% $Id: spm_L_priors.m 7409 2018-08-27 11:39:00Z bernadette $

% defaults
%--------------------------------------------------------------------------
try, model    = dipfit.model;    catch, model    = 'LFP'; end
try, type     = dipfit.type;     catch, type     = 'LFP'; end
try, location = dipfit.location; catch, location = 0;     end
try, pC;                         catch, pC       = [];    end

% number of sources
%--------------------------------------------------------------------------
try
    n = dipfit.Ns;
    m = dipfit.Nc;
catch
    n = dipfit;
    m = n;
end

% location priors (4 mm)
%--------------------------------------------------------------------------
if location, V = 2^2; else, V = 0; end

% parameters for electromagnetic forward model
%==========================================================================
switch type

    case{'ECD'} % mean           and variance
        %------------------------------------------------------------------
        pE.Lpos = dipfit.Lpos;   pC.Lpos = ones(3,n)*V;    % positions
        pE.L    = zeros(3,n);    pC.L    = ones(3,n)*64;   % orientations

        Sc = find(~cellfun(@isempty,dipfit.silent_source)); % silence sources for CSD
        if(Sc); pC.L(:,Sc) = pC.L(:,Sc)*0; end

    case{'IMG'}
        %------------------------------------------------------------------
        m       = dipfit.Nm;                               % number modes
        pE.Lpos = sparse(3,0);   pC.Lpos = sparse(3,0);    % positions
        pE.L    = zeros(m,n);    pC.L    = ones(m,n)*64;   % modes

        Sc = find(~cellfun(@isempty,dipfit.silent_source)); % silence sources for CSD
        if(Sc); pC.L(:,Sc) = pC.L(:,Sc)*0; end

    case{'LFP'}
        %------------------------------------------------------------------
        pE.Lpos = sparse(3,0);   pC.Lpos = sparse(3,0);    % positions
        pE.L    = ones(1,m);     pC.L    = ones(1,m)*64;   % gains

    otherwise
        warndlg('Unknown spatial model')

end

% contributing states (encoded in J)
%==========================================================================
if ischar(model), mod.source = model; model = mod; end
pE.J = {};
pC.J = {};

for i = 1:numel(model)

    switch upper(model(i).source)

        case{'ERP','SEP'}
            %--------------------------------------------------------------
            pE.J{end + 1} = sparse(1,9,1,1,9);               % 9 states
            pC.J{end + 1} = sparse(1,[1 7],1/32,1,9);

        case{'CMC','TFM'}
            %--------------------------------------------------------------
            pE.J{end + 1} = sparse(1,3,1,1,8);               % 8 states
            pC.J{end + 1} = sparse(1,[1 7],1/32,1,8);

        case{'LFP'}
            %--------------------------------------------------------------
            pE.J{end + 1} = sparse(1,9,1,1,13);              % 13 states
            pC.J{end + 1} = sparse(1,[1 7],1/32,1,13);

        case{'NMM'}
            %--------------------------------------------------------------
            pE.J{end + 1} = sparse(1,3,1,1,9);               % 9 states
            pC.J{end + 1} = sparse(1,[1,2],1/32,1,9);

        case{'NMDA'}
            %--------------------------------------------------------------
            pE.J{end + 1} = sparse(1,3,1,1,12);              % 12 states
            pC.J{end + 1} = sparse(1,[1,2],1/32,1,12);

        case{'CMM'}
            %--------------------------------------------------------------
            pE.J{end + 1} = sparse(1,2,1,1,12);              % 12 states
            pC.J{end + 1} = sparse(1,[3,4],1/32,1,12);

        case{'CMM_NMDA'}
            %--------------------------------------------------------------
            pE.J{end + 1} = sparse(1,2,1,1,16);              % 12 states
            pC.J{end + 1} = sparse(1,[3,4],1/32,1,16);

        case{'MFM'}
            %--------------------------------------------------------------
            pE.J{end + 1} = sparse(1,3,1,1,36);              % 36 (9 + 27)
            pC.J{end + 1} = sparse(1,[1,2],1/32,1,36);       % states

        case{'DEM','NFM'}
            %--------------------------------------------------------------
            pE.J{end + 1} = [];                              % null
            pC.J{end + 1} = [];

        case{'BGT'}
            %--------------------------------------------------------------
            %assuming data are from STN
            pE.J{end + 1} = sparse(1,5,1,1,10);               % 10 states
            pC.J{end + 1} = sparse(1,10);

        case{'MMC'}
            %--------------------------------------------------------------
            pE.J{end + 1} = sparse(1,[1 3 7],[.2 .2 .6],1,8);   % 8 states
            pC.J{end + 1} = sparse(1,8);

        case{'NULL'}
            %--------------------------------------------------------------
            nx   = size(pE.A,1)/m;
            pE.J{end + 1} = ones(1,nx);                      % nx states
            pC.J{end + 1} = ones(1,nx);

        otherwise
            warndlg('Unknown neural model')

    end

    % Cardinal sources
    %----------------------------------------------------------------------
    if isfield(model(i),'J')
        if numel(model(i).J)
            pE.J{i} = spm_zeros(pE.J{i});
            pE.J{i}(model(i).J) = 1;
        end
    end

    %  subsidiary (free) sources
    %----------------------------------------------------------------------
    if isfield(model(i),'K')
        if numel(model(i).K)
            pC.J{i} = spm_zeros(pE.J{i});
            pC.J{i}(model(i).K) = 1/32;
        end
    end

end

% replace J with a vector if there is only one sort of model
%--------------------------------------------------------------------------
if numel(pE.J) == 1
    pE.J = pE.J{:};
    pC.J = pC.J{:};
end