function varths = Get_VarthsPSI_swing(zetaj,ntilj,PSIdj,PSIdjm1)
%UNTITLED2 Summary of this function goes here
%   Detailed explanation goes here

zetaj2     = zetaj^2; zetaj3 = zetaj*zetaj; zetaj4 = zetaj*zetaj3;

varths = zeros(1,4);
gamms  = zeros(1,3);

gamms(1)  = (1 - zetaj4)/8 + zetaj3/3 - zetaj2/4;
gamms(2)  = 5/12 + zetaj4/4 - zetaj3/3 - zetaj2/2 + zetaj;
gamms(3)  = 1/12 - (1 + zetaj4)/8 + zetaj2/4;

varths(3) = PSIdjm1(ntilj(1)-1)*gamms(1) + PSIdjm1(ntilj(1))*gamms(2) + PSIdjm1(ntilj(1)+1)*gamms(3);

gamms(1) = 1/12 - gamms(1);
gamms(2) = 5/6  - gamms(2);
gamms(3) = 1/12 - gamms(3);

varths(1) = PSIdj(ntilj(1)-1)*gamms(1) + PSIdj(ntilj(1))*gamms(2) + PSIdj(ntilj(1)+1)*gamms(3);

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

gamms(1)  = zetaj4/8 - zetaj3/2 + zetaj2/2;
gamms(2)  = -zetaj4/4 + 2*zetaj3/3;
gamms(3)  = zetaj4/8 - zetaj3/6;

varths(4) = PSIdjm1(ntilj(1))*gamms(1) + PSIdjm1(ntilj(1)+1)*gamms(2) + PSIdjm1(ntilj(1)+2)*gamms(3);

gamms(1) = 1/12 - gamms(1);
gamms(2) = 5/6  - gamms(2);
gamms(3) = 1/12 - gamms(3);

varths(2) = PSIdj(ntilj(1))*gamms(1) + PSIdj(ntilj(1)+1)*gamms(2) + PSIdj(ntilj(1)+2)*gamms(3);

end


% Recursive Least-Squares Algorithm with exponential weighting
%
% From S. Haykin, "Adaptive Filtering Theory (3rd Ed.)", Prentice Hall,
% Chapter 13.
%
% This file is part of the Kernel Adaptive Filtering Toolbox for Matlab.
% https://github.com/steven2358/kafbox/

classdef rls < linear_filter

    properties (GetAccess = 'public', SetAccess = 'private')
        lambda = .99; % forgetting factor
        c = 1E-4; % regularization
    end

    properties (GetAccess = 'public', SetAccess = 'private')
        P = []; % inverse autocorrelation matrix
        w = []; % filter coefficients
    end

    methods

        function obj = rls(parameters) % constructor
            if (nargin > 0) % copy valid parameters
                for fn = fieldnames(parameters)'
                    if ismember(fn,fieldnames(obj))
                        obj.(fn{1}) = parameters.(fn{1});
                    end
                end
            end
        end

        function y_est = evaluate(obj,x) % evaluate the algorithm
            if numel(obj.w)>0
                y_est = x*obj.w;
            else
                y_est = zeros(size(x,1),1);
            end
        end

        function train(obj,x,y) % train the algorithm
            if numel(obj.w)==0 % initialize
                m = length(x);
                obj.w = zeros(m,1);
                obj.P = obj.c\eye(m);
            end

            g = obj.P*x'/(obj.lambda+x*obj.P*x'); % gain vector
            err = y - x*obj.w; % instantaneous error
            obj.w = obj.w + g*err; % update filter coefficients
            obj.P = obj.lambda\(obj.P - g*x*obj.P); % update inv. autocorr.
        end

    end
end


function [forecast_record]=forecasttv2(data_endo_a,data_exo_p,It,Bu,beta_gibbs,omega_gibbs,F_gibbs,phi_gibbs,L_gibbs,gamma,sbar,Fstartlocation,Fperiods,n,p,k,q,const)

% create first the cell storing the results
forecast_record=cell(n,1);

% other preliminary tasks: generate the matrix of predicted exogenous variables
% if the constant has been retained, augment the matrices of exogenous with a column of ones:
if const==1
data_exo_p=[ones(Fperiods,1) data_exo_p];
% if no constant was included, do nothing
else
end

% then start simulations
% repeat the process a number of times equal to the number of simulations retained from Gibbs sampling
for ii=1:It-Bu

% compute the reduced matrix Y
Y=data_endo_a(end-p+1:end,:);

% step 3: draw beta, omega and sigma and F from their posterior distributions
% draw beta
beta=beta_gibbs{Fstartlocation-1,1}(:,ii);
% draw omega
omega=omega_gibbs(:,ii);
% create a choleski of omega, the variance matrix for the law of motion
cholomega=sparse(diag(omega));
% draw F from its posterior distribution
F=sparse(F_gibbs(:,:,ii));
% step 4: draw phi from its posterior
phi=phi_gibbs(ii,:)';
% also, compute the pre-sample value of lambda, the stochastic volatility process
lambda=L_gibbs(Fstartlocation-1,:,ii)';

   % then generate forecasts recursively
   % for each iteration ii, repeat the process for periods T+1 to T+h
   for jj=1:Fperiods

   % update beta
   beta=beta+cholomega*randn(q,1);
   % reshape it to obtain B
   B=reshape(beta,k,n);

   % use the function lagx to obtain the matrix temp
   temp=bear.lagx(Y,p-1);
   % define the reduced regressor matrix X
   % if no exogenous variable is present at all in the model (neither constant nor other exogenous), define X only from the endogenous variables
      if isempty(data_exo_p)==1
      X=[temp(end,:)];
      % if there are exogenous vaiables, concatenate them next to the endogenous
      else
      X=[temp(end,:) data_exo_p(jj,:)];
      end

   % update lambda_t and obtain Lambda_t
   % loop over variables
      for kk=1:n
      lambda(kk,1)=gamma*lambda(kk,1)+phi(kk,1)^0.5*randn;
      end
   % obtain Lambda_t
   Lambda=sparse(diag(sbar.*exp(lambda)));

   % recover sigma_t and draw the residuals
   sigma=full(F*Lambda*F');
   % draw the vector of residuals
   res=bear.trns(chol(bear.nspd(sigma),'Lower')*randn(n,1));

   % obtain predicted value for T+jj
   yp=X*B+res;

   % concatenate the transpose of yp to the top of Y
   Y=[Y;yp];

   % step 8: repeat until values are obtained for T+h
   end

   % record the results from current iteration in the cell forecast_record
   % loop over variables
   for kk=1:n
   % consider column kk of matrix Y and trim the p initial values: what remains is the predicted values for the period T+1 to T+h, for variable kk
   temp1=Y(p+1:end,kk);
   % record these values in the corresponding matrix of forecast_record
   forecast_record{kk,1}(ii,:)=temp1';
   end

% step 9: repeat until It-Bu iterations are obtained
end


%% cellEig
% Below is a demonstration of the features of the |cellEig| function

%% Syntax
% |[V,D]=cellEig(C);|

%% Description
% Computes eigenvalues and eigenvectors for each matrix contained in the
% cell array C, i.e. [v,d]=eig(c) is executed for each cell entry. The
% output is two cell arrays, i.e. the cell V containing the eigenvectors
% and the cell D containing the eigenvalues.

%% Examples

%%
clear; close all; clc;

%% Example: Calculating eigenvalues for matrices contained in cells
% Creating example cell containing two matrices

M1=rand(3,3);
M1=M1*M1';
M2=rand(5,5);
M2=M2*M2';

C={M1,M2};
[V,D]=cellEig(C);

%%
% Contained in the output cells are the eigenvectors and eigenvalues of
% each of the matrices e.g. for the first
v1=V{1}
d1=D{1}

%%
% and the second entry
v2=V{2}
d2=D{2}

%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% 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 gray = gray_salt_and_pepper ( gray, level )

%*****************************************************************************80
%
%% GRAY_SALT_AND_PEPPER adds salt-and-pepper noise to a grayscale image.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    26 February 2011
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, uint8 GRAY(:,:), the image.
%
%    Input, real LEVEL, the level of noise to add, between 0.0 (none)
%    and 1.0 (all).
%
%    Output, uint8 GRAY(:,:), the image with added noise.  A fraction of
%    about LEVEL of the pixels have been reset to 0 or 255.
%
  [ m, n ] = size ( gray );

  r = rand ( m, n );

  i0 = find ( r <= level / 2 );
  gray ( i0 ) = 0;

  i255 = find ( 1 - level / 2 <= r );
  gray ( i255 ) = 255;

  return
end


function [rs,rp]=reflectionCoeffsVec(e1,e2,k,n,u1,u2)
%%REFLECTIONCOEFFSVEC Reflection coefficients for the reflection of an
%           electromagnetic plane wave from a LOSSLESS medium off a LOSSY
%           medium (or another lossless medium) are computed given a vector
%           in the direction of propagation of the light and a vector
%           normal to the surface. Both media must have real
%           permeabilities. For example, one might approximate the
%           troposphere as lossless while accounting for the loss in sea
%           water. Lossy media have complex permittivities. This function
%           is a different parameterization of reflectionCoeffs.
%
%INPUTS: e1 The permittivity (refraction index) of the lossless medium.
%           The incoming ray is traveling through this prior to reflecting
%           off of the surface with permittivity e2. This must be a real
%           quantity (lossless). e1 and e2 can both be either absolute
%           permittivities or relative permittivities. "Relative" means
%           that the permittivity of the medium has been divided by the
%           permittivity of free space and is a dimensionless quantity.
%        e2 The permittivity of the medium against which the ray reflects.
%           This can be complex (lossy).
%         k A 3X1 vector in the direction of propagation of the light
%           approaching the surface from which it will reflect.
%         n A 3X1 normal vector to the surface of reflection. It does not
%           matter whether n is pointing up or down from the surface.
%        u1 The permeability of the lossless medium. This must be
%           a real quantity.  u1 and u2 can both be either absolute
%           permeabilities or relative permeabilities. If omitted or an
%           empty matrix is passed, a value of 1 is used (the permeability
%           equals that of free space). That is a reasonable approximation
%           for air.
%        u2 The permeability of the lossy medium against which the incoming
%           ray reflects. medium. This must be a real quantity. If omitted
%           or an empty matrix is passed, a value of 1 is used. That is a
%           reasonable approximation for water.
%
%OUTPUTS: rs The complex reflection coefficient for s-polarized light, also
%            known as transverse-Electric (TE) polarized light.
%         rp The complex reflection coefficient for p-polarized light, also
%            known as transverse-Magnetic (TM) polarized light and as
%            tangent-plane polarized light.
%
%This function uses angBetweenVecs to get the angle between the incoming
%vector and the normal to the surface (adjusting in case one should have
%used -n instead of n) and then calls reflectionCoeffs.
%
%July 2021 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

if(nargin<6||isempty(u2))
    u2=1;
end

if(nargin<5||isempty(u1))
    u1=1;
end

thetai=angBetweenVecs(k,n);

if(thetai>pi/2)
    %If -n should have been used instead of n.
    thetai=pi-thetai;
end
[rs,rp]=reflectionCoeffs(e1,e2,thetai,u1,u2);

end

%LICENSE:
%
%The source code is in the public domain and not licensed or under
%copyright. The information and software may be used freely by the public.
%As required by 17 U.S.C. 403, third parties producing copyrighted works
%consisting predominantly of the material produced by U.S. government
%agencies must provide notice with such work(s) identifying the U.S.
%Government material incorporated and stating that such material is not
%subject to copyright protection.
%
%Derived works shall not identify themselves in a manner that implies an
%endorsement by or an affiliation with the Naval Research Laboratory.
%
%RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE
%SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY THE NAVAL
%RESEARCH LABORATORY FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE ACTIONS
%OF RECIPIENT IN THE USE OF THE SOFTWARE.


function cc_level_compose_animate ( )

%*****************************************************************************80
%
%% CC_LEVEL_COMPOSE_ANIMATE displays the grids that compose one level.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    16 November 2006
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  timestamp ( );

  fprintf ( 1, '\n' );
  fprintf ( 1, 'CC_LEVEL_COMPOSE_ANIMATE:\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Display the nested 2D Clenshaw-Curtis grids\n' );
  fprintf ( 1, '  that compose one level.\n' );

  dim_num = 2;

  while ( 1 )
%
%  Get user input.
%
    fprintf ( 1, '\n' );
    level = input ( 'Enter the LEVEL or RETURN to exit;' );

    if ( isempty ( level ) )
      break
    end
%
%  Generate the entire set of points.
%
    [ grid_num, point_num ] = cc_levels_minmax_size ( dim_num, ...
      level, level );

    [ grid_level, grid_order, grid_points ] = cc_levels_minmax ( dim_num, ...
      level, level,  grid_num, point_num );

    [ dim_num, grid_points_num ] = size ( grid_points );
%
%  Display the full set of points as filled blue circles.
%
    clf
    axes_handle = axes;
    handle_new = scatter ( grid_points(1,:), grid_points(2,:), 'b', 'filled' );
    axis square
    grid on
    set ( axes_handle, 'xtick', [ -1, -.75, -.5, -.25, 0, .25, .50, .75, 1] );
    set ( axes_handle, 'xticklabel', [] );
    set ( axes_handle, 'ytick', [ -1, -.75, -.5, -.25, 0, .25, .50, .75, 1] );
    set ( axes_handle, 'yticklabel', [] );
    axis ( [ -1.1, 1.1, -1.1, 1.1 ] )
    s = sprintf ( 'Entire grid for LEVEL %d', level );
    title ( s );
    fprintf ( 1, 'Press return\n', level );
    pause

    hold off
%
%  Display the full set of points in gray.
%  Display each contributing grid, one at a time, in red.
%
    for gridd = 1 : grid_num

      order_1d(1:2) = grid_order(1:2,gridd)
      order_nd = prod ( order_1d(1:2) );
      grid_points_new = cc_grid ( dim_num, order_1d, order_nd );

      clf
%
%  We have to name the axes in order to control the grid.
%
      axes_handle = axes;
%
%  Plot the OLD points.
%
      handle_old = scatter ( grid_points(1,:), grid_points(2,:), 'bo' );

      hold on

      handle_new = scatter ( grid_points_new(1,:), grid_points_new(2,:), ...
        'r', 'filled' );
%
%  Force the plotting region to be square, not rectangular.
%
      axis square
%
%  Request grid lines.
%
      grid on
%
%  Specify the location of the grid lines, and suppress labeling.
%
      set ( axes_handle, 'xtick', [ -1, -.75, -.5, -.25, 0, .25, .50, .75, 1] );
      set ( axes_handle, 'xticklabel', [] );
      set ( axes_handle, 'ytick', [ -1, -.75, -.5, -.25, 0, .25, .50, .75, 1] );
      set ( axes_handle, 'yticklabel', [] );
%
%  Make the plotting region slightly bigger than the data.
%
      axis ( [ -1.1, 1.1, -1.1, 1.1 ] )
%
%  Title
%
      s = sprintf ( '+ %d * %d CC grid', grid_level(1,gridd), grid_level(2,gridd) );
      title ( s );

      fprintf ( 1, '+ %d*%d CC grid, Press return\n', ...
        grid_level(1,gridd), grid_level(2,gridd) );
      pause

      hold off

    end
%
%  Display the full set of points as filled blue circles.
%
    clf
    axes_handle = axes;
    handle_new = scatter ( grid_points(1,:), grid_points(2,:), 'b', 'filled' );
    axis square
    grid on
    set ( axes_handle, 'xtick', [ -1, -.75, -.5, -.25, 0, .25, .50, .75, 1] );
    set ( axes_handle, 'xticklabel', [] );
    set ( axes_handle, 'ytick', [ -1, -.75, -.5, -.25, 0, .25, .50, .75, 1] );
    set ( axes_handle, 'yticklabel', [] );
    axis ( [ -1.1, 1.1, -1.1, 1.1 ] )
    s = sprintf ( 'Entire grid for LEVEL %d', level );
    title ( s );
    fprintf ( 1, 'Press return\n', level );
    pause

    hold off

    fprintf ( 1, 'Press return to CLEAR the grid!\n' );
    pause
    clf

  end

  fprintf ( 1, '\n' );
  fprintf ( 1, 'CC_LEVEL_COMPOSE_ANIMATE:\n' );
  fprintf ( 1, '  Normal end of execution.\n' );

  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Spherical Harmonic Modeling and Analysis Toolkit (SPHARM-MAT) is a 3D
% shape modeling and analysis toolkit.
% It is a software package developed at Shenlab in Center for Neuroimaging,
% Indiana University (SpharmMat@gmail.com, http://www.iupui.edu/~shenlab/)
% It is available to the scientific community as copyright freeware
% under the terms of the GNU General Public Licence.
%
% Copyright 2009, 2010, ShenLab, Center for Neuroimaging, Indiana University
%
% This file is part of SPHARM-MAT.
%
% SPHARM-MAT 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.
%
% SPHARM-MAT 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 SPHARM-MAT. If not, see <http://www.gnu.org/licenses/>.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% ============================================
% FLD.m
%
% Goal:
%   1. Calculate the optimal FLD projection
%   2. For two class problem
%
% Li Shen
% 11/13/2002 - create

function [FLD_basis, FLD_vals] = FLD(Samples,Labels)

d = size(Samples);
if (d(2)>d(1)-2)
    disp('---------------------------------');
    disp(sprintf('N=%d points, M=%d dims (IGNORE the last %d dims): a nonsigular Sb requires M<=N-c (c=2)',d,d(2)-d(1)+2));
    disp('---------------------------------');
    Samples = Samples(:,1:d(1)-2);
end

FLD_basis = [];

Sb = get_Sb(Samples,Labels);
Sw = get_Sw(Samples,Labels);

[V,D] = eig(Sb,Sw);

[eigval,ind] = sort(diag(D));

FLD_basis = V(:,ind(end));

FLD_vals = Samples*FLD_basis;

return;

%
% calculate between class scatter matrix Sb
%

function Sb = get_Sb(Samples,Labels)

c1_ind = find(Labels==1); c2_ind = find(Labels==2);
m = mean(Samples,1); m1_m = mean(Samples(c1_ind,:),1) - m ; m2_m = mean(Samples(c2_ind,:),1) - m;
Sb = length(c1_ind)*(m1_m'*m1_m) + length(c2_ind)*(m2_m'*m2_m);

return;

%
% calculate within class scatter matrix Sw
%

function Sw = get_Sw(Samples,Labels)

c1_ind = find(Labels==1); c2_ind = find(Labels==2);

% need to have at least 2 points in each class
Sw = cov(Samples(c1_ind,:))*(length(c1_ind)-1) + cov(Samples(c2_ind,:))*(length(c2_ind)-1);

return;

%
% calculate within class scatter matrix Sw (directly according to the definition)
%

function Sw = get_Sw_v2(Samples,Labels)

c1_ind = find(Labels==1); c2_ind = find(Labels==2);

% to verify the correctness of Sw
Sw = zeros(size(Samples,2));
m1 = mean(Samples(c1_ind,:),1);
xs1 = Samples(c1_ind,:) - m1(ones(1,length(c1_ind)),:);
for i = 1:size(xs1,1)
    Sw = Sw + xs1(i,:)'*xs1(i,:);
end

m2 = mean(Samples(c2_ind,:),1);
xs2 = Samples(c2_ind,:) - m2(ones(1,length(c2_ind)),:);
for i = 1:size(xs2,1)
    Sw = Sw + xs2(i,:)'*xs2(i,:);
end

return;


function [mfg, mbg] = im_modes(im)
% IM_MODES  Estimate typical values (modes) of foreground/background
% intensities in a greyscale image.
%
% [MFG, MBG] = im_modes(IM)
%
%   IM is an N-array of grayscale intensity values.
%
%   MFG, MBG are scalars with the typical intensity values of foreground
%   (darker) and foreground (lighter) voxels. "Typical" means the mode of
%   the corresponding distributions.
%
%   The modes are estimated by computing histograms with up to 500 bins for
%   the intensity values, and smoothing the distribution until only 1 or 2
%   peaks are visible. In case of 1 peak, it is assume that the image
%   contains only background voxels, and MFG=NaN.

% Author: Ramon Casero <rcasero@gmail.com>
% Copyright © 2014 University of Oxford
% Version: 0.1.0
%
% University of Oxford means the Chancellor, Masters and Scholars of
% the University of Oxford, having an administrative office at
% Wellington Square, Oxford OX1 2JD, UK.
%
% This file is part of Gerardus.
%
% 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. The offer of this
% program under the terms of the License is subject to the License
% being interpreted in accordance with English Law and subject to any
% action against the University of Oxford being under the jurisdiction
% of the English Courts.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see
% <http://www.gnu.org/licenses/>.

DEBUG = 0;

% check arguments
narginchk(1, 1);
nargoutchk(0, 2);

% ignore intensity values = 0. Those are considered to be masked out
im2 = im(im > 0);

% if the input image is empty, or too small, we assume that we don't have
% enough information to estimate the background and foreground
if (nnz(im2) < 100)
    mbg = nan;
    mfg = nan;
    return
end

% number of bins to use. We assume that we need at least 10 samples per
% bin, but we don't need more than 500 bins in total. Histograms with more
% bins are slower to process and smooth
nbin = min(500, ceil(nnz(im2)/10));

% compute histogram of the intensity values
[fhist, xhist] = hist(im2, nbin);
fhist = fhist / sum(fhist);

% initial estimation of peaks in the histogram
[pks, loc] = findpeaks(fhist, 'minpeakheight', 0.5e-3);

% number of peaks found
npks = length(pks);

% smooth the histogram until we find just 1 or 2 peaks
tol = 0.5e-10;
while ~((npks == 1) ...
        || ((npks == 2) && (abs(diff(loc)) >= 50)))

    % increase the smoothing parameter
    tol = tol * 2;

    % smooth the histogram
    [~, fhist2] = spaps(xhist, fhist, tol);

    % find the peaks
    [pks, loc] = findpeaks(fhist2, 'minpeakheight', 0.5e-3);

    % number of peaks found
    npks = length(pks);

end

% deal with the number of peaks
if (npks == 2)

    % we have background and tissue. The background is lighter. Sort the
    % peaks in darker to lighter order
    loc = sort(loc, 'ascend');

    % extract typical intensities for background and foreground
    mfg = xhist(loc(1));
    mbg = xhist(loc(2));

    % DEBUG
    if (DEBUG)
        subplot(2, 1, 1)
        hold off
        plot(xhist, fhist, 'b')
        hold on
        plot(xhist, fhist2, 'r')
        plot(mfg*[1 1], [0 max(fhist)], 'g')
        plot(mbg*[1 1], [0 max(fhist)], 'k')

        subplot(2, 1, 2)
        hold off
        imagesc(im(:, :, round((size(im, 3)+1)/2)))
    end

elseif (npks == 1)

    % we assume there's only background (although note that this could be a
    % case with only tissue)
    mfg = nan;
    mbg = xhist(loc);

    % DEBUG
    if (DEBUG)
        hold off
        plot(xhist, fhist, 'b')
        hold on
        plot(xhist, fhist2, 'r')
        plot(mbg*[1 1], [0 max(fhist)], 'r')
    end

else

    error('Assertion fail: The histogram has no peaks')

end

end


function errors = test_jtv_filter()
%TEST_JTV_FILTER This function test all the time-vertex filters
close all
errors = 0;
warning on

errors = errors + test_jtv_graph();
errors = errors + test_jtv_graph_diagonalization();

errors = errors + test_diffusion();
errors = errors + test_wave();
errors = errors + test_jft_ijft();
errors = errors + test_swap_transform();

errors = errors + test_theory()
errors = errors + test_swap_localization();

errors = errors + test_jtv_cheb_coeff();
errors = errors + test_jtv_cheb_op();

errors = errors + test_jtv_filter_evaluate();
errors = errors + test_jtv_filter_array();

errors = errors + test_jtv_filter_analysis();
errors = errors + test_jtv_filter_synthesis();

errors = errors + test_jtv_matrix_analysis_op();
errors = errors + test_jtv_matrix_synthesis_op();

errors = errors + test_jtv_filter_dual();
errors = errors + test_jtv_filter_inverse();

try  %#ok<TRYNC>
    close(100)
end

end

function errors = test_jtv_graph()
errors=0;

try

    N = 100;
    T = 200;
    fs = 1;
    G = gsp_sensor(N);
    G = gsp_jtv_graph(G,T,fs);

    fprintf('Test JTV - timevertex graph:  OK\n');
catch
    errors = errors + 1;
    warning('Test JTV - Error in timevertex graph test')
end

end

function errors = test_jtv_graph_diagonalization()
errors  = 0;
T=30;
N=20;
G = gsp_sensor(N);
G = gsp_compute_fourier_basis(G);
DFT = dftmtx(T)';

Gt = gsp_ring(T);
Gp = gsp_graph_product(G,Gt);
Gp = gsp_create_laplacian(Gp,'combinatorial');
Gp = gsp_compute_fourier_basis(Gp);

U = kron(G.U,DFT);

errors = errors + gsp_assert_test(U'*Gp.L*U,diag(diag(U'*Gp.L*U)),1e-10,'JTV - diagonalization test');

end

function errors = test_diffusion()

errors = 0;
try

    N = 100;
    T = 200;
    G = gsp_sensor(N);
    G = gsp_jtv_graph(G,T);
    G = gsp_estimate_lmax(G);
    [g,ft] = gsp_jtv_design_diffusion(G);
    gsp_plot_jtv_filter(G,g,ft);
    close

    fprintf('JTV: diffusion kernel 1 ok\n');
catch
    errors = errors + 1;
    warning('JTV: Error diffusion kernel 1 test')
end

try

    N = 100;
    T = 200;
    G = gsp_sensor(N);
    G = gsp_jtv_graph(G,T);
    G = gsp_estimate_lmax(G);
    tau=.1;
    [g,ft] = gsp_jtv_design_diffusion(G,tau);
    gsp_plot_jtv_filter(G,g,ft);
    close

    fprintf('JTV: diffusion kernel 2 ok\n');
catch
    errors = errors + 1;
    warning('JTV: Error diffusion kernel 2 test')
end

try

    N = 100;
    T = 200;
    G = gsp_sensor(N);
    G = gsp_jtv_graph(G,T);
    G = gsp_estimate_lmax(G);

    tau=[.01 0.1 1 2];
    param.normalize=1;
    param.show_sum=0;
    param.title=num2cell(tau);
    [g,ft] = gsp_jtv_design_diffusion(G,tau,param);

    gsp_plot_jtv_filter(G,g,ft);
    close

    fprintf('JTV: diffusion kernel 3 ok\n');
catch
    errors = errors + 1;
    warning('JTV: Error diffusion kernel 3 test')
end

end

function errors = test_wave()

errors = 0;
try

    N = 100;
    T = 200;
    G = gsp_sensor(N);
    G = gsp_jtv_graph(G,T);
    G = gsp_estimate_lmax(G);

    [g,ft] = gsp_jtv_design_wave(G);
    gsp_plot_jtv_filter(G,g,ft);

    close

    fprintf('JTV: wave kernel 1 ok\n');
catch
    errors = errors + 1;
    warning('JTV: Error wave kernel 1 test')
end

try

    N = 100;
    T = 200;
    G = gsp_sensor(N);
    G = gsp_jtv_graph(G,T);
    G = gsp_estimate_lmax(G);

    alpha=1;
    [g,ft] = gsp_jtv_design_wave(G,alpha);
    gsp_plot_jtv_filter(G,g,ft);

    close

    fprintf('JTV: wave kernel 2 ok\n');
catch
    errors = errors + 1;
    warning('JTV: Error wave kernel 2 test')
end

try

    N = 100;
    T = 200;
    G = gsp_sensor(N);
    G = gsp_jtv_graph(G,T);
    G = gsp_estimate_lmax(G);

    alpha=1;
    param.normalize=1;
    [g,ft] = gsp_jtv_design_wave(G,alpha,param);
    gsp_plot_jtv_filter(G,g,ft);

    close

    fprintf('JTV: wave kernel 3 ok\n');
catch
    errors = errors + 1;
    warning('JTV: Error wave kernel 3 test')
end

end

function errors = test_jft_ijft()
errors = 0;

try

    N=50;
    T=100;
    G = gsp_sensor(N);
    G = gsp_jtv_graph(G,T);
    G = gsp_compute_fourier_basis(G);

    x = randn(N,T);

    xhat = gsp_jft(G,x);

catch
    errors = errors + 1;
    warning('JTV: Error jtgft test')
end

try

    N=50;
    T=100;
    G = gsp_sensor(N);
    G = gsp_jtv_graph(G,T);
    G = gsp_compute_fourier_basis(G);

    xhat = randn(N,T);
    x = gsp_ijft(G,x);

catch
    errors = errors + 1;
    warning('JTV: Error ijtgft test')
end

N=50;
T=100;
G = gsp_sensor(N);
G = gsp_jtv_graph(G,T);
G = gsp_compute_fourier_basis(G);

x = randn(N,T);

x2 = gsp_ijft(G,gsp_jft(G,x));

errors = errors + gsp_assert_test(x,x2,eps(1000),'JTV - inverse jtv Fourier transform');

x = rand(N,T,1);

s1 = gsp_jft(G,x);
s2 = gsp_jft_simple(G,x);

errors = errors + gsp_assert_test(s1,s2,eps(1000),'JTV - JFT 1 dim');

x = rand(N,T,10);

s1 = gsp_jft(G,x);
s2 = gsp_jft_simple(G,x);

errors = errors + gsp_assert_test(s1,s2,eps(1000),'JTV - JFT 2 dim');

end

function errors = test_swap_transform()
errors = 0;

N=50;
T=100;
G = gsp_sensor(N);
G = gsp_jtv_graph(G,T);
G = gsp_compute_fourier_basis(G);

x = randn(N,T);

x1 = fft(gsp_gft(G,x),[],2)/sqrt(T);
x2 = gsp_gft(G,fft(x,[],2))/sqrt(T);
x3 = gsp_jft(G,x);

e1 = norm(x1-x2,'fro')/norm(x1,'fro');
e2 = norm(x1-x3,'fro')/norm(x1,'fro');
e3 = norm(x2-x3,'fro')/norm(x2,'fro');

errors = errors + gsp_assert_test(0,mean([e1 e2 e3]),eps(1000),'JTV - commutative fft gft transform');

%

xhat = gsp_jft(G,x);

x1 = ifft(gsp_igft(G,xhat),[],2)*sqrt(T);
x2 = gsp_igft(G,ifft(xhat,[],2))*sqrt(T);
x3 = gsp_ijft(G,xhat);

e1 = norm(x1-x2,'fro')/norm(x1,'fro');
e2 = norm(x1-x3,'fro')/norm(x1,'fro');
e3 = norm(x2-x3,'fro')/norm(x2,'fro');

errors = errors + gsp_assert_test(0,mean([e1 e2 e3]),eps(1000),'JTV - commutative ifft igft transform');

end

function errors = test_swap_localization()
errors = 0;

N = 100;
T = 50;
G = gsp_sensor(N);
G = gsp_jtv_graph(G,T);
G = gsp_compute_fourier_basis(G);

x = rand(N,T);
vertex=randi(N);
time=randi(T);

% to be updated (with gsp_localize?)
error('Does the boundary still make sense?')
param.boundary='periodic';
x1p = gsp_time_translate(G,gsp_translate_old(G,x,vertex),time,param);
x2p = gsp_translate_old(G,gsp_time_translate(G,x,time,param),vertex);
param.boundary='symmetric';
x1s = gsp_time_translate(G,gsp_translate_old(G,x,vertex),time,param);
x2s = gsp_translate_old(G,gsp_time_translate(G,x,time,param),vertex);
param.boundary='absorbing';
x1a = gsp_time_translate(G,gsp_translate_old(G,x,vertex),time,param);
x2a = gsp_translate_old(G,gsp_time_translate(G,x,time,param),vertex);

n1=norm(x1p-x2p)/norm(x1p);
n2=norm(x1s-x2s)/norm(x1s);
n3=norm(x1a-x2a)/norm(x1a);

if  (n1+n2+n3)/3< eps(1000)
    fprintf('JTV: commutative translation operator ok\n');

else
    errors = errors + 1;
    warning('JTV: error commutative translation operator test')
end

end

function errors = test_jtv_cheb_coeff()
errors = 0;

try
    N = 100;
    T = 50;
    alpha = 1;
    G = gsp_sensor(N);
    G = gsp_jtv_graph(G,T);
    G = gsp_estimate_lmax(G);
    [g,ft] = gsp_jtv_design_wave(G, alpha);
    c = gsp_jtv_cheby_coeff(G, g,ft);

    fprintf('FILTER: jtv cheb coeff 1 ok\n');

catch
    errors = 1;
    warning('FILTER: Error in jtv cheb coeff 1 test')
end

try
    N = 100;
    T = 50;
    alpha = [ 0.1 0.5 1 ];
    G = gsp_sensor(N);
    G = gsp_jtv_graph(G,T);
    G = gsp_estimate_lmax(G);
    [g,ft] = gsp_jtv_design_wave(G, alpha);
    c = gsp_jtv_cheby_coeff(G, g,ft);

    fprintf('FILTER: jtv cheb coeff 2 ok\n');

catch
    errors = 1;
    warning('FILTER: Error in jtv cheb coeff 2 test')
end

end

function errors = test_jtv_cheb_op()

errors = 0;
try
    N = 100;
    T = 50;
    G = gsp_sensor(N);
    G = gsp_jtv_graph(G,T);
    G = gsp_estimate_lmax(G);
    alpha = 1;
    [g,ft] = gsp_jtv_design_wave(G, alpha);
    c = gsp_jtv_cheby_coeff(G, g,ft);
    f = randn(N,T);
    r = gsp_jtv_cheby_op(G, c, f);

    fprintf('FILTER: cheb op ok\n');
catch
    errors = 1;
    warning('FILTER: Error in cheb op test')
end

end

function errors = test_jtv_filter_evaluate()
errors = 0;

N = 100;
T = 100;
G = gsp_sensor(N);
G = gsp_compute_fourier_basis(G);
G = gsp_jtv_graph(G,T);

alpha=1;
[g,ft] = gsp_jtv_design_wave(G,alpha);
x = G.e;
param.filtertype = ft;
t = gsp_jtv_ta(G);
f = gsp_jtv_fa(G);

x1 = gsp_jtv_filter_evaluate_simple(G,g,x,param);

x2 = gsp_jtv_filter_evaluate(g,ft,x,t,param);

errors = errors + gsp_assert_test(x1,x2,1e-12,'JTV filter evaluate 1');

g = @(x,y) x+y;
ft = 'js';
param.filtertype = ft;
x1 = gsp_jtv_filter_evaluate_simple(G,g,x,param);

x2 = gsp_jtv_filter_evaluate(g,ft,x,f);

errors = errors + gsp_assert_test(x1,x2,1e-12,'JTV filter evaluate 2');

end

function errors = test_jtv_filter_array()
errors = 0;

N = 500;
T = 100;
G = gsp_sensor(N);
G = gsp_compute_fourier_basis(G);
G = gsp_jtv_graph(G,T);

alpha=[0 0.5 0.7 1];
[g,ftg] = gsp_jtv_design_wave(G,alpha);
x = G.e;
t = gsp_jtv_ta(G);

[h,fth] = gsp_jtv_filter_array(G,g,ftg);

x1 = gsp_jtv_filter_evaluate(g,ftg,x,t);
x2 = gsp_jtv_filter_evaluate(h,fth,x,t);

errors = errors + gsp_assert_test(x1,x2,1e-12,'JTV filter array 1');

g = @(x,y) exp((x-y.^2)/0.1);
ftg = 'js';
f = gsp_jtv_fa(G);

[h,fth] = gsp_jtv_filter_array(G,g,ftg);

x1 = gsp_jtv_filter_evaluate(g,ftg,x,f);
x2 = gsp_jtv_filter_evaluate(h,fth,x,f);

errors = errors + gsp_assert_test(x1,x2,1e-12,'JTV filter array 2');

end

function errors = test_jtv_filter_analysis()
%%
errors = 0;

try
    N = 100;
    T = 500;
    G = gsp_sensor(N);
    G = gsp_jtv_graph(G,T);
    G = gsp_compute_fourier_basis(G);

    alpha=[0.1:0.1:0.7];
    [g,ft] = gsp_jtv_design_wave(G,alpha);

    x = rand(N,T);

    param.method = 'exact';
    coeff = gsp_jtv_filter_analysis(G,g,ft,x,param);

    fprintf('JTV: analysis ok\n');
catch
    errors = errors + 1;
    warning('JTV: Error analysis test')
end

N = 1000;
T = 100;
G = gsp_sensor(N);
G = gsp_jtv_graph(G,T);
G = gsp_estimate_lmax(G);

alpha=[0.1:0.1:0.7];
[g,ft] = gsp_jtv_design_wave(G,alpha);

x = randn(N,T);

param.method = 'exact';
tic
G = gsp_compute_fourier_basis(G);
c_exact = gsp_jtv_filter_analysis(G,g,ft,x,param);
param.filtertype = ft;
c_exact2 = gsp_jtv_filter_analysis_simple(G,g,x,param);
time=toc;
fprintf(['Eigendecomposition + Exact filtering time: ' num2str(time) '\n'])

errors = errors + gsp_assert_test(c_exact,c_exact2,1e-10,'JTV - exact analysis 1');

param.method = 'cheby';
param.order=40;
tic
c_cheby = gsp_jtv_filter_analysis(G,g,ft,x,param);
time=toc;
fprintf(['Cheby filtering time: ' num2str(time) '\n'])

errors = errors + gsp_assert_test(c_exact,c_cheby,1e-4,'JTV - cheby analysis 1');

param.method = 'exact';
g = @(x,y) exp(-x.*(y.^2)/0.1);
ft = 'js';
c_exact = gsp_jtv_filter_analysis(G,g,ft,x,param);

param.filtertype = ft;
c_exact2 = gsp_jtv_filter_analysis_simple(G,g,x,param);
errors = errors + gsp_assert_test(c_exact,c_exact2,1e-10,'JTV - exact analysis 2');

param.method = 'cheby';
param.order=20;
c_cheby = gsp_jtv_filter_analysis(G,g,ft,x,param);

errors = errors + gsp_assert_test(c_exact,c_cheby,1e-4,'JTV - cheby analysis 2');

end

function errors = test_jtv_filter_synthesis()
errors = 0;

N = 500;
T = 300;
G = gsp_sensor(N);
G = gsp_jtv_graph(G,T);
G = gsp_compute_fourier_basis(G);

alpha=[0.1:0.1:0.7];
[g,ft] = gsp_jtv_design_wave(G,alpha);

param.lag=1;
x = rand(N,T,numel(alpha));
param.method = 'exact';
s = gsp_jtv_filter_synthesis(G,g,ft,x,param);

param.filtertype = ft;
s2 = gsp_jtv_filter_synthesis_simple(G,g,x,param);

errors = errors + gsp_assert_test(s,s2,1e-10,'JTV  - exact synthesis 1');

param.method = 'cheby';
param.order=200;
s2 = gsp_jtv_filter_synthesis(G,g,ft,x,param);

errors = errors + gsp_assert_test(s,s2,1e-10,'JTV - cheby synthesis 1');

param.method = 'exact';
g = @(x,y) exp(-x.*(y.^2)/0.1);
ft = 'js';
x = rand(N,T,1,3);
s = gsp_jtv_filter_synthesis(G,g,ft,x,param);

param.filtertype = ft;
s2 = gsp_jtv_filter_synthesis_simple(G,g,x,param);
errors = errors + gsp_assert_test(s,s2,1e-10,'JTV  - exact synthesis 2');

param.method = 'cheby';
param.order=20;
s2 = gsp_jtv_filter_synthesis(G,g,ft,x,param);
time=toc;

errors = errors + gsp_assert_test(s,s2,1e-4,'JTV - cheby analysis 2');

end

function errors = test_jtv_matrix_analysis_op()
errors = 0;

N = 20;
T = 20;
G = gsp_sensor(N);
G = gsp_jtv_graph(G,T);
G = gsp_compute_fourier_basis(G);

alpha = 1;
[g,ft] = gsp_jtv_design_wave(G,alpha);

F = gsp_jtv_compute_frame(G,g,ft);

x = rand(N,T);

c1 = gsp_jtv_frame_analysis(F,x);

param.method = 'exact';
c2 = gsp_jtv_filter_analysis(G,g,ft,x,param);

errors = errors + gsp_assert_test(c1,c2,eps(1000),'JTV - analysis operator matrix');

end

function errors = test_jtv_matrix_synthesis_op()
errors = 0;

N = 20;
T = 20;
G = gsp_sensor(N);
param.extension=1;
G = gsp_jtv_graph(G,T,[],param);
G = gsp_compute_fourier_basis(G);

[g,ft] = gsp_jtv_design_wave(G);

F = gsp_jtv_compute_frame(G,g,ft);

x = randn(N,T);

param.method = 'exact';

coeff = gsp_jtv_filter_analysis(G,g,ft,x,param);

x1 = gsp_jtv_frame_synthesis(F,coeff);

x2 = gsp_jtv_filter_synthesis(G,g,ft,coeff,param);

errors = errors + gsp_assert_test(x1,x2,eps(1000),'JTV - synthesis operator matrix');

end

function errors = test_jtv_filter_dual()
errors = 0;

N = 50;
T = 50;
G = gsp_sensor(N);
G = gsp_jtv_graph(G,T);
G = gsp_compute_fourier_basis(G);

alpha=linspace(0,2,5);
[g,ft] = gsp_jtv_design_damped_wave(G,alpha,[0.01 0.1]);

try
    gd = gsp_jtv_design_can_dual(g,ft);
    gsp_plot_jtv_filter(G,gd,ft);
    close
    fprintf('Test JTV - Canonical 1: OK \n');
catch
    errors = errors +1;
    warning('Test JTV - Error canonical dual')
end

N = 50;
T = 50;
G = gsp_sensor(N);
G = gsp_jtv_graph(G,T);
G = gsp_compute_fourier_basis(G);

Nf = 4;
g = gsp_jtv_design_meyer(G,Nf);

try
    gd = gsp_jtv_design_can_dual(g,ft);
    gsp_plot_jtv_filter(G,gd,ft);
    close
    fprintf('Test JTV - Canonical 2: OK \n');
catch
    errors = errors +1;
    warning('Test JTV - Error canonical dual')
end

end

function errors = test_jtv_filter_inverse()
%%
errors = 0;

N = 50;
T = 50;
G = gsp_sensor(N);
G = gsp_jtv_graph(G,T);
G = gsp_compute_fourier_basis(G);

alpha=linspace(0,2,5);
[g,ft] = gsp_jtv_design_damped_wave(G,alpha);
f = randn(N,T);

f1 = gsp_jtv_filter_analysis(G,g,ft,f);
f2 = gsp_jtv_filter_inverse(G,g,ft,f1);

errors = errors + gsp_assert_test(f,f2,eps(1000),'JTV - filter inverse 1');

[h,ft] = gsp_jtv_filter_array(G,g,ft);
f1 = gsp_jtv_filter_analysis(G,h,ft,f);
f2 = gsp_jtv_filter_inverse(G,h,ft,f1);
errors = errors + gsp_assert_test(f,f2,eps(1000),'JTV - filter inverse 2');

Nf = 4;
[g,ft] = gsp_jtv_design_meyer(G,Nf);
f1 = gsp_jtv_filter_analysis(G,g,ft,f);
f2 = gsp_jtv_filter_inverse(G,g,ft,f1);

errors = errors + gsp_assert_test(f,f2,eps(1000),'JTV - filter inverse 3');

[h,ft] = gsp_jtv_filter_array(G,g,ft);
f1 = gsp_jtv_filter_analysis(G,h,ft,f);
f2 = gsp_jtv_filter_inverse(G,h,ft,f1);
errors = errors + gsp_assert_test(f,f2,eps(1000),'JTV - filter inverse 4');

end

function errors = test_theory()

errors = 0;

N = 100;
T = 50;
G = gsp_sensor(N);
G = gsp_jtv_graph(G,T);
G = gsp_compute_fourier_basis(G);
g = @(x,w) abs(exp(-w.*x)).^2;
ft = 'js';
garray = gsp_jtv_filter_array(G,g,ft);
x1p = gsp_itft(G, gsp_vec2mat(gsp_filter_analysis(G,garray,gsp_delta(G,1) ),T))/sqrt(T);
x2p = gsp_jtv_filter_analysis(G,g,ft,gsp_jtv_delta(G,1,1));
% norm(x1p(:)/norm(x1p(:))-x2p(:)/norm(x2p(:)))

errors = errors +gsp_assert_test(x1p,x2p,1e-10,'TEST THEORY')

end


function [ sparse_order, sparse_index ] = sparse_grid_mixed_index ( ...
  dim_num, level_max, rule, point_num, point_total_num, sparse_unique_index )

%*****************************************************************************80
%
%% SPARSE_GRID_MIXED_INDEX indexes a sparse grid made from mixed 1D rules.
%
%  Discussion:
%
%    For each "unique" point in the sparse grid, we return its INDEX and ORDER.
%
%    That is, for the I-th unique point P, we determine the product grid which
%    first generated this point, and we return in SPARSE_ORDER the orders of
%    the 1D rules in that grid, and in SPARSE_INDEX the component indexes in
%    those rules that generated this specific point.
%
%    For instance, say P was first generated by a rule which was a 3D product
%    of a 9th order CC rule and a 15th order GL rule, and that to generate P,
%    we used the 7-th point of the CC rule and the 3rh point of the GL rule.
%    Then the SPARSE_ORDER information would be (9,15) and the SPARSE_INDEX
%    information would be (7,3).  This, combined with the information in RULE,
%    is enough to regenerate the value of P.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    05 March 2011
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Fabio Nobile, Raul Tempone, Clayton Webster,
%    A Sparse Grid Stochastic Collocation Method for Partial Differential
%    Equations with Random Input Data,
%    SIAM Journal on Numerical Analysis,
%    Volume 46, Number 5, 2008, pages 2309-2345.
%
%  Parameters:
%
%    Input, integer DIM_NUM, the spatial dimension.
%
%    Input, integer LEVEL_MAX, the maximum value of LEVEL.
%
%    Input, integer RULE(DIM_NUM), the rule in each dimension.
%     1, "CC",  Clenshaw Curtis, Closed Fully Nested rule.
%     2, "F2",  Fejer Type 2, Open Fully Nested rule.
%     3, "GP",  Gauss Patterson, Open Fully Nested rule.
%     4, "GL",  Gauss Legendre, Open Weakly Nested rule.
%     5, "GH",  Gauss Hermite, Open Weakly Nested rule.
%     6, "GGH", Generalized Gauss Hermite, Open Weakly Nested rule.
%     7, "LG",  Gauss Laguerre, Open Non Nested rule.
%     8, "GLG", Generalized Gauss Laguerre, Open Non Nested rule.
%     9, "GJ",  Gauss Jacobi, Open Non Nested rule.
%    10, "GW",  Golub Welsch, (presumed) Open Non Nested rule.
%    11, "CC_SE", Clenshaw Curtis Slow Exponential, Closed Fully Nested rule.
%    12, "F2_SE", Fejer Type 2 Slow Exponential, Closed Fully Nested rule.
%    13, "GP_SE", Gauss Patterson Slow Exponential, Closed Fully Nested rule.
%    14, "CC_ME", Clenshaw Curtis Moderate Exponential, Closed Fully Nested rule.
%    15, "F2_ME", Fejer Type 2 Moderate Exponential, Closed Fully Nested rule.
%    16, "GP_ME", Gauss Patterson Moderate Exponential, Closed Fully Nested rule.
%    17, "CCN", Clenshaw Curtis Nested, Linear, Closed Fully Nested rule.
%
%    Input, integer POINT_NUM, the number of unique points in the grid.
%
%    Input, integer POINT_TOTAL_NUM, the total number of points in the grid.
%
%    Input, integer SPARSE_UNIQUE_INDEX(POINT_TOTAL_NUM), associates each
%    point in the grid with its unique representative.
%
%    Output, integer SPARSE_ORDER(DIM_NUM,POINT_NUM), lists, for each point,
%    the order of the 1D rules used in the grid that generated it.
%
%    Output, integer SPARSE_INDEX(DIM_NUM,POINT_NUM), lists, for each point,
%    its index in each of the 1D rules in the grid that generated it.
%    The indices are 1-based.
%

%
%  Special cases.
%
  if ( level_max < 0 )
    sparse_order = [];
    sparse_index = [];
    return
  end

  if ( level_max == 0 )
    sparse_order(1:dim_num,1) = 1;
    sparse_index(1:dim_num,1) = 1;
    return
  end

  sparse_order = zeros ( dim_num, point_num );
  sparse_index = zeros ( dim_num, point_num );

  point_count = 0;
%
%  The outer loop generates values of LEVEL.
%
  level_min = max ( 0, level_max + 1 - dim_num );

  for level = level_min : level_max
%
%  The middle loop generates a GRID,
%  based on the next partition that adds up to LEVEL.
%
    level_1d = [];
    more_grids = 0;
    h = 0;
    t = 0;

    while ( 1 )

      [ level_1d, more_grids, h, t ] = comp_next ( level, dim_num, level_1d, ...
        more_grids, h, t );

      order_1d = level_to_order_default ( dim_num, level_1d, rule );
%
%  The inner loop generates a POINT of the GRID of the LEVEL.
%
      point_index = [];
      more_points = 0;

      while ( 1 )

        [ point_index, more_points ] = vec_colex_next3 ( dim_num, order_1d, point_index, ...
          more_points );

        if ( ~more_points )
          break
        end

        point_count = point_count + 1;
        point_unique = sparse_unique_index(point_count);
        sparse_order(1:dim_num,point_unique) = order_1d(1:dim_num);
        sparse_index(1:dim_num,point_unique) = point_index(1:dim_num);

      end

      if ( ~more_grids )
        break
      end

    end

  end

  return
end


function out = conv3fft(z1,z2)

z1 = single(z1);
z2 = single(z2);

siz1 = size(z1);
siz2 = size(z2);
siz = siz1+siz2-1;

z1x=size(z1,1);
z1y=size(z1,2);
z2x=size(z2,1);
z2y=size(z2,2);

out=real(ifftn(fftn(z1,siz).*fftn(z2,siz)));

p = ((siz2-1)+mod((siz2-1),2))/2;

out=out(p(1)+1:p(1)+siz1(1),p(2)+1:p(2)+siz1(2),p(3)+1:p(3)+siz1(3));


function transforms3d(varargin)
%TRANSFORMS3D  Conventions for manipulating 3D affine transforms.
%
%   By 'transform' we mean an affine transform. A 3D affine transform
%   is represented by a 4*4 matrix. The last row of the matrix is equal to
%   [0 0 0 1].
%
%
%
%   Example:
%   % create a translation by the vector [10 20 30]:
%   T = createTranslation3d([10 20 30]);
%   % Transform a basic point:
%   PT1 = [4 5 6];
%   PT2 = transformPoint3d(PT1, T)
%   % returns:
%   PT2 =
%       14   25   36
%
%   See also
%   createTranslation3d, createScaling3d, , createBasisTransform3d
%   createRotationOx, createRotationOy, createRotationOz
%   rotation3dAxisAndAngle, rotation3dToEulerAngles,
%   createRotation3dLineAngle, eulerAnglesToRotation3d
%   transformPoint3d, transformVector3d, transformLine3d, transformPlane3d
%   composeTransforms3d, recenterTransform3d
%

% ------
% Author: David Legland
% e-mail: david.legland@inra.fr
% Created: 2008-10-13,    using Matlab 7.4.0.287 (R2007a)
% Copyright 2008 INRA - BIA PV Nantes - MIAJ Jouy-en-Josas.


function [x,fval,exitflag,info,Opt] = opti_lsqcurvefit(fun,x0,xdata,ydata,lb,ub,opts)
%OPTI_LSQCURVEFIT Solve a NLS using an OPTI NLS Solver (Matlab Overload)
%
%   [x,fval,exitflag,info] = opti_lsqcurvefit(fun,x0,xdata,ydata,lb,ub)
%   solves the nonlinear least squares problem sum[(f(x,xdata)-ydata)^2]
%   where fun is the nonlinear function to be fitted [fun(x,xdata)],
%   starting at x0, to the sample data ydata. Optional bounds lb and ub can
%   be placed on the decision variables x.
%
%   [x,fval,exitflag,info] = opti_lsqcurvefit(fun,...,ub,opts) allows the
%   user to specify optiset options. This includes specifying a solver via
%   the 'solver' field of optiset.
%
%   [x,...,info,Opt] = opti_lsqcurvefit(fun,...) returns the internally
%   built OPTI object.

%   Copyright (C) 2011 Jonathan Currie (IPL)

% Handle missing arguments
if nargin < 7, opts = optiset; end
if nargin < 6, ub = []; end
if nargin < 5, lb = []; end
if nargin < 4, error('You must supply at least 4 arguments to opti_lsqcurvefit'); end

%Build OPTI Object
Opt = opti('fun',fun,'data',xdata,ydata,'bounds',lb,ub,'x0',x0,'options',opts);

%Solve
[x,fval,exitflag,info] = solve(Opt);


function res = lt(a,b)
%LT           Implements  a < b  elementwise for intervals a and b
%
%  if true,  a  is definitely less than  b
%

% written  10/16/98     S.M. Rump
% modified 11/30/98     S.M. Rump
% modified 04/04/04     S.M. Rump  set round to nearest for safety
% modified 04/06/05     S.M. Rump  rounding unchanged
%

  if ~isa(a,'intval')
    a = intval(a);
  end
  if ~isa(b,'intval')
    b = intval(b);
  end

  if a.complex | b.complex
    res = real(sup(a)) < real(inf(b)) & imag(sup(a)) < imag(inf(b)) ;
  else
    res = sup(a) < inf(b) ;
  end


function xPol=Cart2DState2PolarState(xCart,systemType)
%%CART2DSSTATE2POLARSTATE Transform a 2D Cartesian state into a state
%                         consisting of position, heading and speed as well
%                         as possibly a turn rate and a linear
%                         acceleration, depending on the choice of
%                         systemType.
%
%INPUTS: xCart A Cartesian state vector consisting of position velocity and
%              possibly acceleration into a state where heading and speed
%              have been separated. xCart has the form
%              [x;y;xdot;ydot;xddot;yddot], where the acceleration terms
%              xddot;yddot can be omitted if the system type is 'ConstVel'.
%   systemType A string constant specifying the desired type of output. In
%              all instances, the heading is measured in terms of radians
%              counterclockwise from the x-axis. Possible values are:
%              'ConstVel'     The target state is [position;heading;speed]
%                             and xCart is [position;velocity]
%              'ConstAccel'   The target state is [position;heading;speed;
%                             speed derivative] and xCart is
%                             [position;velocity;acceleration]
%              'ConstTurn'    The target state is [position;heading;speed;
%                             turn rate] and xCart is
%                             [position;velocity;acceleration]
%              'TurnAndAccel' The target state is [position;heading;speed;
%                             turnrate; speed derivative] and xCart is
%                             [position;velocity;acceleration]
%
%OUTPUTS: xPol The state converted from 2D Cartesian coordinates into the
%              selected 2D coordinate system.
%
%When the system type is 'ConstVel' or 'TurnAndAccel', only a single
%solution is mathematically observable. When the system type is
%'ConstAccel' or 'ConstTurn', the system is overdetermined, but only a
%simple solution is used, not a least squares solution.
%
%The use of 2D states where the heading and speed have been separated is
%discussed in [1] and [2].
%
%The opposite of this function is polar2DState2CartState.
%
%REFERENCES:
%[1] M. Busch and S. Blackman, "Evaluation of IMM filtering for an air
%    defense system application," in Proceedings of SPIE: Signal and Data
%    Processing of Small Targets, vol. 2561, 9 Jul. 1995, pp. 435-447.
%[1] J. L. Gertz, "Multisensor surveillance for improved aircraft
%    tracking," The Lincoln Laboratory Journal, vol. 2, no. 3, pp. 381-396,
%    1989.
%
%July 2014 David F. Crouse, Naval Research Laboratory, Washington D.C.
%%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

%Get position
x=xCart(1);
y=xCart(2);
%Get velocity
xDot=xCart(3);
yDot=xCart(4);

switch(systemType)
    case 'ConstVel' %Given position, heading, and speed.
        xPol=[x;
              y;
              atan2(yDot,xDot);
              sqrt(yDot^2+xDot^2)];
    case 'ConstAccel'%Given position, heading, speed, and linear
                     %acceleration
        %Get acceleration
        xDdot=xCart(5);
        yDdot=xCart(6);

        theta=atan2(yDot,xDot);%Heading
        %Determine the sign of the derivative velocity, ignoring the possible
        %effects of noise...
        vDot=sqrt(yDdot^2+xDdot^2);%Linear acceleration

        diff1=(vDot*cos(theta)-xDdot)^2+(vDot*sin(theta)-yDdot)^2;
        diff2=(-vDot*cos(theta)-xDdot)^2+(-vDot*sin(theta)-yDdot)^2;
        if(diff2<diff1)
            vDot=-vDot;
        end
        xPol=[x;
              y;
              theta;
              sqrt(yDot^2+xDot^2);
              vDot];
    case 'ConstTurn' %Given position, heading, speed, and turn rate.
        %Get acceleration
        xDdot=xCart(5);
        yDdot=xCart(6);

        %Turn rate
        omega=(xDot*yDdot-yDot*xDdot)/(xDot^2+yDot^2);

        if(~isfinite(omega))
            omega=0;
        end

        xPol=[x;
              y;
              atan2(yDot,xDot);
              sqrt(yDot^2+xDot^2);
              omega];
    case 'TurnAndAccel'%Given position, heading, speed, turn rate, and
                       %linear acceleration.
        %Get acceleration
        xDdot=xCart(5);
        yDdot=xCart(6);

        theta=atan2(yDot,xDot);%Heading
        v=sqrt(yDot^2+xDot^2);%Speed
        omega=(yDdot*cos(theta)-xDdot*sin(theta))/v;%Turn rate

        %Deal with slow speed targets.
        if(~isfinite(omega))
            omega=0;
        end

        %Linear acceleration
        vDot=xDdot*cos(theta)+yDdot*sin(theta);

        xPol=[x;
              y;
              theta;
              v;
              omega;
              vDot];
    otherwise
        error('Invalid system type given.')
end

end

%LICENSE:
%
%The source code is in the public domain and not licensed or under
%copyright. The information and software may be used freely by the public.
%As required by 17 U.S.C. 403, third parties producing copyrighted works
%consisting predominantly of the material produced by U.S. government
%agencies must provide notice with such work(s) identifying the U.S.
%Government material incorporated and stating that such material is not
%subject to copyright protection.
%
%Derived works shall not identify themselves in a manner that implies an
%endorsement by or an affiliation with the Naval Research Laboratory.
%
%RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE
%SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY THE NAVAL
%RESEARCH LABORATORY FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE ACTIONS
%OF RECIPIENT IN THE USE OF THE SOFTWARE.


%[2015]-"Multi-verse optimizer: A nature-inspired algorithm for global
%optimization"

% (9/12/2020)

function MVO = jMultiVerseOptimizer(feat,label,opts)
% Parameters
lb    = 0;
ub    = 1;
thres = 0.5;
p     = 6;      % control TDR
Wmax  = 1;      % maximum WEP
Wmin  = 0.2;    % minimum WEP
type  = 1;

if isfield(opts,'T'), max_Iter = opts.T; end
if isfield(opts,'N'), N = opts.N; end
if isfield(opts,'p'), p = opts.p; end
if isfield(opts,'Wmin'), Wmin = opts.Wmin; end
if isfield(opts,'Wmax'), Wmax = opts.Wmax; end
if isfield(opts,'ty'), type = opts.ty; end
if isfield(opts,'thres'), thres = opts.thres; end

% Objective function
fun = @jFitnessFunction;
% Number of dimensions
dim = size(feat,2);
% Initial
X   = zeros(N,dim);
for i = 1:N
  for d = 1:dim
    X(i,d) = lb + (ub - lb) * rand();
  end
end
% Pre
fit  = zeros(1,N);
fitG = inf;

curve = inf;
t = 1;
% Iterations
while t <= max_Iter
  % Calculate inflation rate
  for i = 1:N
    fit(i) = fun(feat,label,(X(i,:) > thres),opts);
    % Best universe
    if fit(i) < fitG
      fitG = fit(i);
      Xgb  = X(i,:);
    end
  end
  % Sort universe from best to worst
  [fitSU, idx] = sort(fit,'ascend');
  X_SU         = X(idx,:);
  % Elitism (first 1 is elite)
  X(1,:) = X_SU(1,:);
  % Either 1-norm or 2-norm
  if type == 1
    % Normalize inflation rate using 2-norm
    NI = fitSU ./ sqrt(sum(fitSU .^ 2));
  elseif type == 2
    % Normalize inflation rate using 1-norm
    NI = fitSU / sum(fitSU);
  end
  % Normalize inverse inflation rate using 1-norm
  inv_fitSU = 1 ./ (1 + fitSU);
  inv_NI    = inv_fitSU / sum(inv_fitSU);
  % Wormhole Existence probability (3.3), increases from 0.2 to 1
  WEP = Wmin + t * ((Wmax - Wmin) / max_Iter);
  % Travelling disrance rate (3.4), descreases from 0.6 to 0
  TDR = 1 - ((t ^ (1 / p)) / (max_Iter ^ (1 / p)));
  % Start with 2 since first is elite
  for i = 2:N
    % Define black hole
    idx_BH = i;
    for d = 1:dim
      % White/black hole tunnels & exchange object of universes (3.1)
      r1 = rand();
      if r1 < NI(i)
        % Random select k with roulette wheel
        idx_WH       = jRouletteWheelSelection(inv_NI);
        % Position update
        X(idx_BH, d) = X_SU(idx_WH, d);
      end
      % Local changes for universes (3.2)
      r2 = rand();
      if r2 < WEP
        r3 = rand();
        r4 = rand();
        if r3 < 0.5
          X(i,d) = Xgb(d) + TDR * ((ub - lb) * r4 + lb);
        else
          X(i,d) = Xgb(d) - TDR * ((ub - lb) * r4 + lb);
        end
      else
        X(i,d) = X(i,d);
      end
    end
    % Boundary
    XB = X(i,:); XB(XB > ub) = ub; XB(XB < lb) = lb;
    X(i,:) = XB;
  end
  curve(t) = fitG;
  fprintf('\nIteration %d Best (MVO)= %f',t,curve(t))
  t = t + 1;
end
% Select features
Pos   = 1:dim;
Sf    = Pos((Xgb > thres) == 1);
sFeat = feat(:,Sf);
% Store results
MVO.sf = Sf;
MVO.ff = sFeat;
MVO.nf = length(Sf);
MVO.c  = curve;
MVO.f  = feat;
MVO.l  = label;
end

%// Roulette Wheel Selection //
function Index = jRouletteWheelSelection(prob)
% Cummulative summation
C = cumsum(prob);
% Random one value, most probability value [0~1]
P = rand();
% Route wheel
for i = 1:length(C)
	if C(i) > P
    Index = i;
    break;
  end
end
end


% CORRECT_MC - compute an upper limit for the number of independent
%                time-frequency estimate in a given time-frequency image.
%                This number can be used to correct for multiple comparisons.
%
% Usage:
%   [ncorrect array] = correct_mc( EEG, cycles, maxfreq, timesout);
%
% Inputs:
%    EEG       - EEGLAB structure
%    cycles    - [float] same as the cycle input to TIMEF. Default is [3 0.5].
%    freqrange - [float] minimum and maximum frequency. Default is [2 50] Hz.
%    timesout  - [integer] array of number of time points to test.
%
% Output:
%    ncorrect - number of independent tf estimate in the time-freq image
%    array    - array of size (freqs x timesout) containing pvalues.
%
% Method details:
%
% Dividing by the total number of time-frequency estimate in the 2-D
% time-frequency image decomposition would be too conservative since
% spectral estimates of neighboring time-frequency points are highly
% correlated. One must thus estimate the number of independent
% time-frequency points in the TF image. Here, I used geometrical wavelets
% which are optimal in terms of image compression, so neighboring
% frequencies can be assume to carry independent spectral estimates.
% We thus had time-frequency decompositions at only X frequencies (e.g. 120,
% 60, 30, 15, 7.5, 3.25, 1.625 Hz). For each frequency, I then found
% the minimum number of time points for which there was a significant
% correlation of the spectral estimates between neighboring time points
% (for each frequency and number of time point, I computed the correlation
% from 0 to 1 for all data channel to obtain an a probability distribution
% of correlation; we then fitted this distribution using a 4th order curve
% (Ramberg, J. S., E. J. Dudewicz, et al. (1979). "A probability
% distribution and its uses in fitting data." Technometrics 21(2)) and
% assessed the probability of significance for the value 0 (no correlation)
% to be within the distribution of estimated correlation). For instance,
% using 28 time points at 120 Hz, there was no significant (p>0.05 taking
% into account Bonferoni correction for multiple comparisons) correlation
% between neighboring time-frequency power estimate, but there was a
% significant correlation using 32 time points instead of 28 (p<0.05).
% Applying the same approach for the X geometrical frequencies and summing
% the minimum number of time points for observing a significant correlation
% at all frequencies, ones obtain in general a number below 200 (with the
% defaults above and 3-second data epochs) independent estimates. In all
% the time-frequency plots, one has to used a significance mask at p<0.00025
% (0.05/200). An alternative method for correcting for multiple comparisons
% is presented in Nichols & Holmes, Human Brain Mapping, 2001.
%
% Author: Arnaud Delorme, SCCN, Jan 17, 2004

% Copyright (C) 2004 Arnaud Delorme, SCCN, arno@salk.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function [ncorrect, pval] = correct_mc( EEG, cycles, freqrange, timesout);

    if nargin < 1
        help correct_mc;
        return;
    end
    if nargin < 2
        cycles  = [3 0.5];
    end
    if nargin < 3
        freqrange = [2 50];
    end
    if nargin < 4
        % possible number of time outputs
        % -------------------------------
        timesout = [5 6 7 8 9 10 12 14 16 18 20 24 28 32 36 40];
    end
    nfreqs = ceil(log2(freqrange(2)));

    % scan times
    % ----------
    for ti = 1:length(timesout)
        clear tmpf

        % scan data channels
        % ------------------
        for index = 1:EEG.nbchan

            clf; [ersp,itc,powbase,times,freqs,erspboot,itcboot] = newtimef(EEG.data(index,:),EEG.pnts, ...
                             [EEG.xmin EEG.xmax]*1000,EEG.srate, cycles, 'timesout', timesout(ti), ...
                             'freqscale', 'log', 'nfreqs', nfreqs, 'freqrange', freqrange, 'plotitc', 'off', 'plotersp', 'off');

            % compute correlation
            % -------------------
            for fi = 1:length(freqs)
                tmp      = corrcoef(ersp(fi,1:end-1), ersp(fi,2:end));
                tmpf(index,fi) = tmp(2,1);
            end

        end

        % fit curve and determine if the result is significant
        % ----------------------------------------------------
        for fi = 1:length(freqs)
            pval(fi, ti) = rsfit(tmpf(:,fi)', 0);
            if pval(fi,ti) > 0.9999, pval(fi,ti) = NaN; end
        end
    end

    % find minimum number of points for each frequency
    % ------------------------------------------------
    ncorrect = 0;
    threshold = 0.05 / prod(size(pval));
    for fi = 1:size(pval,1)
        ti = 1;
        while ti <= size(pval,2)
            if pval(fi,ti) < threshold
                ncorrect = ncorrect +  timesout(ti);
                ti = size(pval,2)+1;
            end
            ti = ti+1;
        end
    end


function hydro = excitationIRF(hydro,tEnd,nDt,nDw,wMin,wMax)
% Calculates the normalized excitation impulse response function:
%
% 	:math:`\overline{K}_{e,i,\theta}(t) = {\frac{1}{2\pi}}\intop_{-\infty}^{\infty}{\frac{X_i(\omega,\theta)e^{i{\omega}t}}{{\rho}g}}d\omega`
%
% Default parameters can be used by inputting [].
% See ``WEC-Sim\examples\BEMIO`` for examples of usage.
%
% Parameters
% ----------
%     hydro : struct
%         Structure of hydro data
%
%     tEnd : float
%         Calculation range for the IRF, where the IRF is calculated from t
%         = 0 to tEnd, and the default is 100 s
%
%     nDt : float
%         Number of time steps in the IRF, the default is 1001
%
%     nDw : float
%         Number of frequency steps used in the IRF calculation
%         (hydrodynamic coefficients are interpolated to correspond), the
%         default is 1001
%
%     wMin : float
%         Minimum frequency to use in the IRF calculation, the default is
%         the minimum frequency from the BEM data
%
%     wMax : float
%         Maximum frequency to use in the IRF calculation, the default is
%         the maximum frequency from the BEM data
%
% Returns
% -------
%     hydro : struct
%         Structure of hydro data with excitation IRF
%

p = waitbar(0,'Calculating excitation IRFs...');  % Progress bar

% Set defaults if empty
if isempty(tEnd)==1;  tEnd = 100;           end
if isempty(nDt)==1;    nDt = 1001;            end
if isempty(nDw)==1;    nDw = 1001;            end
if isempty(wMin)==1;  wMin = min(hydro.w);  end
if isempty(wMax)==1;  wMax = max(hydro.w);  end

% Interpolate to the given t and w
t = linspace(-tEnd,tEnd,nDt);
w = linspace(wMin,wMax,nDw);
N = sum(hydro.dof)*hydro.Nh;

% Calculate the impulse response function for excitation
n = 0;
for i = 1:sum(hydro.dof)
    for j = 1:hydro.Nh
        ex_re = interp1(hydro.w,squeeze(hydro.ex_re(i,j,:)),w);
        ex_im = interp1(hydro.w,squeeze(hydro.ex_im(i,j,:)),w);
        hydro.ex_K(i,j,:) = (1/pi)*trapz(w,ex_re.*cos(w.*t(:))-ex_im.*sin(w.*t(:)),2);
        n = n+1;
    end
    waitbar(n/N)
end

hydro.ex_t = t;
hydro.ex_w = w;
close(p);

end


function [D, DGC] = plotConcVSdGft0GroupContUncertainty(modelT)
% Compares the difference between minimum & maximum concentration, on a
% logarithmic scale, and the group contribution uncertainty for each
% metabolite.
%
% USAGE:
%
%    [D, DGC] = plotConcVSdGft0GroupContUncertainty(modelT)
%
% INPUT:
%    modelT:    structure with fields:
%
%                 * modelT.concMax
%                 * modelT.concMin
%                 * modelT.dfGt0GroupContUncertainty
%
% OUTPUTS:
%    D:
%    DGC:

[nMet,nRxn]=size(modelT.mets);

RT=modelT.T*modelT.gasConstant;

D=zeros(nMet,1);
DGC=zeros(nMet,1);
q=0;
q2=0;
r=0;
for m=1:nMet
    d=(RT*log(modelT.concMax(m)/modelT.concMin(m)))/2;
    dgc=modelT.dfGt0GroupContUncertainty(m);
    if isempty(d) || isnan(dgc)
        D(m)=NaN;
        DGC(m)=NaN;
    else
        D(m)=d;
        DGC(m)=dgc;
        if dgc>(d/2)
            q=q+1;
        end
        if dgc>(d)
            q2=q2+1;
        end
        r=r+1;
    end
end

fraction=q/r;
fraction2q=q2/r

q2=0;
r2=0;
for m=1:nMet
    d=(RT*log(modelT.concMax(m)/modelT.concMin(m)))/2;
    dgc=modelT.dfGt0GroupContUncertainty(m);
    if strcmp(modelT.dfGt0Source(m),'Keq')
        dgc=NaN;
    end
    if ~(isempty(d) || isnan(dgc))
        if dgc>(d/2)
            q2=q2+1;
        end
        r2=r2+1;
    end
end

fraction2r=q2/r2;

fprintf('%s\n',['Fraction of metabolites where GC uncertainty is more significant: ' num2str(fraction)]);

d=(RT*log(20/0.2))/2;

% figure
% plot(D,DGC,'.')
% plot(DGC,'.')

figure1=figure;
axes1 = axes('Parent',figure1,'FontSize',14,'CLim',[1 2],'Layer','top');
hist(DGC,100)
h = findobj(gca,'Type','patch');
set(h,'FaceColor','r','EdgeColor','w')
line([d d],[0 300],'Color','b','LineWidth',4,'LineStyle','--')

text('Position',[d,175],'String','$$\longleftarrow\;5.9=\frac{1}{2}RT\ln\left(\frac{20}{0.2}\right)$$','Interpreter','latex','FontSize',18,'Color','b');

xlim([0, 100])
set(gca,'XTick',0:10:100,'TickDir','out')
ylabel('# Reactants','FontSize',14)
xlabel('Standard Error in {\Delta_{f}G_{est}^{0}} (kJ/mol)','FontSize',14)


function [xopt,fopt]=simann(func, x, LB, UB, sa_t, sa_rt, sa_nt, sa_ns,rseed)

% Simulated Annealing programmed for minimization problem
% INPUTS
% func, string variable containing name of function file to be optimized
% x, starting values
% LB, lower bound on optimization parameters
% UB, upper bound on optimization parameters
% sa_t, initial temperature
% sa_rt, temperature reduction factor, 0 < sa_rt < 1, try .85
% sa_nt, number of times through ns loop before temperature reduction (recommended value: 5)
% sa_ns, number of times through function before stepsize adjustment (recommended value: 20)
%
% OUTPUTS
% xopt, the optimal solution
%
%

LB=LB(:)';
UB=UB(:)';

rand('state',rseed);                      %sets seed for random number generator
sa_neps=4;                                %number of times eps
                                          %tolerance is achieved before termination
sa_eps=eps;                              %convergence criteria
sa_maxeval=60;%12000000;                      %maximum number of function evaluations

sa_nargs=length(LB);                      %number of parameters
sa_nobds=0;
sa_nacc=0;                                %number of acceptions
sa_nevals=0;                              %number of evaluations
sa_opteval=0;                             %optimum number of
                                          %function evaluations

fstar=Inf*ones(sa_neps,1);

%x=LB+(UB-LB).*rand(1, sa_nargs);         %starting values for model parameters
f=feval(func,x);                          %function evaluation with parameters x
%disp('initial loss function value:');disp(f);
sa_nevals=sa_nevals+1;
xopt=x;
fopt=f;
xtot=x;
fstar(1)=f;

VM=(UB-LB);%/2;                      %maximum step size

%LOOP
while 1

  nup=0;                                   %number of uphill movements
  nrej=0;                                  %number of rejections
  nnew=0;
  ndown=0;                                 %number of downhill movements
  lnobds=0;
  nacp=zeros(sa_nargs,1);
  C = progress('init','Determine initial hyperparameters for simplex...');
  for m=1:sa_nt
    for j=1:sa_ns
      for h=1:sa_nargs
        if sa_nevals>=sa_maxeval
          %disp('too many function evaluations')
          return
        end
        C = progress(C,sa_nevals/sa_maxeval);
        %workbar(sa_nevals/sa_maxeval,'Determine initial hyperparameters to build grid...','Progress')
        % generate xp, trial value of x
        xp=x;
        xp(h)=x(h)+VM(h)*(2*rand(1,1)-1.0);               %calculate new value for x (xp)
        if (xp(h)<LB(h)) | (xp(h)>UB(h))
          xp(h)=LB(h)+(UB(h)-LB(h))*rand(1,1);
          lnobds=lnobds+1;
          sa_nobds=sa_nobds+1;
        end
        % evaluate at xp and return as fp
        %disp ('current parameter vector:');disp(xp);
        fp=feval(func,xp);                                 %function evaluation with parameters xp
        %disp ('function value');disp(fp);
        sa_nevals=sa_nevals+1;

        % we minimize! accept if the function value decreases
        if fp<=f
          x=xp;
          f=fp;
          sa_nacc=sa_nacc+1;
          nacp(h)=nacp(h)+1;
          nup=nup+1;
          % if smaller than any previous point, record as new optimum
          if fp<fopt
            xopt=xp;
            fopt=fp;
            sa_opteval=sa_nevals;
            nnew=nnew+1;
          end
        else % function value increases
          p=exp((f-fp)/sa_t);                              %random number
          pp=rand(1,1);
          if pp<p
            x=xp;
            f=fp;
            sa_nacc=sa_nacc+1;
            nacp(h)=nacp(h)+1;
            ndown=ndown+1;
          else
            nrej=nrej+1;
          end
        end
      end
    end

    % adjust maximal step size vm
    c=ones(sa_nargs,1)*2;%??
    for i=1:sa_nargs
      ratio=nacp(i)/sa_ns;
      if ratio>0.6
        VM(i)=VM(i) * (1+c(i)*(ratio-0.6)/0.4);
      elseif ratio <0.4
        VM(i)=VM(i)/(1+c(i)*((0.4-ratio)/0.4));
      end
      if VM(i)>(UB(i)-LB(i))
        VM(i)=UB(i)-LB(i);
      end
    end

    % provide statistics about current state of optimization

%     disp('No. of evaluations');disp(sa_nevals);disp('  current temperature');disp(sa_t);
%     disp('current optimum function value');disp(fopt);
%     disp('No. of downhill steps');disp(nup);  % note misnomer in variable declaration!
%     disp('No. of accepted uphill steps');disp(ndown); % we minimize, thus downhill is always accepted!
%     disp('No. of rejections');disp(nrej);
%     disp('current parameter values');disp(xp);
%     disp('current optimum vector');disp(xopt);
%     disp('current step size');disp(VM);
    %disp('Variables used:');whos;

  for i=1:sa_nargs
     nacp(i) = 0;
  end
  end

  % check termination criteria
  fstar(1)=f;
  quit = ((fstar(1)-fopt) <= sa_eps);
  if any(abs(fstar-f)>sa_eps)
    quit=0;
  end

  if quit
    disp(['simulated annealing achieved termination after ', num2str(sa_nevals),' evals']);
    return
  end

  % reduce temperature
  sa_t=sa_t*sa_rt;
  fstar(2:4)=fstar(1:3);
  % continue from current optimum
  x=xopt;
  f=fopt;
end %while


function M = load_image(type, n, options)

% load_image - load benchmark images.
%
%   M = load_image(name, n, options);
%
%   name can be:
%   Synthetic images:
%       'chessboard1', 'chessboard', 'square', 'squareregular', 'disk', 'diskregular', 'quaterdisk', '3contours', 'line',
%       'line_vertical', 'line_horizontal', 'line_diagonal', 'line_circle',
%       'parabola', 'sin', 'phantom', 'circ_oscil',
%       'fnoise' (1/f^alpha noise).
%   Natural images:
%       'boat', 'lena', 'goldhill', 'mandrill', 'maurice', 'polygons_blurred', or your own.
%
%   Copyright (c) 2004 Gabriel Peyre

if nargin<2
    n = 512;
end
options.null = 0;

if iscell(type)
    for i=1:length(type)
        M{i} = load_image(type{i},n,options);
    end
    return;
end

type = lower(type);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% parameters for geometric objects
eta         = getoptions(options, 'eta', .1);
gamma       = getoptions(options, 'gamma', 1/sqrt(2));
radius      = getoptions(options, 'radius', 10);
center      = getoptions(options, 'center', [0 0]);
center1     = getoptions(options, 'center1', [0 0]);
w           = getoptions(options, 'tube_width', 0.06);
nb_points   = getoptions(options, 'nb_points', 9);
scaling     = getoptions(options, 'scaling', 1);
theta       = getoptions(options, 'theta', 30 * 2*pi/360);
eccentricity = getoptions(options, 'eccentricity', 1.3);
sigma = getoptions(options, 'sigma', 0);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% for the line, can be vertical / horizontal / diagonal / any
if strcmp(type, 'line_vertical')
    eta = 0.5;              % translation
    gamma = 0;      % slope
elseif strcmp(type, 'line_horizontal')
    eta = 0.5;              % translation
    gamma = Inf;      % slope
elseif strcmp(type, 'line_diagonal')
    eta = 0;              % translation
    gamma = 1;      % slope
end

if strcmp(type(1:min(12,end)), 'square-tube-')
    k = str2double(type(13:end));
    c1 = [.22 .5]; c2 = [1-c1(1) .5];
    eta = 1.5;
    r1 = [c1 c1] + .21*[-1 -eta 1 eta];
    r2 = [c2 c2] + .21*[-1 -eta 1 eta];
    M = double( draw_rectangle(r1,n) | draw_rectangle(r2,n) );
    if mod(k,2)==0
        sel = n/2-k/2+1:n/2+k/2;
    else
        sel = n/2-(k-1)/2:n/2+(k-1)/2;
    end
    M( round(.25*n:.75*n), sel ) = 1;
    return;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
switch lower(type)

    case 'constant'
        M = ones(n);

    case 'ramp'
        x = linspace(0,1,n);
        [Y,M] = meshgrid(x,x);

    case 'bump'

        s = getoptions(options, 'bump_size', .5);
        c = getoptions(options, 'center', [0 0]);
        if length(s)==1
            s = [s s];
        end
        x = linspace(-1,1,n);
        [Y,X] = meshgrid(x,x);
        X = (X-c(1))/s(1); Y = (Y-c(2))/s(2);
        M = exp( -(X.^2+Y.^2)/2 );

    case 'periodic'
        x = linspace(-pi,pi,n)/1.1;
        [Y,X] = meshgrid(x,x);
        f = getoptions(options, 'freq', 6);
        M = (1+cos(f*X)).*(1+cos(f*Y));

    case {'letter-x' 'letter-v' 'letter-z' 'letter-y'}
        M = create_letter(type(8), radius, n);

    case 'l'
        r1 = [.1 .1  .3 .9];
        r2 = [.1 .1 .9 .4];
        M = double( draw_rectangle(r1,n) | draw_rectangle(r2,n) );

    case 'ellipse'
        c1 = [0.15 0.5];
        c2 = [0.85 0.5];
        x = linspace(0,1,n);
        [Y,X] = meshgrid(x,x);
        d = sqrt((X-c1(1)).^2 + (Y-c1(2)).^2) + sqrt((X-c2(1)).^2 + (Y-c2(2)).^2);
        M = double( d<=eccentricity*sqrt( sum((c1-c2).^2) ) );
    case 'ellipse-thin'
        options.eccentricity = 1.06;
        M = load_image('ellipse', n, options);
    case 'ellipse-fat'
        options.eccentricity = 1.3;
        M = load_image('ellipse', n, options);

    case 'square-tube'
        c1 = [.25 .5];
        c2 = [.75 .5];
        r1 = [c1 c1] + .18*[-1 -1 1 1];
        r2 = [c2 c2] + .18*[-1 -1 1 1];
        r3 = [c1(1)-w c1(2)-w c2(1)+w c2(2)+w];
        M = double( draw_rectangle(r1,n) | draw_rectangle(r2,n) | draw_rectangle(r3,n) );
    case 'square-tube-1'
        options.tube_width = 0.03;
        M = load_image('square-tube', n, options);
    case 'square-tube-2'
        options.tube_width = 0.06;
        M = load_image('square-tube', n, options);
    case 'square-tube-3'
        options.im = 0.09;
        M = load_image('square-tube', n, options);
    case 'polygon'
        theta = sort( rand(nb_points,1)*2*pi );
        radius = scaling*rescale(rand(nb_points,1), 0.1, 0.93);
        points = [cos(theta) sin(theta)] .* repmat(radius, 1,2);
        points = (points+1)/2*(n-1)+1; points(end+1,:) = points(1,:);
        M = draw_polygons(zeros(n),0.8,{points'});
        [x,y] = ind2sub(size(M),find(M));
        p = 100; m = length(x);
        lambda = linspace(0,1,p);
        X = n/2 + repmat(x-n/2, [1 p]) .* repmat(lambda, [m 1]);
        Y = n/2 + repmat(y-n/2, [1 p]) .* repmat(lambda, [m 1]);
        I = round(X) + (round(Y)-1)*n;
        M = zeros(n); M(I) = 1;
    case 'polygon-8'
        options.nb_points = 8;
        M = load_image('polygon', n, options);
    case 'polygon-10'
        options.nb_points = 8;
        M = load_image('polygon', n, options);
    case 'polygon-12'
        options.nb_points = 8;
        M = load_image('polygon', n, options);
    case 'pacman'
        options.radius = 0.45;
        options.center = [.5 .5];
        M = load_image('disk', n, options);
        x = linspace(-1,1,n);
        [Y,X] = meshgrid(x,x);
        T =atan2(Y,X);
        M = M .* (1-(abs(T-pi/2)<theta/2));
    case 'square-hole'
        options.radius = 0.45;
        M = load_image('disk', n, options);
        options.scaling = 0.5;
        M = M - load_image('polygon-10', n, options);

    case 'grid-circles'
        if isempty(n)
            n = 256;
        end
        f = getoptions(options, 'frequency', 30);
        eta = getoptions(options, 'width', .3);
        x = linspace(-n/2,n/2,n) - round(n*0.03);
        y = linspace(0,n,n);
        [Y,X] = meshgrid(y,x);
        R = sqrt(X.^2+Y.^2);
        theta = 0.05*pi/2;
        X1 = cos(theta)*X+sin(theta)*Y;
        Y1 = -sin(theta)*X+cos(theta)*Y;
        A1 = abs(cos(2*pi*R/f))<eta;
        A2 = max( abs(cos(2*pi*X1/f))<eta, abs(cos(2*pi*Y1/f))<eta );

        M = A1;
        M(X1>0) = A2(X1>0);

    case 'chessboard1'
        x = -1:2/(n-1):1;
        [Y,X] = meshgrid(x,x);
        M = (2*(Y>=0)-1).*(2*(X>=0)-1);

    case 'chessboard'
        width = getoptions(options, 'width', round(n/16) );
        [Y,X] = meshgrid(0:n-1,0:n-1);
        M = mod( floor(X/width)+floor(Y/width), 2 ) == 0;

    case 'square'
        if ~isfield( options, 'radius' )
            radius = 0.6;
        end
        x = linspace(-1,1,n);
        [Y,X] = meshgrid(x,x);
        M = max( abs(X),abs(Y) )<radius;

    case 'squareregular'
        M = rescale(load_image('square',n,options));
        if not(isfield(options, 'alpha'))
            options.alpha = 3;
        end
        S = load_image('fnoise',n,options);
        M = M + rescale(S,-0.3,0.3);

    case 'regular1'
        options.alpha = 1;
        M = load_image('fnoise',n,options);
    case 'regular2'
        options.alpha = 2;
        M = load_image('fnoise',n,options);
    case 'regular3'
        options.alpha = 3;
        M = load_image('fnoise',n,options);

    case 'sparsecurves'
        options.alpha = 3;
        M = load_image('fnoise',n,options);
        M = rescale(M);
        ncurves = 3;
        M = cos(2*pi*ncurves);

    case 'geometrical'

        J = getoptions(options, 'Jgeometrical', 4);
        sgeom = 100*n/256;
        options.bound = 'per';
        A = ones(n);
        for j=0:J-1
            B = A;
            for k=1:2^j
                I = find(B==k);
                U = perform_blurring(randn(n),sgeom,options);
                s = median(U(I));
                I1 = find( (B==k) & (U>s) );
                I2 = find( (B==k) & (U<=s) );
                A(I1) = 2*k-1;
                A(I2) = 2*k;
            end
        end
        M = A;

    case 'lic-texture'

        disp('Computing random tensor field.');
        options.sigma_tensor = getoptions(options, 'lic_regularity', 50*n/256);
        T = compute_tensor_field_random(n,options);
        Flow = perform_tensor_decomp(T); % extract eigenfield.
        options.isoriented = 0; % no orientation in streamlines
        % initial texture
        lic_width = getoptions(options, 'lic_width', 0);
        M0 = perform_blurring(randn(n),lic_width);
        M0 = perform_histogram_equalization( M0, 'linear');
        options.histogram = 'linear';
        options.dt = 0.4;
        options.M0 = M0;
        options.verb = 1;
        options.flow_correction = 1;
        options.niter_lic = 3;
        w = 30;
        M = perform_lic(Flow, w, options);

    case 'square_texture'
        M = load_image('square',n);
        M = rescale(M);
        % make a texture patch
        x = linspace(0,1,n);
        [Y,X] = meshgrid(x,x);
        theta = pi/3;
        x = cos(theta)*X + sin(theta)*Y;
        c = [0.3,0.4]; r = 0.2;
        I = find( (X-c(1)).^2 + (Y-c(2)).^2 < r^2 );
        eta = 3/n; lambda = 0.3;
        M(I) = M(I) + lambda * sin( x(I) * 2*pi / eta );

    case 'tv-image'
        M = rand(n);
        tau = compute_total_variation(M);
        options.niter = 400;
        [M,err_tv,err_l2] = perform_tv_projection(M,tau/1000,options);
        M = perform_histogram_equalization(M,'linear');

    case 'oscillatory_texture'
        x = linspace(0,1,n);
        [Y,X] = meshgrid(x,x);
        theta = pi/3;
        x = cos(theta)*X + sin(theta)*Y;
        c = [0.3,0.4]; r = 0.2;
        I = find( (X-c(1)).^2 + (Y-c(2)).^2 < r^2 );
        eta = 3/n; lambda = 0.3;
        M = sin( x * 2*pi / eta );

    case {'line', 'line_vertical', 'line_horizontal', 'line_diagonal'}
        x = 0:1/(n-1):1;
        [Y,X] = meshgrid(x,x);
        if gamma~=Inf
            M = (X-eta) - gamma*Y < 0;
        else
            M = (Y-eta) < 0;
        end

    case 'line-windowed'
        x = 0:1/(n-1):1;
        [Y,X] = meshgrid(x,x);
        eta = .3;
        gamma = getoptions(options, 'gamma', pi/10);
        parabola = getoptions(options, 'parabola', 0);
        M = (X-eta) - gamma*Y - parabola*Y.^2 < 0;
        f = sin( pi*x ).^2;
        M = M .* ( f'*f );

    case 'grating'
        x = linspace(-1,1,n);
        [Y,X] = meshgrid(x,x);
        theta = getoptions(options, 'theta', .2);
        freq = getoptions(options, 'freq', .2);
        X = cos(theta)*X + sin(theta)*Y;
        M = sin(2*pi*X/freq);

    case 'disk'
        if ~isfield( options, 'radius' )
            radius = 0.35;
        end
        if ~isfield( options, 'center' )
            center = [0.5, 0.5];    % center of the circle
        end
        x = 0:1/(n-1):1;
        [Y,X] = meshgrid(x,x);
        M = (X-center(1)).^2 + (Y-center(2)).^2 < radius^2;

    case 'diskregular'
        M = rescale(load_image('disk',n,options));
        if not(isfield(options, 'alpha'))
            options.alpha = 3;
        end
        S = load_image('fnoise',n,options);
        M = M + rescale(S,-0.3,0.3);

    case 'quarterdisk'
        if ~isfield( options, 'radius' )
            radius = 0.95;
        end
        if ~isfield( options, 'center' )
            center = -[0.1, 0.1];    % center of the circle
        end
        x = 0:1/(n-1):1;
        [Y,X] = meshgrid(x,x);
        M = (X-center(1)).^2 + (Y-center(2)).^2 < radius^2;

    case 'fading_contour'
        if ~isfield( options, 'radius' )
            radius = 0.95;
        end
        if ~isfield( options, 'center' )
            center = -[0.1, 0.1];    % center of the circle
        end
        x = 0:1/(n-1):1;
        [Y,X] = meshgrid(x,x);
        M = (X-center(1)).^2 + (Y-center(2)).^2 < radius^2;
        theta = 2/pi*atan2(Y,X);
        h = 0.5;
        M = exp(-(1-theta).^2/h^2).*M;

    case '3contours'
        radius = 1.3;
        center = [-1, 1];
        radius1 = 0.8;
        center1 = [0, 0];
        x = 0:1/(n-1):1;
        [Y,X] = meshgrid(x,x);
        f1 = (X-center(1)).^2 + (Y-center(2)).^2 < radius^2;
        f2 = (X-center1(1)).^2 + (Y-center1(2)).^2 < radius1^2;
        M = f1 + 0.5*f2.*(1-f1);

    case 'line_circle'

        gamma = 1/sqrt(2);

        x = linspace(-1,1,n);
        [Y,X] = meshgrid(x,x);
        M1 = double( X>gamma*Y+0.25 );
        M2 = X.^2 + Y.^2 < 0.6^2;
        M = 20 + max(0.5*M1,M2) * 216;

    case 'fnoise'

        % generate an image M whose Fourier spectrum amplitude is
        %   |M^(omega)| = 1/f^{omega}
        alpha = getoptions(options, 'alpha', 1);
        M = gen_noisy_image(n,alpha);

    case 'gaussiannoise'
        % generate an image of filtered noise with gaussian
        sigma = getoptions(options, 'sigma', 10);
        M = randn(n);
        m = 51;
        h = compute_gaussian_filter([m m],sigma/(4*n),[n n]);
        M = perform_convolution(M,h);
        return;

    case {'bwhorizontal','bwvertical','bwcircle'}

        [Y,X] = meshgrid(0:n-1,0:n-1);
        if strcmp(type, 'bwhorizontal')
            d = X;
        elseif strcmp(type, 'bwvertical')
            d = Y;
        elseif strcmp(type, 'bwcircle')
            d = sqrt( (X-(n-1)/2).^2 + (Y-(n-1)/2).^2 );
        end
        if isfield(options, 'stripe_width')
            stripe_width = options.stripe_width;
        else
            stripe_width = 5;
        end
        if isfield(options, 'black_prop')
            black_prop = options.black_prop;
        else
            black_prop = 0.5;
        end
        M = double( mod( d/(2*stripe_width),1 )>=black_prop );

    case 'parabola'

        % curvature
        c = getoptions(c, 'c', .1);
        % angle
        theta = getoptions(options, 'theta',  pi/sqrt(2));
        x = -0.5:1/(n-1):0.5;
        [Y,X] = meshgrid(x,x);
        Xs = X*cos(theta) + Y*sin(theta);
        Y =-X*sin(theta) + Y*cos(theta); X = Xs;
        M = Y>c*X.^2;

    case 'sin'

        [Y,X] = meshgrid(-1:2/(n-1):1, -1:2/(n-1):1);
        M = Y >= 0.6*cos(pi*X);
        M = double(M);

    case 'circ_oscil'

        x = linspace(-1,1,n);
        [Y,X] = meshgrid(x,x);
        R = sqrt(X.^2+Y.^2);
        M = cos(R.^3*50);

    case 'phantom'

        M = phantom(n);

    case 'periodic_bumps'
        nbr_periods = getoptions(options, 'nbr_periods', 8);
        theta = getoptions(options, 'theta', 1/sqrt(2));
        skew = getoptions(options, 'skew', 1/sqrt(2) );
        A = [cos(theta), -sin(theta); sin(theta), cos(theta)];
        B = [1 skew; 0 1];
        T = B*A;
        x = (0:n-1)*2*pi*nbr_periods/(n-1);
        [Y,X] = meshgrid(x,x);
        pos = [X(:)'; Y(:)'];
        pos = T*pos;
        X = reshape(pos(1,:), n,n);
        Y = reshape(pos(2,:), n,n);
        M = cos(X).*sin(Y);

    case 'noise'
        sigma = getoptions(options, 'sigma', 1);
        M = randn(n) * sigma;

    case 'disk-corner'
        x = linspace(0,1,n);
        [Y,X] = meshgrid(x,x);
        rho = .3; eta = .1;
        M1 = rho*X+eta<Y;
        c = [0 .2]; r = .85;
        d = (X-c(1)).^2 + (Y-c(2)).^2;
        M2 = d<r^2;
        M = M1.*M2;

    otherwise
        ext = {'gif', 'png', 'jpg', 'bmp', 'tiff', 'tif', 'pgm', 'ppm'};
        for i=1:length(ext)
            name = [type '.' ext{i}];
            if( exist(name) )
                M = imread( name );
                M = double(M);
                if not(isempty(n)) && (n~=size(M, 1) || n~=size(M, 2)) && nargin>=2
                    M = image_resize(M,n,n);
                end
                if strcmp(type, 'peppers-bw')
                    M(:,1) = M(:,2);
                    M(1,:) = M(2,:);
                end
                if strcmp(type, 'cameraman')
                    M(1:4,:) = M(8:-1:5,:);
                end
                if sigma>0
                    M = perform_blurring(M,sigma);
                end
                return;
            end
        end
        error( ['Image ' type ' does not exists.'] );
end

M = double(M);

if sigma>0
    M = perform_blurring(M,sigma);
end

M = rescale(M);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function M = create_letter(a, r, n)

c = 0.2;
p1 = [c;c];
p2 = [c; 1-c];
p3 = [1-c; 1-c];
p4 = [1-c; c];
p4 = [1-c; c];
pc = [0.5;0.5];
pu = [0.5; c];

switch a
    case 'x'
        point_list = { [p1 p3] [p2 p4] };
    case 'z'
        point_list = { [p2 p3 p1 p4] };
    case 'v'
        point_list = { [p2 pu p3] };
    case 'y'
        point_list = { [p2 pc pu] [pc p3] };

end
% fit image
for i=1:length(point_list)
    a = point_list{i}(2:-1:1,:);
    a(1,:) = 1-a(1,:);
    point_list{i} = round( a*(n-1)+1 );
end
M = draw_polygons(zeros(n),r,point_list);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function sk = draw_polygons(mask,r,point_list)

sk = mask*0;
for i=1:length(point_list)
    pl = point_list{i};
    for k=2:length(pl)
        sk = draw_line(sk,pl(1,k-1),pl(2,k-1),pl(1,k),pl(2,k),r);
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function sk = draw_line(sk,x1,y1,x2,y2,r)

n = size(sk,1);
[Y,X] = meshgrid(1:n,1:n);
q = 100;
t = linspace(0,1,q);
x = x1*t+x2*(1-t); y = y1*t+y2*(1-t);
if r==0
    x = round( x ); y = round( y );
    sk( x+(y-1)*n ) = 1;
else
    for k=1:q
        I = find((X-x(k)).^2 + (Y-y(k)).^2 <= r^2 );
        sk(I) = 1;
    end
end

function M = gen_noisy_image(n,alpha)

% gen_noisy_image - generate a noisy cloud-like image.
%
%   M = gen_noisy_image(n,alpha);
%
% generate an image M whose Fourier spectrum amplitude is
%   |M^(omega)| = 1/f^{omega}
%
%   Copyright (c) 2004 Gabriel Peyr?

if nargin<1
    n = 128;
end
if nargin<2
    alpha = 1.5;
end

if mod(n(1),2)==0
    x = -n/2:n/2-1;
else
    x = -(n-1)/2:(n-1)/2;
end

[Y,X] = meshgrid(x,x);
d = sqrt(X.^2 + Y.^2) + 0.1;
f = rand(n)*2*pi;

M = (d.^(-alpha)) .* exp(f*1i);
% M = real(ifft2(fftshift(M)));

M = ifftshift(M);
M = real( ifft2(M) );

function y = gen_signal_2d(n,alpha)

% gen_signal_2d -  generate a 2D C^\alpha signal of length n x n.
%   gen_signal_2d(n,alpha) generate a 2D signal C^alpha.
%
%   The signal is scale in [0,1].
%
%   Copyright (c) 2003 Gabriel Peyr?

% new new method

[Y,X] = meshgrid(0:n-1, 0:n-1);

A = X+Y+1;
B = X-Y+n+1;

a = gen_signal(2*n+1, alpha);
b = gen_signal(2*n+1, alpha);
y = a(A).*b(B);
% M = a(1:n)*b(1:n)';

return;

% new method
h = (-n/2+1):(n/2); h(n/2)=1;
[X,Y] = meshgrid(h,h);
h = sqrt(X.^2+Y.^2+1).^(-alpha-1/2);
h = h .* exp( 2i*pi*rand(n,n) );
h = fftshift(h);
y = real( ifft2(h) );

m1 = min(min(y));
m2 = max(max(y));
y = (y-m1)/(m2-m1);

return;

%% old code

y = rand(n,n);
y = y - mean(mean(y));
for i=1:alpha
    y = cumsum(cumsum(y)')';
    y = y - mean(mean(y));
end
m1 = min(min(y));
m2 = max(max(y));
y = (y-m1)/(m2-m1);

function newimg = image_resize(img,p1,q1,r1)

% image_resize - resize an image using bicubic interpolation
%
%   newimg = image_resize(img,nx,ny,nz);
% or
%   newimg = image_resize(img,newsize);
%
%   Works for 2D, 2D 2 or 3 channels, 3D images.
%
%   Copyright (c) 2004 Gabriel Peyr?

if nargin==2
    % size specified as an array
    q1 = p1(2);
    if length(p1)>2
        r1 = p1(3);
    else
        r1 = size(img,3);
    end
    p1 = p1(1);
end

if nargin<4
    r1 = size(img,3);
end

if ndims(img)<2 || ndims(img)>3
    error('Works only for grayscale or color images');
end

if ndims(img)==3 && size(img,3)<4
    % RVB image
    newimg = zeros(p1,q1, size(img,3));
    for m=1:size(img,3)
        newimg(:,:,m) = image_resize(img(:,:,m), p1, q1);
    end
    return;
elseif ndims(img)==3
    p = size(img,1);
    q = size(img,2);
    r = size(img,3);
    [Y,X,Z] = meshgrid( (0:q-1)/(q-1), (0:p-1)/(p-1), (0:r-1)/(r-1)  );
    [YI,XI,ZI] = meshgrid( (0:q1-1)/(q1-1), (0:p1-1)/(p1-1), (0:r1-1)/(r1-1) );
    newimg = interp3( Y,X,Z, img, YI,XI,ZI ,'cubic');
    return;
end

p = size(img,1);
q = size(img,2);
[Y,X] = meshgrid( (0:q-1)/(q-1), (0:p-1)/(p-1) );
[YI,XI] = meshgrid( (0:q1-1)/(q1-1), (0:p1-1)/(p1-1) );
newimg = interp2( Y,X, img, YI,XI ,'cubic');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function M = draw_rectangle(r,n)

x = linspace(0,1,n);
[Y,X] = meshgrid(x,x);
M = double( (X>=r(1)) & (X<=r(3)) & (Y>=r(2)) & (Y<=r(4)) ) ;


function y = randsample(n,k,j)
%function y = randsample(n,k)
%
%sample without replacement k integers from 1:n
if nargin<2, k = n; end
if nargin<3, j = 1; end
if numel(n) == 1
    n = 1:n;
end
[ig idx] = sort(rand(numel(n),j));
y = n(idx(1:k,:));
end


function [x, options, flog, pointlog, scalelog] = scg(f, x, options, gradf, varargin)
%SCG	Scaled conjugate gradient optimization.
%
%	Description
%	[X, OPTIONS] = SCG(F, X, OPTIONS, GRADF) uses a scaled conjugate
%	gradients algorithm to find a local minimum of the function F(X)
%	whose gradient is given by GRADF(X).  Here X is a row vector and F
%	returns a scalar value. The point at which F has a local minimum is
%	returned as X.  The function value at that point is returned in
%	OPTIONS(8).
%
%	[X, OPTIONS, FLOG, POINTLOG, SCALELOG] = SCG(F, X, OPTIONS, GRADF)
%	also returns (optionally) a log of the function values after each
%	cycle in FLOG, a log of the points visited in POINTLOG, and a log of
%	the scale values in the algorithm in SCALELOG.
%
%	SCG(F, X, OPTIONS, GRADF, P1, P2, ...) allows additional arguments to
%	be passed to F() and GRADF().     The optional parameters have the
%	following interpretations.
%
%	OPTIONS(1) is set to 1 to display error values; also logs error
%	values in the return argument ERRLOG, and the points visited in the
%	return argument POINTSLOG.  If OPTIONS(1) is set to 0, then only
%	warning messages are displayed.  If OPTIONS(1) is -1, then nothing is
%	displayed.
%
%	OPTIONS(2) is a measure of the absolute precision required for the
%	value of X at the solution.  If the absolute difference between the
%	values of X between two successive steps is less than OPTIONS(2),
%	then this condition is satisfied.
%
%	OPTIONS(3) is a measure of the precision required of the objective
%	function at the solution.  If the absolute difference between the
%	objective function values between two successive steps is less than
%	OPTIONS(3), then this condition is satisfied. Both this and the
%	previous condition must be satisfied for termination.
%
%	OPTIONS(9) is set to 1 to check the user defined gradient function.
%
%	OPTIONS(10) returns the total number of function evaluations
%	(including those in any line searches).
%
%	OPTIONS(11) returns the total number of gradient evaluations.
%
%	OPTIONS(14) is the maximum number of iterations; default 100.
%
%	See also
%	CONJGRAD, QUASINEW
%

%	Copyright (c) Ian T Nabney (1996-2001)

%  Set up the options.
if length(options) < 18
  error('Options vector too short')
end

if(options(14))
  niters = options(14);
else
  niters = 100;
end

display = options(1);
gradcheck = options(9);

% Set up strings for evaluating function and gradient
f = fcnchk(f, length(varargin));
gradf = fcnchk(gradf, length(varargin));

nparams = length(x);

%  Check gradients
if (gradcheck)
  feval('gradchek', x, f, gradf, varargin{:});
end

sigma0 = 1.0e-4;
fold = feval(f, x, varargin{:});	% Initial function value.
fnow = fold;
options(10) = options(10) + 1;		% Increment function evaluation counter.
gradnew = feval(gradf, x, varargin{:});	% Initial gradient.
gradold = gradnew;
options(11) = options(11) + 1;		% Increment gradient evaluation counter.
d = -gradnew;				% Initial search direction.
success = 1;				% Force calculation of directional derivs.
nsuccess = 0;				% nsuccess counts number of successes.
beta = 1.0;				% Initial scale parameter.
betamin = 1.0e-15; 			% Lower bound on scale.
betamax = 1.0e100;			% Upper bound on scale.
j = 1;					% j counts number of iterations.
if nargout >= 3
  flog(j, :) = fold;
  if nargout == 4
    pointlog(j, :) = x;
  end
end

% Main optimization loop.
while (j <= niters)

  % Calculate first and second directional derivatives.
  if (success == 1)
    mu = d*gradnew';
    if (mu >= 0)
      d = - gradnew;
      mu = d*gradnew';
    end
    kappa = d*d';
    if kappa < eps
      options(8) = fnow;
      return
    end
    sigma = sigma0/sqrt(kappa);
    xplus = x + sigma*d;
    gplus = feval(gradf, xplus, varargin{:});
    options(11) = options(11) + 1;
    theta = (d*(gplus' - gradnew'))/sigma;
  end

  % Increase effective curvature and evaluate step size alpha.
  delta = theta + beta*kappa;
  if (delta <= 0)
    delta = beta*kappa;
    beta = beta - theta/kappa;
  end
  alpha = - mu/delta;

  % Calculate the comparison ratio.
  xnew = x + alpha*d;
  fnew = feval(f, xnew, varargin{:});
  options(10) = options(10) + 1;
  Delta = 2*(fnew - fold)/(alpha*mu);
  if (Delta  >= 0)
    success = 1;
    nsuccess = nsuccess + 1;
    x = xnew;
    fnow = fnew;
  else
    success = 0;
    fnow = fold;
  end

  if nargout >= 3
    % Store relevant variables
    flog(j) = fnow;		% Current function value
    if nargout >= 4
      pointlog(j,:) = x;	% Current position
      if nargout >= 5
	scalelog(j) = beta;	% Current scale parameter
      end
    end
  end
  if display > 0
    fprintf(1, 'Cycle %4d  Error %11.6f  Scale %e\n', j, fnow, beta);
  end

  if (success == 1)
    % Test for termination

    if (max(abs(alpha*d)) < options(2) & max(abs(fnew-fold)) < options(3))
      options(8) = fnew;
      return;

    else
      % Update variables for new position
      fold = fnew;
      gradold = gradnew;
      gradnew = feval(gradf, x, varargin{:});
      options(11) = options(11) + 1;
      % If the gradient is zero then we are done.
      if (gradnew*gradnew' == 0)
	options(8) = fnew;
	return;
      end
    end
  end

  % Adjust beta according to comparison ratio.
  if (Delta < 0.25)
    beta = min(4.0*beta, betamax);
  end
  if (Delta > 0.75)
    beta = max(0.5*beta, betamin);
  end

  % Update search direction using Polak-Ribiere formula, or re-start
  % in direction of negative gradient after nparams steps.
  if (nsuccess == nparams)
    d = -gradnew;
    nsuccess = 0;
  else
    if (success == 1)
      gamma = (gradold - gradnew)*gradnew'/(mu);
      d = gamma*d - gradnew;
    end
  end
  j = j + 1;
end

% If we get here, then we haven't terminated in the given number of
% iterations.

options(8) = fold;
if (options(1) >= 0)
  disp(maxitmess);
end


function visualizeBoundary(X, y, model, varargin)
%VISUALIZEBOUNDARY plots a non-linear decision boundary learned by the SVM
%   VISUALIZEBOUNDARYLINEAR(X, y, model) plots a non-linear decision
%   boundary learned by the SVM and overlays the data on it

% Plot the training data on top of the boundary
plotData(X, y)

% Make classification predictions over a grid of values
x1plot = linspace(min(X(:,1)), max(X(:,1)), 100)';
x2plot = linspace(min(X(:,2)), max(X(:,2)), 100)';
[X1, X2] = meshgrid(x1plot, x2plot);
vals = zeros(size(X1));
for i = 1:size(X1, 2)
   this_X = [X1(:, i), X2(:, i)];
   vals(:, i) = svmPredict(model, this_X);
end

% Plot the SVM boundary
hold on
contour(X1, X2, vals, [0 0], 'Color', 'b');
hold off;

end


function newSteps = dtiWarpStep(origSteps,param)
% Warp (shift and scale) the steps into a new coord system
%
%    newSteps = dtiWarpStep(origSteps,param)
%
%    Shifts and scales according to: f(x,p) = ( x+p(2) ) * p(1)
%
%    origSteps - nx1 vector
%    param     - 2x1 vector [scale shift]
%
%    newSteps  - nx1 vector
%
% Example:
%    % original x's
%    x = 1:10;
%    % stretch by 2 times after shifting 5 units to the right
%    nx = dtiWarpStep(x,[2 5]);
%
% History:
%    2007/01/17 shc wrote it.
%

if ieNotDefined('origSteps'), error('Require input data!');         end
if ieNotDefined('param'),     error('Require warping parameters!'); end

newSteps = (origSteps+param(2))*param(1);

return