function [pnt, dhk] = read_off(fn);

% READ_OFF reads vertices and triangles from a OFF format triangulation file
%
% [pnt, dhk] = read_off(filename)
%
% See also READ_TRI, READ_BND

% Copyright (C) 1998, Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.ru.nl/neuroimaging/fieldtrip
% for the documentation and details.
%
%    FieldTrip is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    FieldTrip 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 FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id: read_off.m 945 2010-04-21 17:41:20Z roboos $

fid = fopen(fn, 'rt');
if fid~=-1

  % scan the file type
  [s, count] = fscanf(fid, '%s\n', 1);
  if ~strcmp(s,'OFF')
    msg = sprintf('wrong file type %s', s);
    error(msg);
  end

  % read the number of vertex points and triangles
  [val, count] = fscanf(fid, '%d', 3);
  Npnt = val(1)
  Ndhk = val(2)

  % read the vertex points
  pnt  = fscanf(fid, '%f', [3, Npnt]);
  pnt  = pnt(1:3,:)';

  % read the triangles
  dhk = fscanf(fid, '%d', [4, Ndhk]);
  dhk = (dhk(2:4,:)+1)';
  fclose(fid);

else
  error('unable to open file');
end


% SP_TO_VTK: Export to VTK format for plotting (store data in
%            binary base64 encoded format).
%
%  sp_to_vtk (u, space, geometry, npts, filename,
%             fieldname, [option], [precision])
%  sp_to_vtk (u, space, geometry, pts, filename,
%             fieldname, [option], [precision])
%
% INPUT:
%
%     u:          vector of dof weights
%     space:      object representing the space of discrete functions (see sp_scalar)
%     geometry:   geometry structure (see geo_load)
%     npts:       number of points along each parametric direction where to evaluate
%     pts:        cell array with the coordinates along each parametric direction of the points where to evaluate
%     filename:   name of the output file.
%     fieldname:  how to name the saved variable in the vtk file
%     option:     accepted options are 'value' (default), 'gradient',
%                 and for vectors also 'curl', 'divergence'
%     precision:  accepted options are 32 (default), or 64, other
%                 values are silently ignored
%
%
% OUTPUT:
%
%    a vtk structured mesh file named <filename> is produced, data are
%    base64-encoded and appended at the end of the file to save disk
%    space and write time.
%
% Copyright (C) 2009, 2010, 2014 Carlo de Falco
% Copyright (C) 2011, 2012 Rafael Vazquez
%
%    This program is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.

%    This program is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with this program.  If not, see <http://www.gnu.org/licenses/>.

function sp_to_vtk_raw (u, space, geometry, npts, filename, fieldname, varargin)

  if (nargin == 6)
    option = 'value';
  else
    option = varargin{1};
  end

  if (~(numel (varargin) >= 2) || ~(varargin{2} == 64))
    precision = 32;
  else
    precision = 64;
  end

  [eu, F] = sp_eval (u, space, geometry, npts, option);

  if (space.ncomp == 1 || ~strcmp(option, 'gradient'))
    msh_to_vtk_raw (F, eu, filename, fieldname, precision);
  else
    error ('sp_to_vtk: For vector fields, the gradient cannot be saved')
  end

end


% Make new eyeCatch library

% find ori_map on eyeCatch webiste, filename:
% 'eyeChannelWeightNormalizedpart1.mat' and 'eyeChannelWeightNormalizedpart1.mat'

function new_map = interpo_lib(ori_map, downsize)

[sampleNumber, oldsize] = size(ori_map);
if downsize > sqrt(oldsize)
    error('Downsize map should be smaller than original map.');
end

oldsize = sqrt(oldsize);

% reshape old_map
ori_map = reshape(ori_map, [sampleNumber, oldsize, oldsize]);
new_map = zeros(sampleNumber, downsize^2);

%% resize
for i = 1:sampleNumber
    new_map(i,:) = reshape(imresize(squeeze(ori_map(i,:,:)),[32 32],'nearest'), [1, downsize^2]);
end

% save to mat
filename = 'libEyeCatch';

% for oversize library
% k = 1;
% filename = ['new_lib',int2str(k)];
% while exist([filename,'.mat'],'file')
%     k = k+1;
%     filename = ['new_lib.mat', int2str(k)];
% end

save(filename, 'new_map');

end


function [trl, event] = ft_trialfun_edf(cfg)

% FT_TRIALFUN_EDF is an example trial function for EDF data. It searches for events
% of type "up" in an analog data channel, as indentified by thresholding. This
% threshold can be a hard threshold, i.e. a numeric, or can flexibly be defined
% depending on the data, for example calculating the 'median' of an analog signal.
%
% You can use this as a template for your own conditial trial definitions.
%
% Use this function by calling
%   [cfg] = ft_definetrial(cfg)
% where the configuration structure should contain
%   cfg.dataset  = string with the filename
%   cfg.trialfun = 'ft_trialfun_edf'
%
% See also FT_DEFINETRIAL, FT_TRIALFUN_GENERAL

ft_warning('this trial function is only an example, please copy it and adapt it to your specific EDF situation - see http://www.fieldtriptoolbox.org/getting_started/edf');

% read the header information
hdr           = ft_read_header(cfg.dataset);

% read the events from the data
chanindx      = 1; % this should be adapted to your data
detectflank   = 'up';
threshold     = '(3/2)*nanmedian'; % or, e.g., 1/2 times the median for down flanks
event         = ft_read_event(cfg.dataset, 'trigindx', trigindx, 'detectflank', detectflank, 'threshold', threshold);

% define trials around the events
trl           = [];
pretrig       = 1 * hdr.Fs; % e.g., 1 sec before trigger
posttrig      = 2 * hdr.Fs; % e.g., 2 sec after trigger
for i = 1:numel(event)
  offset    = -hdr.nSamplesPre;  % number of samples prior to the trigger
  trlbegin  = event(i).sample - pretrig;
  trlend    = event(i).sample + posttrig;
  newtrl    = [trlbegin trlend offset];
  trl       = [trl; newtrl]; % store in the trl matrix
end


function [D, optinf] = ccmod(X, S, dsz, opt)

% ccmod -- Convolutional Constrained Method of Optimal Directions (MOD)
%
%         argmin_{d_m} (1/2) \sum_k ||\sum_m x_k,m * d_m - s_k||_2^2
%                      such that ||d_m||_2 = 1
%
%         The solution of the Convolutional Constrained MOD problem
%         (see wohlberg-2016-efficient) is computed using the ADMM
%         approach (see boyd-2010-distributed).
%
% Usage:
%       [D, optinf] = ccmod(X, S, dsz, opt)
%
% Input:
%       X           Coefficient maps (3D array)
%       S           Input images
%       dsz         Dictionary size
%       opt         Algorithm parameters structure
%
% Output:
%       D           Dictionary filter set (3D array)
%       optinf      Details of optimisation
%
%
% Options structure fields:
%   Verbose           Flag determining whether iteration status is displayed.
%                     Fields are iteration number, functional value,
%                     data fidelity term, l1 regularisation term, and
%                     primal and dual residuals (see Sec. 3.3 of
%                     boyd-2010-distributed). The values of rho and sigma
%                     are also displayed if options request that they are
%                     automatically adjusted.
%   MaxMainIter       Maximum main iterations
%   AbsStopTol        Absolute convergence tolerance (see Sec. 3.3.1 of
%                     boyd-2010-distributed)
%   RelStopTol        Relative convergence tolerance (see Sec. 3.3.1 of
%                     boyd-2010-distributed)
%   G0                Initial value for G
%   H0                Initial value for H
%   sigma             ADMM penalty parameter
%   AutoSigma         Flag determining whether sigma is automatically updated
%                     (see Sec. 3.4.1 of boyd-2010-distributed)
%   AutoSigmaPeriod   Iteration period on which sigma is updated
%   SigmaRsdlRatio    Primal/dual residual ratio in sigma update test
%   SigmaScaling      Multiplier applied to sigma when updated
%   AutoSigmaScaling  Flag determining whether SigmaScaling value is
%                     adaptively determined (see wohlberg-2015-adaptive). If
%                     enabled, SigmaScaling specifies a maximum allowed
%                     multiplier instead of a fixed multiplier.
%   StdResiduals      Flag determining whether standard residual definitions
%                     (see Sec 3.3 of boyd-2010-distributed) are used instead
%                     of normalised residuals (see wohlberg-2015-adaptive)
%   RelaxParam        Relaxation parameter (see Sec. 3.4.3 of
%                     boyd-2010-distributed)
%   LinSolve          Linear solver for main problem: 'SM' or 'CG'
%   MaxCGIter         Maximum CG iterations when using CG solver
%   CGTol             CG tolerance when using CG solver
%   CGTolAuto         Flag determining use of automatic CG tolerance
%   CGTolFactor       Factor by which primal residual is divided to obtain CG
%                     tolerance, when automatic tolerance is active
%   ZeroMean          Force learned dictionary entries to be zero-mean
%   AuxVarObj         Flag determining whether objective function is computed
%                     using the auxiliary (split) variable
%
%
% Author: Brendt Wohlberg <brendt@lanl.gov>  Modified: 2015-12-18
%
% This file is part of the SPORCO library. Details of the copyright
% and user license can be found in the 'License' file distributed with
% the library.

if nargin < 4,
  opt = [];
end
checkopt(opt, defaultopts([]));
opt = defaultopts(opt);

% Set up status display for verbose operation
hstr = 'Itn   Obj       Cnst      r         s      ';
sfms = '%4d %9.2e %9.2e %9.2e %9.2e';
nsep = 44;
if opt.AutoSigma,
  hstr = [hstr '   sigma  '];
  sfms = [sfms ' %9.2e'];
  nsep = nsep + 10;
end
if opt.Verbose && opt.MaxMainIter > 0,
  disp(hstr);
  disp(char('-' * ones(1,nsep)));
end

% Collapsing of trailing singleton dimensions greatly complicates
% handling of both SMV and MMV cases. The simplest approach would be
% if S could always be reshaped to 4d, with dimensions consisting of
% image rows, image cols, a single dimensional placeholder for number
% of filters, and number of measurements, but in the single
% measurement case the third dimension is collapsed so that the array
% is only 3d.
if size(S,3) > 1,
  xsz = size(X);
  % Insert singleton 3rd dimension (for number of filters) so that
  % 4th dimension is number of images in input s volume
  S = reshape(S, [size(S,1) size(S,2) 1 size(S,3)]);
else
  xsz = [size(X) 1];
end

% Set dsz to correct form
if numel(dsz) == 3, dsz = dsz(1:2); end

% Mean removal and normalisation projections
Pzmn = @(x) bsxfun(@minus, x, mean(mean(x,1),2));
Pnrm = @(x) normalise(x);

% Projection of filter to full image size and its transpose
% (zero-pad and crop respectively)
Pzp = @(x) zpad(x, xsz(1:2));
PzpT = @(x) bcrop(x, dsz);

% Projection of dictionary filters onto constraint set
if opt.ZeroMean,
  Pcn = @(x) Pnrm(Pzp(Pzmn(PzpT(x))));
else
  Pcn = @(x) Pnrm(Pzp(PzpT(x)));
end

% Start timer
tstart = tic;

% Compute coefficients in DFT domain
Xf = fft2(X, size(S,1), size(S,2));
% Compute signal in DFT domain
Sf = fft2(S);
% S convolved with all coefficients in DFT domain
XSf = sum(bsxfun(@times, conj(Xf), Sf), 4);

% Set up algorithm parameters and initialise variables
sigma = opt.sigma;
if isempty(sigma), sigma = size(S,3); end;
Nd = prod(xsz(1:3));
cgt = opt.CGTol;
optinf = struct('itstat', [], 'opt', opt);
r = Inf;
s = Inf;
epri = 0;
edua = 0;

% Initialise main working variables
D = []; Df = [];
if isempty(opt.G0),
  G = zeros([xsz(1) xsz(2) xsz(3)], class(S));
else
  G = opt.G0;
end
Gprv = G;
if isempty(opt.H0),
  if isempty(opt.G0),
    H = zeros([xsz(1) xsz(2) xsz(3)], class(S));
  else
    H = G;
  end
else
  H = opt.H0;
end

% Main loop
k = 1;
while k <= opt.MaxMainIter && (r > epri | s > edua),

  % Solve subproblems and update dual variable
  if strcmp(opt.LinSolve, 'SM'),
    Df = solvemdbi_ism(Xf, sigma, XSf + sigma*fft2(G - H));
  else
    [Df, cgst] = solvemdbi_cg(Xf, sigma, XSf + sigma*fft2(G - H), ...
                              cgt, opt.MaxCGIter, Df(:));
  end
  D = ifft2(Df, 'symmetric');

  % See pg. 21 of boyd-2010-distributed
  if opt.RelaxParam == 1,
    Dr = D;
  else
    Dr = opt.RelaxParam*D + (1-opt.RelaxParam)*G;
  end

  G = Pcn(Dr + H);
  H = H + Dr - G;

  % Compute data fidelity term in Fourier domain (note normalisation)
  if opt.AuxVarObj,
    Gf = fft2(G); % This represents unnecessary computational cost
    Job = sum(vec(abs(sum(bsxfun(@times,Gf,Xf),3)-Sf).^2))/(2*xsz(1)*xsz(2));
    Jcn = 0;
  else
    Job = sum(vec(abs(sum(bsxfun(@times,Df,Xf),3)-Sf).^2))/(2*xsz(1)*xsz(2));
    Jcn = norm(vec(Pcn(D) - D));
  end

  nD = norm(D(:)); nG = norm(G(:)); nH = norm(H(:));
  if opt.StdResiduals,
    % See pp. 19-20 of boyd-2010-distributed
    r = norm(vec(D - G));
    s = norm(vec(sigma*(Gprv - G)));
    epri = sqrt(Nd)*opt.AbsStopTol+max(nD,nG)*opt.RelStopTol;
    edua = sqrt(Nd)*opt.AbsStopTol+sigma*nH*opt.RelStopTol;
  else
    % See wohlberg-2015-adaptive
    r = norm(vec(D - G))/max(nD,nG);
    s = norm(vec(Gprv - G))/nH;
    epri = sqrt(Nd)*opt.AbsStopTol/max(nD,nG)+opt.RelStopTol;
    edua = sqrt(Nd)*opt.AbsStopTol/(sigma*nH)+opt.RelStopTol;
  end

  if opt.CGTolAuto && (r/opt.CGTolFactor) < cgt,
    cgt = r/opt.CGTolFactor;
  end

  % Record and display iteration details
  tk = toc(tstart);
  optinf.itstat = [optinf.itstat; [k Job Jcn r s epri edua sigma tk]];
  if opt.Verbose,
    if opt.AutoSigma,
      disp(sprintf(sfms, k, Job, Jcn, r, s, sigma));
    else
      disp(sprintf(sfms, k, Job, Jcn, r, s));
    end
  end

  % See wohlberg-2015-adaptive and pp. 20-21 of boyd-2010-distributed
  if opt.AutoSigma,
    if k ~= 1 && mod(k, opt.AutoSigmaPeriod) == 0,
      if opt.AutoSigmaScaling,
        sigmlt = sqrt(r/s);
        if sigmlt < 1, sigmlt = 1/sigmlt; end
        if sigmlt > opt.SigmaScaling, sigmlt = opt.SigmaScaling; end
      else
        sigmlt = opt.SigmaScaling;
      end
      ssf = 1;
      if r > opt.SigmaRsdlRatio*s, ssf = sigmlt; end
      if s > opt.SigmaRsdlRatio*r, ssf = 1/sigmlt; end
      sigma = ssf*sigma;
      H = H/ssf;
    end
  end

  Gprv = G;
  k = k + 1;

end

% Record run time and working variables
optinf.runtime = toc(tstart);
optinf.D = D;
optinf.G = G;
optinf.H = H;
optinf.sigma = sigma;
optinf.cgt = cgt;
if exist('cgst'), optinf.cgst = cgst; end

D = PzpT(G);

if opt.Verbose && opt.MaxMainIter > 0,
  disp(char('-' * ones(1,nsep)));
end

return

function u = vec(v)

  u = v(:);

return

function u = normalise(v)

  nrm = sqrt(sum(sum(v.^2, 1), 2));
  nrm(nrm == 0) = 1;
  u = bsxfun(@rdivide, v, nrm);

return

function u = zpad(v, sz)

  u = zeros(sz(1), sz(2), size(v,3), size(v,4), class(v));
  u(1:size(v,1), 1:size(v,2),:,:) = v;

return

function u = bcrop(v, sz)

  if numel(sz) <= 2,
    if numel(sz) == 1
      cs = [sz sz];
    else
      cs = sz;
    end
    u = v(1:cs(1), 1:cs(2), :);
  else
    if size(sz,1) < size(sz,2), sz = sz'; end
    cs = max(sz);
    u = zeros(cs(1), cs(2), size(v,3));
    for k = 1:size(v,3),
      u(1:sz(k,1), 1:sz(k,2), k) = v(1:sz(k,1), 1:sz(k,2), k);
    end
  end

return

function opt = defaultopts(opt)

  if ~isfield(opt,'Verbose'),
    opt.Verbose = 0;
  end
  if ~isfield(opt,'MaxMainIter'),
    opt.MaxMainIter = 200;
  end
  if ~isfield(opt,'AbsStopTol'),
    opt.AbsStopTol = 1e-6;
  end
  if ~isfield(opt,'RelStopTol'),
    opt.RelStopTol = 1e-4;
  end
  if ~isfield(opt,'G0'),
    opt.G0 = [];
  end
  if ~isfield(opt,'H0'),
    opt.H0 = [];
  end
  if ~isfield(opt,'sigma'),
    opt.sigma = [];
  end
  if ~isfield(opt,'AutoSigma'),
    opt.AutoSigma = 0;
  end
  if ~isfield(opt,'AutoSigmaPeriod'),
    opt.AutoSigmaPeriod = 10;
  end
  if ~isfield(opt,'SigmaRsdlRatio'),
    opt.SigmaRsdlRatio = 10;
  end
  if ~isfield(opt,'SigmaScaling'),
    opt.SigmaScaling = 2;
  end
  if ~isfield(opt,'AutoSigmaScaling'),
    opt.AutoSigmaScaling = 0;
  end
  if ~isfield(opt,'StdResiduals'),
    opt.StdResiduals = 0;
  end
  if ~isfield(opt,'RelaxParam'),
    opt.RelaxParam = 1;
  end
  if ~isfield(opt,'LinSolve'),
    opt.LinSolve = 'SM';
  end
  if ~isfield(opt,'MaxCGIter'),
    opt.MaxCGIter = 1000;
  end
  if ~isfield(opt,'CGTol'),
    opt.CGTol = 1e-3;
  end
  if ~isfield(opt,'CGTolAuto'),
    opt.CGTolAuto = 0;
  end
  if ~isfield(opt,'CGTolAutoFactor'),
    opt.CGTolFactor = 50;
  end
  if ~isfield(opt,'ZeroMean'),
    opt.ZeroMean = 0;
  end
  if ~isfield(opt,'AuxVarObj'),
    opt.AuxVarObj = 0;
  end

return


function [ im_data ] = prepare_img_deng( im_data, mean_data, im_size_h,im_size_w )
%PREPARE_IMG Summary of this function goes here
%   Detailed explanation goes here
% Convert an image returned by Matlab's imread to im_data in caffe's data
% format: W x H x C with BGR channels
im_data = im_data(:, :, [3, 2, 1]);  % permute channels from RGB to BGR
im_data = permute(im_data, [2, 1, 3]);  % flip width and height
im_data = single(im_data);  % convert from uint8 to single
im_data = imresize(im_data, [im_size_w im_size_h ], 'bilinear');  % resize im_data
im_data = im_data - mean_data;  % subtract mean_data (already in W x H x C, BGR)
end


%GETCOST Get classification cost matrix
%
%  [COST,LABLIST] = GETCOST(A)
%
% Returns the classification cost matrix as defined for the dataset A.
% An empty cost matrix is interpreted as equal costs for misclassification.
% In that case COST = ONES(C+1) - EYE(C+1) is returned, if C is the number
% of classes. Row C+1 and column C+1 in COST refer to unlabeld objects.
% In LABLIST the class labels are returned.
%
% If A has target labels an error is returned as in that case no classes
% and thereby no costs are defined.
%
% See DATASETS


function [gx,dgdx,dgdp] = g_DCMwHRFext(Xt,P,ut,in)

%- initializations
idX1 = 1:in.n5(end);
nreg=length(in.n5);
nresp=length(in.r);

gxr=zeros(nresp,1);
dgdxr=zeros(length(Xt),nresp);
dgdpr=zeros(length(P),nresp);

%== compute gradients
[gxn,dgdxn,dgdpn] = g_HRF3(Xt(idX1),P,ut,in) ;
for iR = 1:numel(in.sourceRespIdx)
    respIdx = in.sourceRespIdx{iR};
    idRinX = in.r(respIdx);
    idRinPhi = in.indr(iR);
    [gxr(respIdx),dgdxr(idRinX,respIdx),dgdpr(idRinPhi,respIdx)] = g_softmax4decoding(Xt(idRinX),P(idRinPhi),ut,in);
end
%== concatenate BOLD and behavioral responses
%- state
gx = [gxn ; gxr] ;

%- Jacobian
dgdx = zeros(length(Xt),length(gx));
dgdx(idX1,1:nreg) = dgdxn ;
dgdx(:,nreg+(1:nresp)) = dgdxr ;

%- gradient wrt parameters
dgdp = zeros(length(P),nreg+nresp);
dgdp(1:size(dgdpn,1),1:nreg) = dgdpn ;
dgdp(:,nreg+(1:nresp)) = dgdpr ;

end


classdef tattention < matlab.unittest.TestCase
    % tattention   Tests for transformer.layer.attention

    % Copyright 2020 The Mathworks, Inc.

    % The attention function has 3 purposes:
    % 1. Apply the pre and post attention fully connected layers.
    % 2. Rearrange data format for applying multi-head attention.
    % 3. Preserve the key and value matrices, and append to them when using
    % values from the past. This is done pre-attention.

    properties(Constant,Access=private)
        attention = @transformer.layer.attention
        multiheadAttention = @transformer.layer.multiheadAttention
    end

    properties(TestParameter)
        NumQueries = {1,2}
        NumObs = {1,3}
    end

    methods(Test)
        function checkSingleHeadNoFullyConnected(test,NumQueries,NumObs)
            % Verify that multiheadAttention is used.
            % Do this by setting the fully connected weights to identity
            % and the bias to 0.
            % With a single head we do not need split and merge heads.
            latentDim = 10;
            hyperParams.NumHeads = 1;
            past = [];
            % Set up the fc weights to be identity matrices and biases to
            % be 0.
            weights = test.prepareWeightsStructWithIdentityFC(hyperParams.NumHeads,latentDim);
            % Call attention on an arbitrary input.
            x = dlarray(rand(latentDim*3,NumQueries,NumObs));
            yAct = test.attention(x,past,weights,hyperParams);
            % Verify against multiheadAttention by splitting the arbitrary
            % input into query, key and value.
            [q,k,v] = iSplitQKV(x,hyperParams.NumHeads,latentDim);
            yExp = test.multiheadAttention(q,k,v);
            % Note that for numObs > 1 we need to merge heads. Since we
            % have a single head here, no merger needs to take place -- we
            % just need to permute the observation dimension from 4 to 3
            yExp = permute(yExp, [1 2 4 3]);
            test.verifyEqual(yAct,yExp);
        end

        function checkMultiHeadNoFullyConnected(test,NumQueries,NumObs)
            % Verify the multiple head case. Multi head attention is
            % achieved by simply creating a "head dimension" and pushing it
            % to the back so that it is treated as a "batch"
            % dimension for matrix multiplication.
            latentDim = 10;
            hyperParams.NumHeads = 2;
            past = [];
            % Set up the fc weights to be identity matrices and biases to
            % be 0.
            weights = test.prepareWeightsStructWithIdentityFC(hyperParams.NumHeads,latentDim);
            % Call attention on an arbitrary input.
            x = dlarray(rand(latentDim*hyperParams.NumHeads*3,NumQueries,NumObs));
            yAct = test.attention(x,past,weights,hyperParams);
            [Q,K,V] = iSplitQKV(x,hyperParams.NumHeads,latentDim);
            % Verify against the multiheadAttention function.
            yExp = test.multiheadAttention(Q,K,V);
            yExp = iMergeHeads(yExp);
            test.verifyEqual(yAct,yExp);
        end

        function checkPastPresentCaching(test,NumQueries,NumObs)
            % Verify the 2nd input and output of attention - the pasts
            % passed in are the keys and values for the previous time step.
            % These are concatenated to the keys and values for the current
            % time step before the multiheadAttention call, and these
            % concatenated key and values are passed out as a second
            % output.
            latentDim = 10;
            hyperParams.NumHeads = 2;
            % Set up a fake past by making an initial call to attention.
            past = [];
            % Set up the fc weights to be identity matrices and biases to
            % be 0.
            weights = test.prepareWeightsStructWithIdentityFC(hyperParams.NumHeads,latentDim);
            % Call attention on an arbitrary input.
            x = dlarray(rand(latentDim*hyperParams.NumHeads*3,NumQueries,NumObs));
            [~,past] = test.attention(x,past,weights,hyperParams);
            % Verify the expected value of past - it is the key and values
            % concatenated on the 4th dimension.
            [~,K,V] = iSplitQKV(x,hyperParams.NumHeads,latentDim);
            test.verifyEqual(past,cat(5,K,V));
            % Now verify second call to attention is possible with the first
            % past as input - and verify the value of the attention output.
            [yAct,present] = test.attention(x,past,weights,hyperParams);
            [Q,K,V] = iSplitQKV(x,hyperParams.NumHeads,latentDim);
            % Verify the correct value for present.
            pastK = past(:,:,:,:,1);
            pastV = past(:,:,:,:,2);
            test.verifyEqual(extractdata(present),extractdata(cat(5,cat(2,pastK,K),cat(2,pastV,V))),'AbsTol',1e-5);
            % To compute the expected value, concatenate the pasts
            K = cat(2,K,pastK);
            V = cat(2,V,pastV);
            yExp = test.multiheadAttention(Q,K,V);
            yExp = iMergeHeads(yExp);
            test.verifyEqual(extractdata(yAct),extractdata(yExp),'AbsTol',1e-5);
        end

        function checkInputOutputFC(test,NumQueries,NumObs)
            % The tests above ensure multiheadAttention is used by
            % attention. Now verify the input and output FC operations are
            % used.
            latentDim = 10;
            hyperParams.NumHeads = 2;
            % Set up a fake past by making an initial call to attention.
            past = [];
            params = test.prepareWeightsStructUsingGenerators(hyperParams.NumHeads,latentDim,@randn,@randn);
            % Call attention on an arbitrary input.
            x = dlarray(rand(latentDim*hyperParams.NumHeads*3,NumQueries,NumObs));
            yAct = test.attention(x,past,params,hyperParams);
            % Verify this matches the full attention implementation
            z = fullyconnect(x,params.attn_c_attn_w_0,params.attn_c_attn_b_0,'DataFormat','CBT');
            [Q,K,V] = iSplitQKV(z,hyperParams.NumHeads,latentDim);
            z = test.multiheadAttention(Q,K,V);
            z = iMergeHeads(z);
            yExp = fullyconnect(z,params.attn_c_proj_w_0,params.attn_c_proj_b_0,'DataFormat','CBT');
            test.verifyEqual(extractdata(yAct),extractdata(yExp),'AbsTol',1e-5);
        end

        function defaultIsMaksed(test)
            % Verify the default for the 'CausalMask' NVP is true
            latentDim = 10;
            hyperParams.NumHeads = 2;
            past = [];
            numQueries = 2;
            % Set up the fc weights to be identity matrices and biases to
            % be 0.
            weights = test.prepareWeightsStructWithIdentityFC(hyperParams.NumHeads,latentDim);
            % Call attention on an arbitrary input.
            x = dlarray(rand(latentDim*hyperParams.NumHeads*3,numQueries));
            default = test.attention(x,past,weights,hyperParams);
            masked = test.attention(x,past,weights,hyperParams,'CausalMask',true);
            test.verifyEqual(extractdata(default),extractdata(masked));
        end

        function canTurnOffMask(test)
            % Verify the 'CausalMask' NVP can be set to false - the expectation
            % is this simply sets 'Masked' to false for the
            % multiheadAttention call.
            latentDim = 10;
            hyperParams.NumHeads = 2;
            past = [];
            numQueries = 2;
            % Set up the fc weights to be identity matrices and biases to
            % be 0.
            weights = test.prepareWeightsStructWithIdentityFC(hyperParams.NumHeads,latentDim);
            % Call attention on an arbitrary input.
            x = dlarray(rand(latentDim*hyperParams.NumHeads*3,numQueries));
            yAct = test.attention(x,past,weights,hyperParams,'CausalMask',false);
            [Q,K,V] = iSplitQKV(x,hyperParams.NumHeads,latentDim);
            % Verify against the multiheadAttention function with 'Masked'
            % set to false.
            yExp = test.multiheadAttention(Q,K,V,'CausalMask',false);
            yExp = iMergeHeads(yExp);
            test.verifyEqual(yAct,yExp);
        end

        function canDropout(test)
            % Verify dropout can be applied to attention - the expectation
            % is that this matches simply setting the Dropout NVP in the
            % multiheadAttention call
            latentDim = 10;
            hyperParams.NumHeads = 2;
            past = [];
            numQueries = 2;
            % Set up the fc weights to be identity matrices and biases to
            % be 0.
            weights = test.prepareWeightsStructWithIdentityFC(hyperParams.NumHeads,latentDim);
            % Call attention on an arbitrary input.
            x = dlarray(rand(latentDim*hyperParams.NumHeads*3,numQueries));
            p = 0.5;
            % Set global rng between non-deterministic calls.
            rng(0);
            yAct = test.attention(x,past,weights,hyperParams,'Dropout',p);
            [Q,K,V] = iSplitQKV(x,hyperParams.NumHeads,latentDim);
            % Verify against the multiheadAttention function with 'Dropout'
            % set to p
            % Set global rng between non-deterministic calls.
            rng(0);
            yExp = test.multiheadAttention(Q,K,V,'Dropout',p);
            yExp = iMergeHeads(yExp);
            test.verifyEqual(yAct,yExp);
        end

        function defaultIsNoDropout(test)
            % Verify the default Dropout is 0.
            latentDim = 10;
            hyperParams.NumHeads = 2;
            numQueries = 2;
            % Set up a fake past by making an initial call to attention.
            past = [];
            params = test.prepareWeightsStructUsingGenerators(hyperParams.NumHeads,latentDim,@randn,@randn);
            % Call attention on an arbitrary input.
            x = dlarray(rand(latentDim*hyperParams.NumHeads*3,numQueries));
            yDefault = test.attention(x,past,params,hyperParams);
            yNoDropout = test.attention(x,past,params,hyperParams,'Dropout',0);
            test.verifyEqual(yDefault,yNoDropout);
        end
    end

    methods(Access=private)
        function s = prepareWeightsStruct(~,W1,b1,W2,b2)
            % Prepare a struct compatible with the weights input of
            % attention. These are for the fully connected layers.
            s = struct(...
                'attn_c_attn_w_0',W1,...
                'attn_c_attn_b_0',b1,...
                'attn_c_proj_w_0',W2,...
                'attn_c_proj_b_0',b2);
        end

        function s = prepareWeightsStructUsingGenerators(test,nHeads,latentDim,weightGenerator,biasGenerator)
            % Use function handles weightGenerator and biasGenerator to
            % create weight and bias values for the fc layers in attention.
            % The expectation is these function handles map a size vector
            % to an array of that size.

            % The query, key and value vectors are flattened into 1
            % dimension for the input.
            % There are nHeads of each, and each is a latentDim
            % dimensional vector
            inputDim = 3*nHeads*latentDim;
            W1 = dlarray(weightGenerator([inputDim,inputDim]));
            b1 = dlarray(biasGenerator([inputDim,1]));

            % For the output we don't need the 3 - the multiheadAttention
            % has taken an expectation of the value vectors under some
            % probability distribution.
            outputDim = nHeads*latentDim;
            W2 = dlarray(weightGenerator([outputDim,outputDim]));
            b2 = dlarray(biasGenerator([outputDim,1]));
            s = test.prepareWeightsStruct(W1,b1,W2,b2);
        end

        function s = prepareWeightsStructWithIdentityFC(test,nHeads,latentDim)
            % Prepare a struct compatible with the weights input of
            % attention such that the fc layers are identity operations.
            s = test.prepareWeightsStructUsingGenerators(nHeads,latentDim,@eye,@zeros);
        end
    end
end

function [Q,K,V] = iSplitQKV(X, nHeads, latentDim)
% Split an input array X into the corresponding Q, K and V arrays.
splitSize = latentDim*nHeads;
Q = iSplitHeads(X(1:splitSize,:,:),splitSize,nHeads);
K = iSplitHeads(X((splitSize+1):2*splitSize,:,:),splitSize,nHeads);
V = iSplitHeads(X((2*splitSize+1):3*splitSize,:,:),splitSize,nHeads);
end

function X = iSplitHeads(X, splitSize, numHeads)
X = reshape(X, splitSize/numHeads, numHeads, [], size(X,3));   % Split states
X = permute(X,[1 3 2 4]);
end

function X = iMergeHeads(X)
X = permute(X, [1 3 2 4]);
X = reshape(X, size(X,1)*size(X,2), [], size(X,4));            % Merge states
end


function losses = loss_func(o)
% Compute the loss associated with the intersection over union
% overlap between a ground-truth bounding box and any other
% windows.
%   losses = loss_func(o)
%
% Return value
%   losses    Loss for each element in the input
%
% Argument
%   o         Vector of overlap values

% AUTORIGHTS
% -------------------------------------------------------
% Copyright (C) 2011-2012 Ross Girshick
%
% This file is part of the voc-releaseX code
% (http://people.cs.uchicago.edu/~rbg/latent/)
% and is available under the terms of an MIT-like license
% provided in COPYING. Please retain this notice and
% COPYING if you use this file (or a portion of it) in
% your project.
% -------------------------------------------------------

% The PASCAL VOC detection task loss
% Loss is 0 for IoU >= 0.5
% Loss is 1 for IoU < 0.5
losses = zeros(size(o));
I = find(o < 0.5);
losses(I) = 1.0;


image = imread('Training4.png');
trimap = imread('Training4Trimap.png');

% Closed-form matting
a_cf = closedFormMatting(image, trimap);
% Some alternatives:
% a_ifm = informationFlowMatting(image, trimap);
% a_knn = KNNMatting(image, trimap);

% Get the parameter struct and edit for customization if desired
params = getMattingParams('IFM');
params.useKnownToUnknown = 0;
% params.iu_xyw = 0.1;
% params.loc_mult = 3;
a_ifm = informationFlowMatting(image, trimap, params);

% Trim the trimap
trimmed = patchBasedTrimming(image, trimap);
% An alternative:
% trimmed = trimmingFromUnknownToKnownEdges(image, trimap);

% Run K-to-U information flow to get a rough alpha and confidences
[alphaHat, conf] = knownToUnknownColorMixture(image, trimmed);

% Refine alphaHat shared matting
a_sm_ref = sharedMattingMatteRefinement(image, trimmed, alphaHat, conf);
% Alternative:
% a_ifm_ref = informationFlowMatteRefinement(image, trimmed, alphaHat, conf);


function [ ISIstats ] = bz_ISIStats( spikes,varargin )
%ISIstats = bz_ISIStats(spikes,varargin) calculates the statistics
%inter-spike intervals for the spiketimes in spikes.
%
%   INPUTS
%       spikes      Structure with spikes.times and spikes.UID
%
%       (options)
%       'ints'        A structure with intervals in which to calculate ISIs.
%                       states.stateNAME = [start stop]
%                       Will calculate ISIsstats separately for each state
%                       (Can also 'load' from SleepState.states.mat)
%       'cellclass'     Cell array of strings - label for each cell.
%                       (Can also 'load' from CellClass.cellinfo.mat)
%       'savecellinfo'  logical (default: false) save a cellinfo file?
%       'basePath'
%       'figfolder'     a folder to save the figure in
%       'showfig'       logical (default: false) show the figure?
%       'forceRedetect' logical (default: false) to re-compute even if saved
%       'shuffleCV2'    logical (devault: false)
%       'numISIbins'    number of bins for ISI distribution (default: 60)
%       'numCV2bins'    number pf bins for CV2 distribution (default: 60)
%
%   OUTPUTS
%       ISIstats        cellinfo structure with ISI statistics
%           .summstats  summary statistics
%           .ISIhist    histograms of ISIs etc
%           .sorts      sorting indices
%           .allspikes  ISI/CV2 value for each spike
%                       (ISI is PRECEDING interval for the spike at allspikes.times)
%
%DLevenstein 2018
%% Parse the inputs
defaultstates.ALL = [-Inf Inf];

% parse args
p = inputParser;
addParameter(p,'ints',defaultstates)
addParameter(p,'savecellinfo',false,@islogical)
addParameter(p,'basePath',pwd,@isstr)
addParameter(p,'figfolder',false)
addParameter(p,'showfig',false,@islogical);
addParameter(p,'cellclass',[]);
addParameter(p,'forceRedetect',false,@islogical);
addParameter(p,'shuffleCV2',false,@islogical);
addParameter(p,'numISIbins',60,@islogical);
addParameter(p,'numCV2bins',50,@islogical);

parse(p,varargin{:})
ints = p.Results.ints;
cellclass = p.Results.cellclass;
basePath = p.Results.basePath;
SAVECELLINFO = p.Results.savecellinfo;
figfolder = p.Results.figfolder;
SHOWFIG = p.Results.showfig;
forceRedetect = p.Results.forceRedetect;
SHUFFLECV2 = p.Results.shuffleCV2;
numISIbins = p.Results.numISIbins;
numCV2bins = p.Results.numCV2bins;

%% Load the stuff
baseName = bz_BasenameFromBasepath(basePath);
cellinfofilename = fullfile(basePath,[baseName,'.ISIStats.cellinfo.mat']);

if exist(cellinfofilename,'file') && ~forceRedetect
    ISIstats = bz_LoadCellinfo(basePath,'ISIStats');
    return
end

if strcmp(cellclass,'load')
    cellclass = bz_LoadCellinfo(basePath,'CellClass');
    cellclass = cellclass.label;
end

if strcmp(ints,'load')
    ints = bz_LoadStates(basePath,'SleepState');
    ints = ints.ints;
end

%% Get the States
ints.ALL = [-Inf Inf];  %Add ALL to the options
statenames = fieldnames(ints);
numstates = length(statenames);

%% ISI and CV2 statistics
numcells = length(spikes.times);

%Calculate ISI and CV2 for allspikes
allspikes.ISIs = cellfun(@diff,spikes.times,'UniformOutput',false);
allspikes.meanISI = cellfun(@(X) (X(1:end-1)+X(2:end))./2,allspikes.ISIs,'UniformOutput',false);
allspikes.CV2 = cellfun(@(X) 2.*abs(X(2:end)-X(1:end-1))./(X(2:end)+X(1:end-1)),allspikes.ISIs ,'UniformOutput',false);
%Make sure times line up
allspikes.times = cellfun(@(X) X(2:end-1),spikes.times,'UniformOutput',false);
allspikes.ISIs = cellfun(@(X) X(1:end-1),allspikes.ISIs,'UniformOutput',false);
%%
for ss = 1:numstates
%ss=1;

%Find which spikes are during state of interest
statespikes = cellfun(@(X) InIntervals(X,ints.(statenames{ss})),...
    allspikes.times,'UniformOutput',false);
CV2 = cellfun(@(X,Y) X(Y(2:end-1)),allspikes.CV2,statespikes,'Uniformoutput',false);
ISIs = cellfun(@(X,Y) X(Y(2:end-1)),allspikes.ISIs,statespikes,'Uniformoutput',false);
normISIs = cellfun(@(X) X./mean(X),ISIs,'Uniformoutput',false);

%Summary Statistics
summstats.(statenames{ss}).meanISI = cellfun(@(X) mean(X),ISIs);
summstats.(statenames{ss}).meanrate = 1./summstats.(statenames{ss}).meanISI;
summstats.(statenames{ss}).ISICV = cellfun(@(X) std(X)./mean(X),ISIs);
summstats.(statenames{ss}).meanCV2 = cellfun(@(X) mean(X),CV2);

%Account for no spikes
summstats.(statenames{ss}).meanrate(isnan(summstats.(statenames{ss}).meanrate))=0;

if SHUFFLECV2
    % CV2 for shuffled ISIs
    numshuffle = 100;
    for sh = 1:numshuffle
        ISIs_shuffle = cellfun(@(X) shuffle(X),ISIs,'UniformOutput',false);
        CV2_shuffle = cellfun(@(X) 2.*abs(X(2:end)-X(1:end-1))./(X(2:end)+X(1:end-1)),...
            ISIs_shuffle ,'UniformOutput',false);
        meanshuffle(sh,:) = cellfun(@(X) mean(X),CV2_shuffle);
    end
    summstats.(statenames{ss}).shufflemeanCV2 = mean(meanshuffle);
    summstats.(statenames{ss}).shufflestdCV2 = std(meanshuffle);

end
%%
%Set up all the bins and matrices
ISIhist.linbins = linspace(0,10,numISIbins);
ISIhist.logbins = linspace(log10(0.001),log10(200),numISIbins);
ISIhist.(statenames{ss}).lin = zeros(numcells,numISIbins);
ISIhist.(statenames{ss}).log = zeros(numcells,numISIbins);
ISIhist.(statenames{ss}).return = zeros(numISIbins,numISIbins,numcells);
ISIhist.(statenames{ss}).meannorm = zeros(numcells,numISIbins);

CV2hist.bins = linspace(0,2,numCV2bins+1);
CV2hist.bins = CV2hist.bins(1:end-1)+0.5.*diff(CV2hist.bins([1 2]));
CV2hist.(statenames{ss}) = zeros(numcells,numCV2bins);

Jointhist.(statenames{ss}).log = zeros(numcells,numISIbins,numCV2bins);
Jointhist.(statenames{ss}).norm = zeros(numcells,numISIbins,numCV2bins);

%Calculate all the histograms: ISI, log(ISI), 1/ISI, log(1/ISI)
for cc = 1:numcells
    numspks(cc) = length(ISIs{cc});
    spikethresh = 100; %need 100 spikes to show in mean plot
    enoughspikes(cc) = numspks(cc)>spikethresh;

    if numspks(cc)<1
        continue
    end
    %Calculate ISI histograms
    ISIhist.(statenames{ss}).lin(cc,:) = hist(ISIs{cc},ISIhist.linbins);
    ISIhist.(statenames{ss}).log(cc,:) = hist(log10(ISIs{cc}),ISIhist.logbins);
    ISIhist.(statenames{ss}).loginv(cc,:) = hist(log10(1./ISIs{cc}),ISIhist.logbins);
    ISIhist.(statenames{ss}).meannorm(cc,:) = hist(log10(normISIs{cc}),ISIhist.logbins);

    CV2hist.(statenames{ss})(cc,:) = hist(CV2{cc},CV2hist.bins);
    Jointhist.(statenames{ss}).log(cc,:,:) = hist3(...
        [log10([ISIs{cc};ISIs{cc}(2:end)]),[CV2{cc};CV2{cc}(1:end-1)]],...
        {ISIhist.logbins,CV2hist.bins});
    Jointhist.(statenames{ss}).norm(cc,:,:) = hist3(...
        [log10([normISIs{cc};normISIs{cc}(2:end)]),[CV2{cc};CV2{cc}(1:end-1)]],...
        {ISIhist.logbins,CV2hist.bins});

    %Normalize histograms to number of spikes
    ISIhist.(statenames{ss}).lin(cc,:) = ISIhist.(statenames{ss}).lin(cc,:)./numspks(cc);
    ISIhist.(statenames{ss}).log(cc,:) = ISIhist.(statenames{ss}).log(cc,:)./numspks(cc);
    ISIhist.(statenames{ss}).loginv(cc,:) = ISIhist.(statenames{ss}).loginv(cc,:)./numspks(cc);
    ISIhist.(statenames{ss}).meannorm(cc,:) = ISIhist.(statenames{ss}).meannorm(cc,:)./numspks(cc);

    CV2hist.(statenames{ss})(cc,:) = CV2hist.(statenames{ss})(cc,:)./numspks(cc);

    Jointhist.(statenames{ss}).log(cc,:,:) = Jointhist.(statenames{ss}).log(cc,:,:)./numspks(cc);
    Jointhist.(statenames{ss}).norm(cc,:,:) = Jointhist.(statenames{ss}).norm(cc,:,:)./numspks(cc);

    %Calculate Return maps
    if numspks(cc)>1
    ISIhist.(statenames{ss}).return(:,:,cc) = hist3(log10([ISIs{cc}(1:end-1) ISIs{cc}(2:end)]),{ISIhist.logbins,ISIhist.logbins});
    end
    ISIhist.(statenames{ss}).return(:,:,cc) = ISIhist.(statenames{ss}).return(:,:,cc)./numspks(cc);

end

summstats.(statenames{ss}).numspikes = numspks;

%Sortings
[~,sorts.(statenames{ss}).rate]=sort(summstats.(statenames{ss}).meanrate);
[~,sorts.(statenames{ss}).ISICV]=sort(summstats.(statenames{ss}).ISICV);
[~,sorts.(statenames{ss}).CV2]=sort(summstats.(statenames{ss}).meanCV2);

%Make the cell-type specific sortings and average distributions
if ~isempty(cellclass)
    %Check for empty cell class entries
    noclass = cellfun(@isempty,cellclass);
    sorts.numclassycells = sum(~noclass);
    %cellclass(noclass)={'none'};
    classnames = unique(cellclass(~noclass));
    numclasses = length(classnames);
    for cl = 1:numclasses
        inclasscells{cl} = strcmp(classnames{cl},cellclass);

        %Mean distributions
        meandists.(statenames{ss}).(classnames{cl}).ISIdist = squeeze(nanmean(ISIhist.(statenames{ss}).log(inclasscells{cl}&enoughspikes,:),1));
        meandists.(statenames{ss}).(classnames{cl}).CV2dist = squeeze(nanmean(CV2hist.(statenames{ss})(inclasscells{cl}&enoughspikes,:),1));
        meandists.(statenames{ss}).(classnames{cl}).Jointdist = squeeze(nanmean(Jointhist.(statenames{ss}).log(inclasscells{cl}&enoughspikes,:,:),1));

        %Sorts
        sorttypes = {'rate','ISICV','CV2'};
        for tt = 1:length(sorttypes)
        sorts.(statenames{ss}).([sorttypes{tt},classnames{cl}]) = ...
            intersect(sorts.(statenames{ss}).(sorttypes{tt}),find(inclasscells{cl}),'stable');

        if cl==1
            sorts.(statenames{ss}).([sorttypes{tt},'byclass'])=[];
        end
        sorts.(statenames{ss}).([sorttypes{tt},'byclass']) = ...
            [sorts.(statenames{ss}).([sorttypes{tt},'byclass']) sorts.(statenames{ss}).([sorttypes{tt},classnames{cl}])];
        end

    end
else
    numclasses = 1; cl=1;
    classnames{1} = 'ALL';
    sorts.numclassycells = numcells;
    inclasscells{1} = true(1,numcells);
    sorts.(statenames{ss}).ratebyclass = sorts.(statenames{ss}).rate;
    sorts.(statenames{ss}).ISICVbyclass = sorts.(statenames{ss}).ISICV;
    sorts.(statenames{ss}).CV2byclass = sorts.(statenames{ss}).CV2;

        %Mean distributions
        meandists.(statenames{ss}).(classnames{cl}).ISIdist = squeeze(nanmean(ISIhist.(statenames{ss}).log(inclasscells{cl}&enoughspikes,:),1));
        meandists.(statenames{ss}).(classnames{cl}).CV2dist = squeeze(nanmean(CV2hist.(statenames{ss})(inclasscells{cl},:)&enoughspikes,1));
        meandists.(statenames{ss}).(classnames{cl}).Jointdist = squeeze(nanmean(Jointhist.(statenames{ss}).log(inclasscells{cl}&enoughspikes,:,:),1));
end

%% ACG - get its own analysis
%[ccg,t] = CCG(statespiketimes,[],<options>)

%%
if SHOWFIG | figfolder
figure
    subplot(2,2,1)
        for cl = 1:numclasses
            plot(log10(summstats.(statenames{ss}).meanrate(inclasscells{cl})),...
                log2(summstats.(statenames{ss}).ISICV(inclasscells{cl})),'.','markersize',11)
            hold on
        end
        plot(get(gca,'xlim'),log2([1 1]),'k')
        LogScale('x',10);LogScale('y',2);
        xlabel('Mean Rate (Hz)');ylabel('ISI CV')
        title(statenames{ss})
        box off

    subplot(2,2,2)
    for cl = 1:numclasses

        if SHUFFLECV2
            plot([log10(summstats.(statenames{ss}).meanrate(inclasscells{cl}));...
                log10(summstats.(statenames{ss}).meanrate(inclasscells{cl}))],...
                [summstats.(statenames{ss}).shufflemeanCV2(inclasscells{cl});...
                summstats.(statenames{ss}).meanCV2(inclasscells{cl})],...
                'color',0.8.*[1 1 1],'linewidth',0.25)
            hold on
            plot([log10(summstats.(statenames{ss}).meanrate(inclasscells{cl}));...
                log10(summstats.(statenames{ss}).meanrate(inclasscells{cl}))],...
                [summstats.(statenames{ss}).shufflemeanCV2(inclasscells{cl})-summstats.(statenames{ss}).shufflestdCV2(inclasscells{cl});...
                summstats.(statenames{ss}).shufflemeanCV2(inclasscells{cl})+summstats.(statenames{ss}).shufflestdCV2(inclasscells{cl})],...
                'color',0.8.*[1 1 1],'linewidth',2.5)
        end

        plot(log10(summstats.(statenames{ss}).meanrate(inclasscells{cl})),...
            (summstats.(statenames{ss}).meanCV2(inclasscells{cl})),'.','markersize',11)
        hold on

    end
        plot(get(gca,'xlim'),[1 1],'k')
        LogScale('x',10);
        xlabel('Mean Rate (Hz)');ylabel('ISI <CV2>')
        title(statenames{ss})
        box off

    subplot(2,3,4)
        imagesc((ISIhist.logbins),[1 sorts.numclassycells],...
            ISIhist.(statenames{ss}).log(sorts.(statenames{ss}).ratebyclass,:))
        hold on
        plot(log10(1./(summstats.(statenames{ss}).meanrate(sorts.(statenames{ss}).ratebyclass))),[1:sorts.numclassycells],'k.','LineWidth',2)
        plot(ISIhist.logbins([1 end]),sum(inclasscells{1}).*[1 1]+0.5,'r')
        LogScale('x',10)
        xlabel('ISI (s)')
        xlim(ISIhist.logbins([1 end]))
        %colorbar
      %  legend('1/Mean Firing Rate (s)','location','southeast')
        ylabel('Cell (Sorted by FR, Type)')
        %legend('1/Mean Firing Rate (s)','location','southeast')
        caxis([0 0.1])
        title('ISI Distribution (Log Scale)')

    subplot(2,3,5)
        imagesc((CV2hist.bins),[1 sorts.numclassycells],...
            CV2hist.(statenames{ss})(sorts.(statenames{ss}).ratebyclass,:))
        hold on
        plot((summstats.(statenames{ss}).meanCV2(sorts.(statenames{ss}).ratebyclass)),[1:sorts.numclassycells],'k.','LineWidth',2)
        plot(CV2hist.bins([1 end]),sum(inclasscells{1}).*[1 1]+0.5,'r')
        %LogScale('x',10)
        xlabel('CV2')
        xlim(CV2hist.bins([1 end]))
        %colorbar
        xlim([0 2])
      %  legend('1/Mean Firing Rate (s)','location','southeast')
        ylabel('Cell (Sorted by FR, Type)')
        %legend('1/Mean Firing Rate (s)','location','southeast')
        %caxis([0 0.1])
        title('CV2 Distribution')

	for cl = 1:numclasses
        subplot((numclasses.*2),3,cl.*3+(numclasses.*3))
            imagesc(ISIhist.logbins,CV2hist.bins,meandists.(statenames{ss}).(classnames{cl}).Jointdist')
            hold on
            plot(ISIhist.logbins,meandists.(statenames{ss}).(classnames{cl}).ISIdist.*20,'k')
            plot(meandists.(statenames{ss}).(classnames{cl}).CV2dist.*20-3,CV2hist.bins,'k')
            axis xy
            LogScale('x',10)
            ylabel({(classnames{cl}),'CV2'});
            xlabel('ISI (s)');

            bottomrow = meandists.(statenames{ss}).(classnames{cl}).Jointdist(:,1);
            caxis([0 max([bottomrow;0])])
	end

%     subplot(2,3,5)
%         imagesc((ISIhist.logbins),[1 sorts.numclassycells],...
%             ISIhist.(statenames{ss}).log(sorts.(statenames{ss}).ISICVbyclass,:))
%         hold on
%         plot(log10(1./(summstats.(statenames{ss}).meanrate(sorts.(statenames{ss}).ISICVbyclass))),[1:sorts.numclassycells],'k.','LineWidth',2)
%         plot(ISIhist.logbins([1 end]),sum(inclasscells{1}).*[1 1]+0.5,'r')
%         LogScale('x',10)
%         xlabel('ISI (s)')
%         xlim(ISIhist.logbins([1 end]))
%         %colorbar
%       %  legend('1/Mean Firing Rate (s)','location','southeast')
%         ylabel('Cell (Sorted by CV, Type)')
%         %legend('1/Mean Firing Rate (s)','location','southeast')
%         caxis([0 0.1])
%         title('ISI Distribution (Log Scale)')
%
%     subplot(2,3,6)
%         imagesc((ISIhist.logbins),[1 sorts.numclassycells],...
%             ISIhist.(statenames{ss}).log(sorts.(statenames{ss}).CV2byclass,:))
%         hold on
%         plot(log10(1./(summstats.(statenames{ss}).meanrate(sorts.(statenames{ss}).CV2byclass))),[1:sorts.numclassycells],'k.','LineWidth',2)
%         plot(ISIhist.logbins([1 end]),sum(inclasscells{1}).*[1 1]+0.5,'r')
%         LogScale('x',10)
%         xlabel('ISI (s)')
%         xlim(ISIhist.logbins([1 end]))
%         %colorbar
%       %  legend('1/Mean Firing Rate (s)','location','southeast')
%         ylabel('Cell (Sorted by CV2, Type)')
%         %legend('1/Mean Firing Rate (s)','location','southeast')
%         caxis([0 0.1])
%         title('ISI Distribution (Log Scale)')

%     subplot(2,2,3)
%         plot(log2(summstats.(statenames{ss}).meanrate(CellClass.pE)),...
%             log2(summstats.(statenames{ss}).meanCV2(CellClass.pE)),'k.')
%         hold on
%         plot(log2(summstats.(statenames{ss}).meanrate(CellClass.pI)),...
%             log2(summstats.(statenames{ss}).meanCV2(CellClass.pI)),'r.')
%         LogScale('xy',2)
%         xlabel('Mean Rate (Hz)');ylabel('Mean CV2')
%         title(statenames{ss})
%         box off

if figfolder
    NiceSave(['ISIstats_',(statenames{ss})],figfolder,baseName);
end

%exneurons %top/bottom 25 %ile rate/ISICV
%%
% exwindur = 4; %s
% STATEtimepoints = Restrict(lfp.timestamps,double(SleepState.ints.(statenames{ss})));
% samplewin = STATEtimepoints(randi(length(STATEtimepoints))) + [0 exwindur];
% %%
% figure
% bz_MultiLFPPlot( lfp,'spikes',spikes,'timewin',samplewin,...
%     'sortmetric',summstats.(statenames{ss}).meanCV2,...
%     'cellgroups',{CellClass.pI,CellClass.pE})

end

ISIstats.summstats = summstats;
ISIstats.ISIhist = ISIhist;
ISIstats.CV2hist = CV2hist;
ISIstats.Jointhist = Jointhist;
ISIstats.sorts = sorts;
ISIstats.UID = spikes.UID;
ISIstats.allspikes = allspikes;

if SAVECELLINFO
    save(cellinfofilename,'ISIstats')
end

end


 function y = mtimes_block(ob, x, iblock, nblock)
%function y = mtimes_block(ob, x, iblock, nblock)
% y = G(i'th block) * x	or y = G'(i'th block) * x
% in either case the project data will be "small"
% iblock is 1,...,nblock

% support 'exists' option for seeing if this routine is available
if nargin == 2 & ischar(x) & streq(x, 'exists')
	y = 1;
	return
end

if nargin ~= 4, ir_usage, end

nb = ob.nb;
na = ob.na;

%
% forward projection
%
if ~ob.is_transpose
	if ob.apower ~= 1, error notdone, end

	% if needed, expand concise column
	if ob.is_masked
		idim = size(x);
		np = sum(ob.mask(:));
		nxy = numel(ob.mask);
		if idim(1) ~= np
			error 'size mismatch'
		end
		x = embed(x, ob.mask);
		x = reshape(x, nxy, idim(2));
	end

	y = double(wtfmex('dsc,proj', ob.arg', single(x), uint8(ob.mask), ...
		int32(iblock-1), int32(nblock), ...
		int32(ob.nthread), int32(ob.chat)));

	% fix: extract the relevent columns - should do in wtfmex?
	ia = iblock:nblock:na;
	nv = length(ia);

	if ndims(y) == 3			% [nb,na,nz]
		y = y(:,ia,:);			% [nb,nv,nz]

	elseif size(y,1) == nb*na		% [nba,nz]
		nz = size(y,2);
		y = reshape(y, nb, na, nz);	% [nb,na,nz]
		y = y(:,ia,:);			% [nb,nv,nz]
		y = reshape(y, nb*nv, nz);	% [nb*nv,nz]

	elseif size(y,1) == nb			% [nb,na]
		y = y(:,ia);			% [nb,nv]

	else
		error size
	end

%
% backprojection
%
else
	if ob.apower ~= 1, error notdone, end

	ia = iblock:nblock:na;
	nv = length(ia);

	if ndims(x) == 3		% [nb,nv,nz]
		error todo

	elseif size(x,1) == nb*nv	% [nb*nv,nz]
		nz = size(x,2);
		tmp = zeros(nb, na, nz);
		tmp(:,ia,:) = reshape(x, [nb nv nz]);
		x = reshape(tmp, [nb*na nz]);

	elseif size(x,1) == nb		% [nb,nv]
		error todo

	else
		error bug
	end

	y = double(wtfmex('dsc,back', ob.arg', single(x), uint8(ob.mask), ...
		int32(iblock-1), int32(nblock), ...
		int32(ob.nthread), int32(ob.chat)));

	if ob.is_masked
		if size(y,1) == numel(ob.mask)
			y = y(ob.mask,:);	% [nxy,nz] -> [np,nz]
		else
			y = y(ob.mask);		% [nx,ny] -> [np]
		end
	end
end


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

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

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


function test_tutorial_networkanalysis

% MEM 3gb
% WALLTIME 00:30:00
% DEPENDENCY ft_networkanalysis

%% read the continuous data and segment into 2 seconds epochs
cfg = [];
cfg.dataset              = dccnpath('/home/common/matlab/fieldtrip/data/ftp/test/ctf/SubjectRest.ds');
cfg.trialdef.triallength = 2;
cfg.trialdef.ntrials     = Inf;

cfg = ft_definetrial(cfg);
cfg.continuous  = 'yes';
cfg.channel     = {'MEG'};
data = ft_preprocessing(cfg);

datadir = dccnpath('/home/common/matlab/fieldtrip/data/ftp/tutorial/networkanalysis');
cd(datadir);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% BYPASS THE INTERACTIVE PART, DECLARE TRIALS 38 91 153 AS BAD
%% make a visual inspection and reject bad trials/sensors
%cfg = [];
%cfg.method  = 'summary';
%cfg.channel = 'MEG';
%cfg.layout  = 'CTF275.lay';
%dataclean = ft_rejectvisual(cfg, data);
%
%% you can check the rejected trial numbers by typing
%trlind = [];
%for i=1:length(dataclean.cfg.artfctdef.summary.artifact)
%  trlind(i) = find(data.sampleinfo(:,1)==dataclean.cfg.artfctdef.summary.artifact(i));
%end;
%disp(trlind);

cfg = [];
cfg.trials = setdiff(1:numel(data.trial), [38 91 153]);
dataclean  = ft_selectdata(cfg, data);

%% downsample the data to speed up component analysis
cfg = [];
cfg.resamplefs = 60;
cfg.detrend    = 'yes';
datads = ft_resampledata(cfg, dataclean);

%% use ICA in order to identify cardiac and blink components
cfg = [];
cfg.method          = 'runica';
cfg.runica.maxsteps = 50;
cfg.randomseed      = 0;
comp = ft_componentanalysis(cfg, datads);
%load(fullfile(datadir,'comp.mat'));

%% visualize components

% these were the indices of the bad components that were identified
% they may be different if you re-run the ICA decomposition
badcomp = [1 3 8 23];

cfg = [];
cfg.channel    = badcomp;
cfg.layout     = 'CTF275.lay';
cfg.compscale  = 'local';
cfg.continuous = 'yes';
ft_databrowser(cfg, comp);

cfg = [];
cfg.component = badcomp;
dataica = ft_rejectcomponent(cfg, comp);

%% compute the power spectrum
cfg              = [];
cfg.output       = 'pow';
cfg.method       = 'mtmfft';
cfg.taper        = 'dpss';
cfg.foilim       = [1 20];
cfg.tapsmofrq    = 2;
cfg.keeptrials   = 'no';
fft_data = ft_freqanalysis(cfg, dataica);

%% compute the planar transformation
load ctf275_neighb; % loads the neighbourhood structure for the channels

dataicatmp = dataica;
dataicatmp.grad = data.grad;

cfg = [];
cfg.neighbours    = neighbours;
cfg.planarmethod  = 'sincos';
planar = ft_megplanar(cfg, dataicatmp);
clear dataicatmp;

%% compute the power spectrum
cfg              = [];
cfg.output       = 'pow';
cfg.method       = 'mtmfft';
cfg.taper        = 'dpss';
cfg.foilim       = [1 20];
cfg.tapsmofrq    = 2;
cfg.keeptrials   = 'no';
fft_data_planar = ft_freqanalysis(cfg, planar);

%% plot the topography and the spectrum
figure;

cfg = [];
cfg.layout = 'CTF275.lay';
cfg.xlim   = [9 11];
subplot(2,1,1); ft_topoplotER(cfg, fft_data);

cfg = [];
cfg.channel = {'MRO22', 'MRO32', 'MRO33'};
subplot(2,1,2); ft_singleplotER(cfg, fft_data);

%% load the required geometrical information

%% load the template source model, which is in MNI coordinates
%template = load('standard_sourcemodel3d2cm.mat');
% load mri % individual mri
% load hdm % individual volume model
%
% %% compute the source model
% cfg = [];
% cfg.sourcemodel.warpmni   = 'yes';
% cfg.sourcemodel.template  = template.sourcemodel;
% cfg.sourcemodel.nonlinear = 'yes'; % use non-linear normalization
% cfg.mri            = mri;
% sourcemodel        = ft_prepare_sourcemodel(cfg);

load hdm
load sourcemodel_4k

%% check for the correct alignment of sensors (green) headmodel(transparent) and sourcemodel(blue)
figure;

% make the headmodel surface transparent
ft_plot_headmodel(hdm, 'edgecolor', 'none');
alpha 0.4

% add the source model positions and sensors
ft_plot_mesh(ft_convert_units(sourcemodel, 'cm'),'vertexcolor',sourcemodel.sulc);
ft_plot_sens(dataclean.grad);

view([0 -90 0])

%% compute sensor level Fourier spectra
cfg            = [];
cfg.method     = 'mtmfft';
cfg.output     = 'fourier';
cfg.keeptrials = 'yes';
cfg.tapsmofrq  = 2;
cfg.foi        = 10;
freq           = ft_freqanalysis(cfg, dataica);

%% compute the leadfield
cfg             = [];
cfg.sourcemodel        = sourcemodel;
cfg.headmodel   = hdm;
cfg.channel     = {'MEG'};
lf = ft_prepare_leadfield(cfg, freq);

%% compute the actual source reconstruction
cfg                   = [];
cfg.frequency         = freq.freq;
cfg.grad              = freq.grad;
cfg.method            = 'pcc';
cfg.sourcemodel              = lf;
cfg.headmodel         = hdm;
cfg.keeptrials        = 'yes';
cfg.pcc.lambda        = '10%';
cfg.pcc.projectnoise  = 'yes';
cfg.pcc.fixedori     = 'yes';
source = ft_sourceanalysis(cfg, freq);

%% reduce the source reconstructed data to the dominant orientation
cfg = [];
cfg.projectmom = 'yes';
source_proj = ft_sourcedescriptives(cfg,source);

% and provide the dimension and grid positions of the MRI template positions again
source_proj.dim = template.sourcemodel.dim;
source_proj.pos = template.sourcemodel.pos;

[ftver, ftdir] = ft_version;
if isunix
   templatefile = [ftdir '/template/anatomy/single_subj_T1.nii'];
elseif ispc
  templatefile =  [ftdir '\template\anatomy\single_subj_T1.nii'];
end

template_mri = ft_read_mri(templatefile);

cfg              = [];
cfg.parameter    = 'nai';
cfg.interpmethod = 'nearest';
source_int  = ft_sourceinterpolate(cfg, source_proj, template_mri);

%% plot the neural activity index (power/noise)
cfg               = [];
cfg.method        = 'ortho';
cfg.funparameter  = 'nai';
cfg.maskparameter = cfg.funparameter;
cfg.funcolorlim   = [0.0 10];
cfg.opacitylim    = [3 10];
cfg.opacitymap    = 'rampup';
cfg.funcolormap   = 'jet';
ft_sourceplot(cfg, source_int);

cfg               = [];
cfg.method        = 'ortho';
cfg.funparameter  = 'nai';
cfg.location      = [16 -80 -2];
cfg.maskparameter = cfg.funparameter;
cfg.funcolorlim   = [0.0 10];
cfg.opacitylim    = [3 10];
cfg.opacitymap    = 'rampup';
cfg.funcolormap   = 'jet';
ft_sourceplot(cfg,source_int);

%% add the scalp topographies to the figure

cfg = [];
cfg.layout = 'CTF275.lay';
cfg.xlim   = [9.777650 11.309908];
subplot(2,2,2); ft_topoplotER(cfg,fft_data);
title('axial gradient')

cfg = [];
fft_data_planar_cmb = ft_combineplanar(cfg, fft_data_planar);

cfg = [];
cfg.layout = 'CTF275.lay';
cfg.xlim   = [9.777650 11.309908];
subplot(2,2,3); ft_topoplotER(cfg, fft_data_planar_cmb);
title('planar gradient')

%% compute the power spectrum again but keep the individual trials
cfg              = [];
cfg.output       = 'pow';
cfg.method       = 'mtmfft';
cfg.taper        = 'dpss';
cfg.foilim       = [8 12];
cfg.tapsmofrq    = 2;
cfg.keeptrials   = 'yes';
fft_data = ft_freqanalysis(cfg, dataica);

%% identify the indices of trials with high and low alpha power
tmp     = mean(fft_data.powspctrm,3);           % mean over frequencies between 8-12Hz
ind     = find(mean(tmp,1)==max(mean(tmp,1)));  % find the sensor where power is max
indlow  = find(tmp(:,ind)<=median(tmp(:,ind)));
indhigh = find(tmp(:,ind)>=median(tmp(:,ind)));

%% compute the planar transformation
cfgneigh          = [];
cfgneigh.feedback = 'no';
cfgneigh.method   = 'template';

cfg = [];
cfg.neighbours    = ft_prepare_neighbours(cfgneigh, dataica);
cfg.planarmethod  = 'sincos';
planar = ft_megplanar(cfg, dataica);

%% compute the power spectrum
cfg              = [];
cfg.output       = 'pow';
cfg.method       = 'mtmfft';
cfg.taper        = 'dpss';
cfg.foilim       = [1 20];
cfg.tapsmofrq    = 2;
cfg.keeptrials   = 'no';

cfg.trials       = indlow;
tmp = ft_freqanalysis(cfg, planar);
fft_data_planar_low = ft_combineplanar([], tmp);

cfg.trials       = indhigh;
tmp = ft_freqanalysis(cfg, planar);
fft_data_planar_high = ft_combineplanar([], tmp);

%% and also do the axial representation for comparison purposes
cfg              = [];
cfg.output       = 'pow';
cfg.method       = 'mtmfft';
cfg.taper        = 'dpss';
cfg.foilim       = [1 20];
cfg.tapsmofrq    = 2;
cfg.keeptrials   = 'no';
cfg.trials       = indlow;
fft_data_low = ft_freqanalysis(cfg,dataica);

cfg.trials       = indhigh;
fft_data_high = ft_freqanalysis(cfg,dataica);

%% compute the difference between high and low
cfg = [];
cfg.parameter = 'powspctrm';
cfg.operation = 'subtract';
diff        = ft_math(cfg, fft_data_high,        fft_data_low);
diff_planar = ft_math(cfg, fft_data_planar_high, fft_data_planar_low);
diff_axial  = ft_math(cfg, fft_data_high,        fft_data_low);

%% plot the topography of the difference along with the spectra
figure;

cfg = [];
cfg.layout = 'CTF275.lay';
cfg.xlim   = [9.777650 11.309908];

subplot(1,3,1); ft_topoplotER(cfg, diff_planar); title ('planar gradient')

subplot(1,3,2); ft_topoplotER(cfg, diff_axial); title ('axial gradient')

cfg = [];
cfg.channel = {'MLO21', 'MRO31'};
subplot(1,3,3); ft_singleplotER(cfg,fft_data_high, fft_data_low);

obj = subplot(1,3,3);
set(obj, 'Position', [.7 .37 .2 .3])
title('')
legend('high alpha','low alpha','Location','northoutside','Orientation','horizontal');

%% compute fourier spectra for frequency of interest
cfg            = [];
cfg.method     = 'mtmfft';
cfg.output     = 'fourier';
cfg.keeptrials = 'yes';
cfg.tapsmofrq  = 2;
cfg.foi        = 10;

cfg.trials     = indlow;
freq_low = ft_freqanalysis(cfg, dataica);

cfg.trials     = indhigh;
freq_high = ft_freqanalysis(cfg, dataica);

%% compute the beamformer filters based on the entire data
cfg                   = [];
cfg.frequency         = freq.freq;
cfg.grad              = freq.grad;
cfg.method            = 'pcc';
cfg.sourcemodel              = lf;
cfg.headmodel         = hdm;
cfg.keeptrials        = 'yes';
cfg.pcc.lambda        = '5%';
cfg.pcc.projectnoise  = 'yes';
cfg.pcc.keepfilter    = 'yes';
source = ft_sourceanalysis(cfg, freq);

% use the precomputed filters
cfg                   = [];
cfg.frequency         = freq.freq;
cfg.grad              = freq.grad;
cfg.method            = 'pcc';
cfg.sourcemodel              = lf;
cfg.sourcemodel.filter       = source.avg.filter;
cfg.headmodel         = hdm;
cfg.keeptrials        = 'yes';
cfg.pcc.lambda        = '5%';
cfg.pcc.projectnoise  = 'yes';
source_low  = ft_sourceanalysis(cfg, freq_low);
source_high = ft_sourceanalysis(cfg, freq_high);

%% project dipole moments along the dominant orientation
cfg = [];
cfg.projectmom = 'yes';
source_proj_high = ft_sourcedescriptives(cfg,source_high);
source_proj_low  = ft_sourcedescriptives(cfg,source_low);
source_proj_high.dim = template.sourcemodel.dim;
source_proj_high.pos = template.sourcemodel.pos;
source_proj_low.dim  = template.sourcemodel.dim;
source_proj_low.pos  = template.sourcemodel.pos;

%% interpolate the results onto an anatomical brain template
[ftver, ftdir] = ft_version;
if isunix
   templatefile = [ftdir '/template/anatomy/single_subj_T1.nii'];
elseif ispc
  templatefile =  [ftdir '\template\anatomy\single_subj_T1.nii'];
end

template_mri = ft_read_mri(templatefile);

cfg              = [];
cfg.parameter    = 'pow';
cfg.interpmethod = 'nearest';
source_int_high  = ft_sourceinterpolate(cfg, source_proj_high, template_mri);
source_int_low   = ft_sourceinterpolate(cfg, source_proj_low,  template_mri);

cfg  = [];
cfg.operation = '(x1-x2)/x2';
cfg.parameter = 'pow';
source_int = ft_math(cfg, source_int_high, source_int_low);

cfg  = [];
cfg.operation = '(x1-x2)/x2';
cfg.parameter = 'pow';
source_int = ft_math(cfg, source_int_high, source_int_low);

% up to 50 percent of maximum
source_int.mask = source_int.pow > max(source_int.pow(:))*.5;

% copy the anatomy
source_int.anatomy = source_int_high.anatomy;

cfg = [];
cfg.method        = 'ortho';
cfg.funparameter  = 'pow';
cfg.maskparameter = 'mask';
cfg.funcolorlim   = [-1 1];
cfg.location      = [16 -78 38];
cfg.funcolormap   = 'jet';
ft_sourceplot(cfg, source_int);

cfg = [];
cfg.layout = 'CTF275.lay';
cfg.xlim   = [9.777650 11.309908];
subplot(2,2,2); ft_topoplotER(cfg, diff_planar);

%% reduce memory demands and compute connectivity

% compute the sparse representation
source_sparse = ft_source2sparse(source_proj);

% then compute connectivity
cfg=[];
cfg.method  ='coh';
cfg.complex = 'absimag';
source_conn = ft_connectivityanalysis(cfg, source_sparse);

%% reassign the connectivity
cohspctrm_full = nan(size(source_proj.pos,1));
for i=1:size(source_conn.pos)
  pos1 = source_conn.pos(i,1:3);
  pos2 = source_conn.pos(i,4:6);
  ind1 = find(source_proj.pos(:,1)==pos1(1) & source_proj.pos(:,2)==pos1(2) & source_proj.pos(:,3)==pos1(3));
  ind2 = find(source_proj.pos(:,1)==pos2(1) & source_proj.pos(:,2)==pos2(2) & source_proj.pos(:,3)==pos2(3));
  cohspctrm_full(ind1,ind2) = source_conn.cohspctrm(i);
end

% then go to the 'full' representation again
source_conn_full = [];
source_conn_full.pos       = source_proj.pos;
source_conn_full.dim       = source_proj.dim;
source_conn_full.inside    = source_proj.inside;
source_conn_full.cohspctrm = cohspctrm_full;
source_conn_full.dimord    = 'pos_pos';

%% compute graph metric
cfg = [];
cfg.method    = 'degrees';
cfg.parameter = 'cohspctrm';
cfg.threshold = .1;
network = ft_networkanalysis(cfg,source_conn_full);

%% interpolate on anatomical mri and plot the result
network.pos     = template.sourcemodel.pos;
network.dim     = template.sourcemodel.dim;
network.inside  = template.sourcemodel.inside;

cfg              = [];
cfg.parameter    = 'degrees';
cfg.interpmethod = 'nearest';
network_int  = ft_sourceinterpolate(cfg, network, template_mri);

%%
cfg               = [];
cfg.method        = 'ortho';
cfg.funparameter  = 'avg.degrees';
cfg.funcolormap   = 'jet';
cfg.location      = 'max';
cfg.funparameter  = 'degrees';
ft_sourceplot(cfg, network_int);

% we increase the threshold here to highlight the dominant links
edge = source_conn.cohspctrm >.15;
dlmwrite('edge.edge',edge,'\t');

load standard_sourcemodel3d2cm.mat

node = zeros(372,6);
node(:,1:3) = sourcemodel.pos(sourcemodel.inside,:);
node(:,4)   = 4;
node(:,5)   = network.degrees(network.inside);
node(:,6)   = 0;
node(:,1:3) = node(:,1:3)*10;
dlmwrite('node.node',node,' ');

BrainNet_MapCfg('/yourpath/mesh.nv','/yourpath/node.node','/yourpath/edge.edge');
view([0 -90 0])

cfg = [];
cfg.method = 'plv';
source_conn = ft_connectivityanalysis(cfg, source_sparse);

%% then compute graph metric
source_conn.dim     = source_sparse.dim;
source_conn.outside = source_proj.outside;

% then go to the 'full' representation again
source_conn_full = ft_source2full(source_conn);
source_conn_full.dimord='pos_pos';

%%
fn=fieldnames(source_conn_full);
cfg = [];
cfg.method = 'degrees';
cfg.parameter = fn{4};
cfg.threshold = .5;
deg = ft_networkanalysis(cfg,source_conn_full);


function out=resampleImageStack(in, zoom, interpolation_method)
% Uses resample.m function on the stack on images. Resamples each of the
% image in the scatck by zoom value.
% out=resampleImageStack(in, zoom, interpolation_method)
% default interpolation_method = '4-cubic';
% out(:,:,ii)=resample(in(:,:,ii),zoom, interpolation_method)
if ~exist('interpolation_method','var')
    interpolation_method = '4-cubic';
    fprintf('Default interpolation method: %s\n',interpolation_method)
else
    fprintf('Interpolation method used: %s\n',interpolation_method)
end
nz=size(in,3);

out=zeros(zoom*size(in,1),zoom*size(in,2), size(in,3));
for ii=1:nz
    out(:,:,ii)=resample(in(:,:,ii), zoom,0,interpolation_method);
end


function c = multiprod(a, b, idA, idB)
%MULTIPROD  Multiplying 1-D or 2-D subarrays contained in two N-D arrays.
%   C = MULTIPROD(A,B) is equivalent  to C = MULTIPROD(A,B,[1 2],[1 2])
%   C = MULTIPROD(A,B,[D1 D2]) is eq. to C = MULTIPROD(A,B,[D1 D2],[D1 D2])
%   C = MULTIPROD(A,B,D1) is equival. to C = MULTIPROD(A,B,D1,D1)
%
%   MULTIPROD performs multiple matrix products, with array expansion (AX)
%   enabled. Its first two arguments A and B are "block arrays" of any
%   size, containing one or more 1-D or 2-D subarrays, called "blocks" (*).
%   For instance, a 5?6?3 array may be viewed as an array containing five
%   6?3 blocks. In this case, its size is denoted by 5?(6?3). The 1 or 2
%   adjacent dimensions along which the blocks are contained are called the
%   "internal dimensions" (IDs) of the array (?).
%
%   1) 2-D by 2-D BLOCK(S) (*)
%         C = MULTIPROD(A, B, [DA1 DA2], [DB1 DB2]) contains the products
%         of the P?Q matrices in A by the R?S matrices in B. [DA1 DA2] are
%         the IDs of A; [DB1 DB2] are the IDs of B.
%
%   2) 2-D by 1-D BLOCK(S) (*)
%         C = MULTIPROD(A, B, [DA1 DA2], DB1) contains the products of the
%         P?Q matrices in A by the R-element vectors in B. The latter are
%         considered to be R?1 matrices. [DA1 DA2] are the IDs of A; DB1 is
%         the ID of B.
%
%   3) 1-D by 2-D BLOCK(S) (*)
%         C = MULTIPROD(A, B, DA1, [DB1 DB2]) contains the products of the
%         Q-element vectors in A by the R?S matrices in B. The vectors in A
%         are considered to be 1?Q matrices. DA1 is the ID of A; [DB1 DB2]
%         are the IDs of B.
%
%   4) 1-D BY 1-D BLOCK(S) (*)
%      (a) If either SIZE(A, DA1) == 1 or SIZE(B, DB1) == 1, or both,
%             C = MULTIPROD(A, B, DA1, DB1) returns products of scalars by
%             vectors, or vectors by scalars or scalars by scalars.
%      (b) If SIZE(A, DA1) == SIZE(B, DB1),
%             C = MULTIPROD(A, B, [0 DA1], [DB1 0]) or
%             C = MULTIPROD(A, B, DA1, DB1) virtually turns the vectors
%             contained in A and B into 1?P and P?1 matrices, respectively,
%             then returns their products, similar to scalar products.
%             Namely, C = DOT2(A, B, DA1, DB1) is equivalent to
%             C = MULTIPROD(CONJ(A), B, [0 DA1], [DB1 0]).
%      (c) Without limitations on the length of the vectors in A and B,
%             C = MULTIPROD(A, B, [DA1 0], [0 DB1]) turns the vectors
%             contained in A and B into P?1 and 1?Q matrices, respectively,
%             then returns their products, similar to outer products.
%             Namely, C = OUTER(A, B, DA1, DB1) is equivalent to
%             C = MULTIPROD(CONJ(A), B, [DA1 0], [0 DB1]).
%
%   Common constraints for all syntaxes:
%      The external dimensions of A and B must either be identical or
%      compatible with AX rules. The internal dimensions of each block
%      array must be adjacent (DA2 == DA1 + 1 and DB2 == DB1 + 1 are
%      required). DA1 and DB1 are allowed to be larger than NDIMS(A) and
%      NDIMS(B). In syntaxes 1, 2, and 3, Q == R is required, unless the
%      blocks in A or B are scalars.
%
%   Array expansion (AX):
%      AX is a powerful generalization to N-D of the concept of scalar
%      expansion. Indeed, A and B may be scalars, vectors, matrices or
%      multi-dimensional arrays. Scalar expansion is the virtual
%      replication or annihilation of a scalar which allows you to combine
%      it, element by element, with an array X of any size (e.g. X+10,
%      X*10, or []-10). Similarly, in MULTIPROD, the purpose of AX is to
%      automatically match the size of the external dimensions (EDs) of A
%      and B, so that block-by-block products can be performed. ED matching
%      is achieved by means of a dimension shift followed by a singleton
%      expansion:
%      1) Dimension shift (see SHIFTDIM).
%            Whenever DA1 ~= DB1, a shift is applied to impose DA1 == DB1.
%            If DA1 > DB1, B is shifted to the right by DA1 - DB1 steps.
%            If DB1 > DA1, A is shifted to the right by DB1 - DA1 steps.
%      2) Singleton expansion (SX).
%            Whenever an ED of either A or B is singleton and the
%            corresponding ED of the other array is not, the mismatch is
%            fixed by virtually replicating the array (or diminishing it to
%            length 0) along that dimension.
%
%   MULTIPROD is a generalization for N-D arrays of the matrix
%   multiplication function MTIMES, with AX enabled. Vector inner, outer,
%   and cross products generalized for N-D arrays and with AX enabled are
%   performed by DOT2, OUTER, and CROSS2 (MATLAB Central, file #8782).
%   Elementwise multiplications (see TIMES) and other elementwise binary
%   operations with AX enabled are performed by BAXFUN (MATLAB Central,
%   file #23084). Together, these functions make up the ?ARRAYLAB toolbox?.
%
%   Input and output format:
%      The size of the EDs of C is determined by AX. Block size is
%      determined as follows, for each of the above-listed syntaxes:
%      1) C contains P?S matrices along IDs MAX([DA1 DA2], [DB1 DB2]).
%      2) Array     Block size     ID(s)
%         ----------------------------------------------------
%         A         P?Q  (2-D)     [DA1 DA2]
%         B         R    (1-D)     DB1
%         C (a)     P    (1-D)     MAX(DA1, DB1)
%         C (b)     P?Q  (2-D)     MAX([DA1 DA2], [DB1 DB1+1])
%         ----------------------------------------------------
%         (a) The 1-D blocks in B are not scalars (R > 1).
%         (b) The 1-D blocks in B are scalars (R = 1).
%      3) Array     Block size     ID(s)
%         ----------------------------------------------------
%         A           Q  (1-D)     DA1
%         B         R?S  (2-D)     [DB1 DB2]
%         C (a)       S  (1-D)     MAX(DA1, DB1)
%         C (b)     R?S  (2-D)     MAX([DA1 DA1+1], [DB1 DB2])
%         ----------------------------------------------------
%         (a) The 1-D blocks in A are not scalars (Q > 1).
%         (b) The 1-D blocks in A are scalars (Q = 1).
%      4)     Array     Block size         ID(s)
%         --------------------------------------------------------------
%         (a) A         P        (1-D)     DA1
%             B         Q        (1-D)     DB1
%             C         MAX(P,Q) (1-D)     MAX(DA1, DB1)
%         --------------------------------------------------------------
%         (b) A         P        (1-D)     DA1
%             B         P        (1-D)     DB1
%             C         1        (1-D)     MAX(DA1, DB1)
%         --------------------------------------------------------------
%         (c) A         P        (1-D)     DA1
%             B         Q        (1-D)     DB1
%             C         P?Q      (2-D)     MAX([DA1 DA1+1], [DB1 DB1+1])
%         --------------------------------------------------------------
%
%   Terminological notes:
%   (*) 1-D and 2-D blocks are generically referred to as "vectors" and
%       "matrices", respectively. However, both may be also called
%       ?scalars? if they have a single element. Moreover, matrices with a
%       single row or column (e.g. 1?3 or 3?1) may be also called ?row
%       vectors? or ?column vectors?.
%   (?) Not to be confused with the "inner dimensions" of the two matrices
%       involved in a product X * Y, defined as the 2nd dimension of X and
%       the 1st of Y (DA2 and DB1 in syntaxes 1, 2, 3).
%
%   Examples:
%    1) If  A is .................... a 5?(6?3)?2 array,
%       and B is .................... a 5?(3?4)?2 array,
%       C = MULTIPROD(A, B, [2 3]) is a 5?(6?4)?2 array.
%
%       A single matrix A pre-multiplies each matrix in B
%       If  A is ........................... a (1?3)    single matrix,
%       and B is ........................... a 10?(3?4) 3-D array,
%       C = MULTIPROD(A, B, [1 2], [3 4]) is a 10?(1?4) 3-D array.
%
%       Each matrix in A pre-multiplies each matrix in B (all possible
%       combinations)
%       If  A is .................... a (6?3)?5   array,
%       and B is .................... a (3?4)?1?2 array,
%       C = MULTIPROD(A, B, [1 2]) is a (6?4)?5?2 array.
%
%   2a) If  A is ........................... a 5?(6?3)?2 4-D array,
%       and B is ........................... a 5?(3)?2   3-D array,
%       C = MULTIPROD(A, B, [2 3], [2]) is   a 5?(6)?2   3-D array.
%
%   2b) If  A is ........................... a 5?(6?3)?2 4-D array,
%       and B is ........................... a 5?(1)?2   3-D array,
%       C = MULTIPROD(A, B, [2 3], [2]) is   a 5?(6?3)?2 4-D array.
%
%   4a) If both A and B are .................. 5?(6)?2   3-D arrays,
%       C = MULTIPROD(A, B, 2) is .......... a 5?(1)?2   3-D array, while
%   4b) C = MULTIPROD(A, B, [2 0], [0 2]) is a 5?(6?6)?2 4-D array
%
%   See also DOT2, OUTER, CROSS2, BAXFUN, MULTITRANSP, MULTITRACE, MULTISCALE.

% $ Version: 2.1 $
% CODE      by:            Paolo de Leva
%                          (Univ. of Rome, Foro Italico, IT)    2009 Jan 24
%           optimized by:  Paolo de Leva
%                          Jinhui Bai (Georgetown Univ., D.C.)  2009 Jan 24
% COMMENTS  by:            Paolo de Leva                        2009 Feb 24
% OUTPUT    tested by:     Paolo de Leva                        2009 Feb 24
% -------------------------------------------------------------------------

%error( nargchk(2, 4, nargin) ); % Allow 2 to 4 input arguments % HK
narginchk(2, 4); % added by HK
switch nargin % Setting IDA and/or IDB
    case 2, idA = [1 2]; idB = [1 2];
    case 3, idB = idA;
end

% ESC 1 - Special simple case (both A and B are 2D), solved using C = A * B

     if ndims(a)==2 && ndims(b)==2 && ...
         isequal(idA,[1 2]) && isequal(idB,[1 2])
         c = a * b; return
     end

% MAIN 0 - Checking and evaluating array size, block size, and IDs

     sizeA0 = size(a);
     sizeB0 = size(b);
     [sizeA, sizeB, shiftC, delC, sizeisnew, idA, idB, ...
     squashOK, sxtimesOK, timesOK, mtimesOK, sumOK] = ...
                                           sizeval(idA,idB, sizeA0,sizeB0);

% MAIN 1 - Applying dimension shift (first step of AX) and
%          turning both A and B into arrays of either 1-D or 2-D blocks

     if sizeisnew(1), a = reshape(a, sizeA); end
     if sizeisnew(2), b = reshape(b, sizeB); end

% MAIN 2 - Performing products with or without SX (second step of AX)

     if squashOK % SQUASH + MTIMES (fastest engine)
         c = squash2D_mtimes(a,b, idA,idB, sizeA,sizeB, squashOK);
     elseif timesOK % TIMES (preferred w.r. to SX + TIMES)
         if sumOK, c = sum(a .* b, sumOK);
         else      c =     a .* b; end
     elseif sxtimesOK % SX + TIMES
         if sumOK, c = sum(bsxfun(@times, a, b), sumOK);
         else      c =     bsxfun(@times, a, b); end
     elseif mtimesOK % MTIMES (rarely used)
         c = a * b;
     end

% MAIN 3 - Reshaping C (by inserting or removing singleton dimensions)

     [sizeC sizeCisnew] = adjustsize(size(c), shiftC, false, delC, false);
     if sizeCisnew, c = reshape(c, sizeC); end

function c = squash2D_mtimes(a, b, idA, idB, sizeA, sizeB, squashOK)
% SQUASH2D_MTIMES  Multiproduct with single-block expansion (SBX).
%    Actually, no expansion is performed. The multi-block array is
%    rearranged from N-D to 2-D, then MTIMES is applied, and eventually the
%    result is rearranged back to N-D. No additional memory is required.
%    One and only one of the two arrays must be single-block, and its IDs
%    must be [1 2] (MAIN 1 removes leading singletons). Both arrays
%    must contain 2-D blocks (MAIN 1 expands 1-D blocks to 2-D).

    if squashOK == 1 % A is multi-block, B is single-block (squashing A)

        % STEP 1 - Moving IDA(2) to last dimension
        nd = length(sizeA);
        d2 = idA(2);
        order = [1:(d2-1) (d2+1):nd d2]; % Partial shifting
        a = permute(a, order); % ...?Q

        % STEP 2 - Squashing A from N-D to 2-D
        q = sizeB(1);
        s = sizeB(2);
        lengthorder = length(order);
        collapsedsize = sizeA(order(1:lengthorder-1));
        n = prod(collapsedsize);
        a = reshape(a, [n, q]); % N?Q
        fullsize = [collapsedsize s]; % Size to reshape C back to N-D

    else % B is multi-block, A is single-block (squashing B)

        % STEP 1 - Moving IDB(1) to first dimension
        nd = length(sizeB);
        d1 = idB(1);
        order = [d1 1:(d1-1) (d1+1):nd]; % Partial shifting
        b = permute(b, order); % Q?...

        % STEP 2 - Squashing B from N-D to 2-D
        p = sizeA(1);
        q = sizeA(2);
        lengthorder = length(order);
        collapsedsize = sizeB(order(2:lengthorder));
        n = prod(collapsedsize);
        b = reshape(b, [q, n]); % Q?N
        fullsize = [p collapsedsize]; % Size to reshape C back to N-D

    end

    % FINAL STEPS - Multiplication, reshape to N-D, inverse permutation
    invorder(order) = 1 : lengthorder;
    c = permute (reshape(a*b, fullsize), invorder);

function [sizeA, sizeB, shiftC, delC, sizeisnew, idA, idB, ...
          squashOK, sxtimesOK, timesOK, mtimesOK, sumOK] = ...
                                          sizeval(idA0,idB0, sizeA0,sizeB0)
%SIZEVAL   Evaluation of array size, block size, and IDs
%    Possible values for IDA and IDB:
%        [DA1 DA2], [DB1 DB2]
%        [DA1 DA2], [DB1]
%        [DA1],     [DB1 DB2]
%        [DA1],     [DB1]
%        [DA1 0],   [0 DB1]
%        [0 DA1],   [DB1 0]
%
%    sizeA/B     Equal to sizeA0/B0 if RESHAPE is not needed in MAIN 1
%    shiftC, delC    Variables controlling MAIN 3.
%    sizeisnew   1x2 logical array; activates reshaping of A and B.
%    idA/B       May change only if squashOK ~= 0
%    squashOK    If only A or B is a multi-block array (M-B) and the other
%                is single-block (1-B), it will be rearranged from N-D to
%                2-D. If both A and B are 1-B or M-B arrays, squashOK = 0.
%                If only A (or B) is a M-B array, squashOK = 1 (or 2).
%    sxtimesOK, timesOK, mtimesOK    Flags controlling MAIN 2 (TRUE/FALSE).
%    sumOK       Dimension along which SUM is performed. If SUM is not
%                needed, sumOK = 0.

% Initializing output arguments

    idA = idA0;
    idB = idB0;
     squashOK = 0;
    sxtimesOK = false;
      timesOK = false;
     mtimesOK = false;
        sumOK = 0;
    shiftC = 0;
    delC = 0;

% Checking for gross input errors

    NidA = numel(idA);
    NidB = numel(idB);
    idA1 = idA(1);
    idB1 = idB(1);
    if  NidA>2 || NidB>2 || NidA==0 || NidB==0 || ...
           ~isreal(idA1) ||    ~isreal(idB1)   || ...
        ~isnumeric(idA1) || ~isnumeric(idB1)   || ...
                 0>idA1  ||          0>idB1    || ... % negative
         idA1~=fix(idA1) ||  idB1~=fix(idB1)   || ... % non-integer
         ~isfinite(idA1) ||  ~isfinite(idB1) % Inf or NaN
        error('MULTIPROD:InvalidDimensionArgument', ...
        ['Internal-dimension arguments (e.g., [IDA1 IDA2]) must\n', ...
         'contain only one or two non-negative finite integers']);
    end

% Checking Syntaxes containing zeros (4b/c)

    declared_outer = false;
    idA2 = idA(NidA); % It may be IDA1 = IDA2 (1-D block)
    idB2 = idB(NidB);

    if any(idA==0) || any(idB==0)

        % "Inner products": C = MULTIPROD(A, B, [0 DA1], [DB1 0])
        if idA1==0 && idA2>0 && idB1>0 && idB2==0
            idA1 = idA2;
            idB2 = idB1;
        % "Outer products": C = MULTIPROD(A, B, [DA1 0], [0 DB1])
        elseif idA1>0 && idA2==0 && idB1==0 && idB2>0
            declared_outer = true;
            idA2 = idA1;
            idB1 = idB2;
        else
            error('MULTIPROD:InvalidDimensionArgument', ...
            ['Misused zeros in the internal-dimension arguments\n', ...
            '(see help heads 4b and 4c)']);
        end
        NidA = 1;
        NidB = 1;
        idA = idA1;
        idB = idB1;

    elseif (NidA==2 && idA2~=idA1+1) || ...  % Non-adjacent IDs
           (NidB==2 && idB2~=idB1+1)
        error('MULTIPROD:InvalidDimensionArgument', ...
        ['If an array contains 2-D blocks, its two internal dimensions', ...
        'must be adjacent (e.g. IDA2 == IDA1+1)']);
    end

% ESC - Case for which no reshaping is needed (both A and B are scalars)

    scalarA = isequal(sizeA0, [1 1]);
    scalarB = isequal(sizeB0, [1 1]);
    if scalarA && scalarB
        sizeA = sizeA0;
        sizeB = sizeB0;
        sizeisnew = [false false];
        timesOK = true; return
    end

% Computing and checking adjusted sizes
% The lengths of ADJSIZEA and ADJSIZEB must be >= IDA(END) and IDB(END)

    NsA = idA2 - length(sizeA0); % Number of added trailing singletons
    NsB = idB2 - length(sizeB0);
    adjsizeA = [sizeA0 ones(1,NsA)];
    adjsizeB = [sizeB0 ones(1,NsB)];
    extsizeA = adjsizeA([1:idA1-1, idA2+1:end]); % Size of EDs
    extsizeB = adjsizeB([1:idB1-1, idB2+1:end]);
    p = adjsizeA(idA1);
    q = adjsizeA(idA2);
    r = adjsizeB(idB1);
    s = adjsizeB(idB2);
    scalarsinA = (p==1 && q==1);
    scalarsinB = (r==1 && s==1);
    singleA = all(extsizeA==1);
    singleB = all(extsizeB==1);
    if q~=r && ~scalarsinA && ~scalarsinB && ~declared_outer
       error('MULTIPROD:InnerDimensionsMismatch', ...
             'Inner matrix dimensions must agree.');
    end

% STEP 1/3 - DIMENSION SHIFTING (FIRST STEP OF AX)
%   Pipeline 1 (using TIMES) never needs left, and may need right shifting.
%   Pipeline 2 (using MTIMES) may need left shifting of A and right of B.

    shiftA = 0;
    shiftB = 0;
    diffBA = idB1 - idA1;
    if scalarA % Do nothing
    elseif singleA && ~scalarsinB, shiftA = -idA1 + 1; %  Left shifting A
    elseif idB1 > idA1,            shiftA = diffBA;    % Right shifting A
    end
    if scalarB % Do nothing
    elseif singleB && ~scalarsinA, shiftB = -idB1 + 1; %  Left shifting B
    elseif idA1 > idB1,            shiftB = -diffBA;   % Right shifting B
    end

% STEP 2/3 - SELECTION OF PROPER ENGINE AND BLOCK SIZE ADJUSTMENTS

    addA  = 0; addB  = 0;
    delA  = 0; delB  = 0;
    swapA = 0; swapB = 0;
    idC1 = max(idA1, idB1);
    idC2 = idC1 + 1;
    checktimes = false;

    if (singleA||singleB) &&~scalarsinA &&~scalarsinB % Engine using MTIMES

        if singleA && singleB
            mtimesOK = true;
            shiftC=idC1-1; % Right shifting C
            idC1=1; idC2=2;
        elseif singleA
            squashOK = 2;
            idB = [idB1, idB1+1] + shiftB;
        else % singleB
            squashOK = 1;
            idA = [idA1, idA1+1] + shiftA;
        end

        if NidA==2 && NidB==2 % 1) 2-D BLOCKS BY 2-D BLOCKS
            % OK
        elseif NidA==2        % 2) 2-D BLOCKS BY 1-D BLOCKS
            addB=idB1+1; delC=idC2;
        elseif NidB==2        % 3) 1-D BLOCKS BY 2-D BLOCKS
            addA=idA1; delC=idC1;
        else                  % 4) 1-D BLOCKS BY 1-D BLOCKS
            if declared_outer
                addA=idA1+1; addB=idB1;
            else
                addA=idA1; addB=idB1+1; delC=idC2;
            end
        end

    else % Engine using TIMES (also used if SCALARA || SCALARB)

        sxtimesOK = true;

        if NidA==2 && NidB==2 % 1) 2-D BLOCKS BY 2-D BLOCKS

            if scalarA || scalarB
                timesOK=true;
            elseif scalarsinA && scalarsinB % scal-by-scal
                checktimes=true;
            elseif scalarsinA || scalarsinB || ... % scal-by-mat
                (q==1 && r==1)  % vec-by-vec ("outer")
            elseif p==1 && s==1 % vec-by-vec ("inner")
                swapA=idA1; sumOK=idC1; checktimes=true;
            elseif s==1 % mat-by-vec
                swapB=idB1; sumOK=idC2;
            elseif p==1 % vec-by-mat
                swapA=idA1; sumOK=idC1;
            else % mat-by-mat
                addA=idA2+1; addB=idB1; sumOK=idC2; delC=idC2;
            end

        elseif NidA==2 % 2) 2-D BLOCKS BY 1-D BLOCKS

            if scalarA || scalarB
                timesOK=true;
            elseif scalarsinA && scalarsinB % scal-by-scal
                addB=idB1; checktimes=true;
            elseif scalarsinA % scal-by-vec
                delA=idA1;
            elseif scalarsinB % mat-by-scal
                addB=idB1;
            elseif p==1 % vec-by-vec ("inner")
                delA=idA1; sumOK=idC1; checktimes=true;
            else % mat-by-vec
                addB=idB1; sumOK=idC2; delC=idC2;
            end

        elseif NidB==2 % 3) 1-D BLOCKS BY 2-D BLOCKS

            if scalarA || scalarB
                timesOK=true;
            elseif scalarsinA && scalarsinB % scal-by-scal
                addA=idA1+1; checktimes=true;
            elseif scalarsinB % vec-by-scal
                delB=idB2;
            elseif scalarsinA % scal-by-mat
                addA=idA1+1;
            elseif s==1 % vec-by-vec ("inner")
                delB=idB2; sumOK=idC1; checktimes=true;
            else % vec-by-mat
                addA=idA1+1; sumOK=idC1; delC=idC1;
            end

        else % 4) 1-D BLOCKS BY 1-D BLOCKS

            if scalarA || scalarB
                timesOK=true;
            elseif declared_outer % vec-by-vec ("outer")
                addA=idA1+1; addB=idB1;
            elseif scalarsinA && scalarsinB % scal-by-scal
                checktimes=true;
            elseif scalarsinA || scalarsinB % vec-by-scal
            else % vec-by-vec
                sumOK=idC1; checktimes=true;
            end
        end
    end

% STEP 3/3 - Adjusting the size of A and B. The size of C is adjusted
%            later, because it is not known yet.

    [sizeA, sizeisnew(1)] = adjustsize(sizeA0, shiftA, addA, delA, swapA);
    [sizeB, sizeisnew(2)] = adjustsize(sizeB0, shiftB, addB, delB, swapB);

    if checktimes % Faster than calling BBXFUN
        diff = length(sizeB) - length(sizeA);
        if isequal([sizeA ones(1,diff)], [sizeB ones(1,-diff)])
            timesOK = true;
        end
    end

function [sizeA, sizeisnew] = adjustsize(sizeA0, shiftA, addA, delA, swapA)
% ADJUSTSIZE  Adjusting size of a block array.

    % Dimension shifting (by adding or deleting trailing singleton dim.)
    if     shiftA>0, [sizeA,newA1] = addsing(sizeA0, 1, shiftA);
    elseif shiftA<0, [sizeA,newA1] = delsing(sizeA0, 1,-shiftA);
    else   sizeA = sizeA0;  newA1  = false;
    end
    % Modifying block size (by adding, deleting, or moving singleton dim.)
    if      addA, [sizeA,newA2] = addsing(sizeA, addA+shiftA, 1); % 1D-->2D
    elseif  delA, [sizeA,newA2] = delsing(sizeA, delA+shiftA, 1); % 2D-->1D
    elseif swapA, [sizeA,newA2] = swapdim(sizeA,swapA+shiftA); % ID Swapping
    else                 newA2  = false;
    end
    sizeisnew = newA1 || newA2;

function [newsize, flag] = addsing(size0, dim, ns)
%ADDSING   Adding NS singleton dimensions to the size of an array.
%   Warning: NS is assumed to be a positive integer.
%   Example: If the size of A is ..... SIZE0 = [5 9 3]
%            NEWSIZE = ADDSING(SIZE0, 3, 2) is [5 9 1 1 3]

    if dim > length(size0)
        newsize = size0;
        flag = false;
    else
        newsize = [size0(1:dim-1), ones(1,ns), size0(dim:end)];
        flag = true;
    end

function [newsize, flag] = delsing(size0, dim, ns)
%DELSING   Removing NS singleton dimensions from the size of an array.
%   Warning: Trailing singletons are not removed
%   Example: If the size of A is SIZE0 = [1 1 1 5 9 3]
%            NEWSIZE = DELSING(SIZE, 1, 3) is  [5 9 3]

    if dim > length(size0)-ns % Trailing singletons are not removed
        newsize = size0;
        flag = false;
    else % Trailing singl. added, so NEWSIZE is guaranteed to be 2D or more
        newsize = size0([1:dim-1, dim+ns:end, dim]);
        flag = true;
    end

function [newsize, flag] = swapdim(size0, dim)
%SWAPDIM   Swapping two adjacent dimensions of an array (DIM and DIM+1).
%   Used only when both A and B are multi-block arrays with 2-D blocks.
%   Example: If the size of A is .......... 5?(6?3)
%            NEWSIZE = SWAPIDS(SIZE0, 2) is 5?(3?6)

    newsize = [size0 1]; % Guarantees that dimension DIM+1 exists.
    newsize = newsize([1:dim-1, dim+1, dim, dim+2:end]);
    flag = true;


function f = times(f, g)
%.*   CHEBFUN multiplication.
%   F.*G multiplies F and G, where F and G may be CHEBFUN objects or scalars.
%   If F and/or G is array-valued, the dimensions must match.
%
% See also MTIMES.

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

% Deal with the special cases:
if ( ~isa(f, 'chebfun') )      % ??? * CHEBFUN

    % Ensure CHEBFUN is the first input:
    if ( ~g(1).isTransposed )
        f = times(g, f);
    else
        f = times(g.', f.').';
    end

elseif ( isempty(g) )          % CHEBFUN * []

    f = [];
    return

elseif ( isempty(f) )          % empty CHEBFUN * CHEBFUN

    % Nothing to do here. (Return an empty CHEBFUN as output.)
    return

elseif ( isnumeric(g) )        % CHEBFUN * double

    if ( numel(f) == 1 )
        % Array-valued case:

        % Loop over the funs:
        for k = 1:numel(f.funs)
            f.funs{k} = times(f.funs{k}, g);
        end

        % Multiply the pointValues:
        if ( numel(g) > 1 )
            f.pointValues = bsxfun(@times, f.pointValues, g);
        else
            f.pointValues = f.pointValues .* g;
        end

    else
        % Quasimatrix case:

        numCols = numel(f);
        % Promote g if required:
        if ( ~isscalar(g) )
            error('CHEBFUN:CHEBFUN:times:dim', 'Matrix dimensions must agree.');
        end
        % Loop over the columns:
        for k = 1:numCols
            f(k) = f(k).*g;
        end

    end

elseif ( ~isa(g, 'chebfun') )  % CHEBFUN * ???

    error('CHEBFUN:CHEBFUN:times:unknown', ...
          ['Undefined function ''times'' for input arguments of type ' ...
           '%s and %s.'], class(f), class(g));

else                           % CHEBFUN .* CHEBFUN

    % Check to see if one of the CHEBFUNs is transposed:
    if ( xor(f(1).isTransposed, g(1).isTransposed) )
        error('CHEBFUN:CHEBFUN:times:matdim', ...
            'Matrix dimensions must agree. (One input is transposed).');
    end

    dimCheck(f, g);

    if ( numel(f) == 1 && numel(g) == 1 )
        % CHEBFUN case:

        % If one of the two CHEBFUNs uses a PERIODICTECH reprensetation,
        % cast it to a NONPERIODICTECH.
        if ( ~isPeriodicTech(f.funs{1}) && isPeriodicTech(g.funs{1}) )
            g = chebfun(g, g.domain, 'tech', get(f.funs{1}, 'tech'));
        elseif ( isPeriodicTech(f.funs{1}) && ~isPeriodicTech(g.funs{1}) )
            f = chebfun(f, f.domain, 'tech', get(g.funs{1}, 'tech'));
        end

        % Overlap:
        [f, g] = overlap(f, g);

        % Loop over the FUNs:
        for k = 1:numel(f.funs)
            f.funs{k} = times(f.funs{k}, g.funs{k});
        end
        f.pointValues = f.pointValues .* g.pointValues;

    else
        % QUASIMATRIX case:

        % Convert to cell for simplicity
        f = cheb2cell(f);
        g = cheb2cell(g);

        % Loop over the columns:
        if ( numel(f) == 1 )
            for k = numel(g):-1:1
                h(k) = f{1} .* g{k};
            end
        elseif ( numel(g) == 1 )
            for k = numel(f):-1:1
                h(k) = f{k} .* g{1};
            end
        else % numel(f) = numel(g)
            for k = numel(f):-1:1
                h(k) = f{k} .* g{k};
            end
        end
        f = h;
    end
end

% Set small breakpoint values to zero:
f = thresholdBreakpointValues(f);

end


function handle = imageVisualiseVargplvm(imageVals, imageSize, transpose, negative, ...
				 scale, thresh)

% IMAGEVISUALISE Helper code for showing an image during 2-D visualisation.
% FORMAT
% DESC is a helper function for plotting image data using latent
% variable models.
% ARG imageValues : the values to set the image data to.
% ARG imageSize : the size of the image.
% ARG transpose : whether the resized image needs to be transposed
% (default 1, which is yes).
% ARG negative : whether to display the negative of the image
% (default 0, which is no).
% ARG scale : whether or not to use the imagesc function (defaults
% to 1, which is yes).
% ARG thresh : An array, thresh = [minVal, threshDown, threshUp, maxVal]
% which gives value minVal to all image elements smaller than threshDown
% and value maxVal to all image elements larger than threshUp.
% RETURN handle : a the handle to the image data.
%
% COPYRIGHT : Neil D. Lawrence, 2003, 2004, 2006
%
% SEEALSO : imageModify, lvmResultsDynamic

% SHEFFIELDML

if nargin < 3 || isempty(transpose)
  transpose = 1;
end
if nargin< 4 || isempty(negative)
  negative = 0;
end
if nargin < 5 || isempty(scale)
  scale = 1;
end
if nargin < 6
    thresh = [];
end
if negative
  imageVals = -imageVals;
end
imageData = reshape(imageVals, imageSize(1), imageSize(2));
if transpose
  imageData = imageData';
end
if ~isempty(thresh)
    imageData(imageData < thresh(2)) = thresh(1);
    imageData(imageData >= thresh(3)) = thresh(4);
end
if scale
  handle = imagesc(imageData);
else
  handle = image(imageData);
end
colormap gray


%扩频函数
function [out] = spread(data, code)

% ****************************************************************
%   data   : 输入数据序列
%   code   : 扩频码序列
%   out    : 扩频后的输出数据序列
% ****************************************************************

switch nargin
case { 0 , 1 }                                  %如果输入参数个数不对，提示错误
    error('缺少输入参数');
end

[hn,vn] = size(data);
[hc,vc] = size(code);

if hn > hc                                      %如果扩频码数小于输入的待扩频的数据序列，提示错误
    error('缺少扩频码序列');
end

out = zeros(hn,vn*vc);

for ii=1:hn
    out(ii,:) = reshape(code(ii,:).'*data(ii,:),1,vn*vc);
end

%******************************** end of file ********************************


function [V,F] = simple_cube()
%SIMPLE_CUBE  construct a triangle mesh for a simple cube
%
% [V,F] = simple_cube();
%
% Outputs:
%  V,F  the triangle mesh of a simple cube

V = [?, ?, ?; ... %dots in MATLAB allow us to insert a linebreak, but continue with the same statement
    ?, ?, ?; ...
    ?, ?, ?; ...
    ?, ?, ?; ...
    ?, ?, ?; ...
    ?, ?, ?; ...
    ?, ?, ?; ...
    ?, ?, ?];

F = [  ];

end