%% Demo: DISTATIS
%
% The data used here is available from http://cosmomvpa.org/datadb.zip
%
% It is based on the following work:
% * Connolly et al (2012), Representation of biological classes in the human
%   brain. Journal of Neuroscience, doi 10.1523/JNEUROSCI.5547-11.2012
%
% Six categories (monkey, lemur, mallard, warbler, ladybug, lunamoth)
% during ten runs in an fMRI study.
%
% This example shows the application of DISTATIS, which tries to find an
% optimal 'compromise' dissimilarity matrix across a set of observations
% (participants)
%
% Reference:
%   - Abdi, H., Valentin, D., O?Toole, A. J., & Edelman, B. (2005).
%     DISTATIS: The analysis of multiple distance matrices. In
%     Proceedings of the IEEE Computer Society: International conference
%     on computer vision and pattern recognition, San Diego, CA, USA
%     (pp. 42?47).
%
% #   For CoSMoMVPA's copyright information and license terms,   #
% #   see the COPYING file distributed with CoSMoMVPA.           #

%% Set data paths
% The function cosmo_config() returns a struct containing paths to tutorial
% data. (Alternatively the paths can be set manually without using
% cosmo_config.)
config=cosmo_config();
study_path=fullfile(config.tutorial_data_path,'ak6');
output_path=config.output_data_path;

readme_fn=fullfile(study_path,'README');
cosmo_type(readme_fn);

% reset citation list
cosmo_check_external('-tic');

%% Preprocessing for DISTATIS: RSM analysis
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
subject_ids={'s01','s02','s03','s04','s05','s06','s07','s08'};
nsubjects=numel(subject_ids);

mask_label='vt_mask';

ds_rsms=cell(nsubjects,1); % allocate space for output
for subject_num=1:nsubjects
    subject_id=subject_ids{subject_num};

    % Code from here is pretty much identical to that above >>>

    % set path for this subject
    data_path=fullfile(study_path,subject_id);

    % Define data locations and load data from even and odd runs
    mask_fn=fullfile(data_path, [mask_label '.nii']); % vt mask

    % Use odd runs only
    data_fn=fullfile(data_path,'glm_T_stats_odd.nii');
    ds=cosmo_fmri_dataset(data_fn,'mask',mask_fn,...
                            'targets',1:6,'chunks',1);

    ds_rsm=cosmo_dissimilarity_matrix_measure(ds);

    % set chunks (one chunk per subject)
    ds_rsm.sa.chunks=subject_num*ones(size(ds_rsm.samples,1),1);
    ds_rsms{subject_num}=ds_rsm;
end

% combine data from all subjects
all_ds=cosmo_stack(ds_rsms);

%% Run DISTATIS
distatis=cosmo_distatis(all_ds);

%% show comprimise distance matrix
[compromise_matrix,dim_labels,values]=cosmo_unflatten(distatis,1);

labels={'monkey', 'lemur', 'mallard', 'warbler', 'ladybug', 'lunamoth'};
n_labels=numel(labels);
figure();
imagesc(compromise_matrix)
title('DSM');
set(gca,'YTick',1:n_labels,'YTickLabel',labels);
set(gca,'XTick',1:n_labels,'XTickLabel',labels);
ylabel(dim_labels{1});
xlabel(dim_labels{2});
colorbar

% skip if stats toolbox is not present
if cosmo_check_external('@stats',false)
    figure();
    hclus = linkage(compromise_matrix);
    dendrogram(hclus,'labels',labels,'orientation','left');
    title('dendrogram');

    figure();
    F = cmdscale(squareform(compromise_matrix));
    text(F(:,1), F(:,2), labels);
    title('2D MDS plot');
    mx = max(abs(F(:)));
    xlim([-mx mx]); ylim([-mx mx]);
end

%% show citation information
cosmo_check_external('-cite');


% Plot simulation results with log x axis.
% Plot only + freq terms.
% Per common practice, do not show carrier term.
% Plot measured, plus specification.
% Dick Benson
% Copyright 2004-2013 The MathWorks, Inc.
index_start = 3;              % move out from carrier at DC and fft window effects
Frame_Length = length(Normalized_Spectrum);
Fvec_meas = Spectrum_dF*((index_start-1):Frame_Length/2);

h2  =  findobj('Tag','plot_VCO');
if isempty(h2)
   h2 =  figure('Tag','plot_VCO')
else
   figure(h2)
end

semilogx(Fvec_meas,10*log10(Normalized_Spectrum(index_start:(Frame_Length/2+1))),....
         Fvec,Lvec,'o','markersize',10,'linewidth',1,'markerfacecolor','g');
xlabel('Hz from Carrier'); ylabel('dBc/Hz'); grid on;
legend('Measured', 'specification');
axis([Fvec(1),Fvec_meas(end),-160,-60])


function rtk=udpos(rtk,tt)

global glc
VAR_POS=30^2; VAR_VEL=10^2; VAR_ACC=10^2; var=0;

% initialize position for first epoch
if norm(rtk.x(1:3))<=0
    for i=1:3,rtk=initx(rtk,rtk.sol.pos(i),VAR_POS,i);end
    if rtk.opt.dynamics==1
        for i=1:3,rtk=initx(rtk,rtk.sol.vel(i),VAR_VEL,i+3);end
        for i=1:3,rtk=initx(rtk,1e-6,VAR_ACC,i+6);end
    end
    return;
end

% static mode
if rtk.opt.mode==glc.PMODE_STATIC,return;end

% kinmatic mode without dynamics
if ~rtk.opt.dynamics
    for i=1:3,rtk=initx(rtk,rtk.sol.pos(i),VAR_POS,i);end
    return;
end

for i=1:3
    var=var+rtk.P(i,i);
end
var=var/3;

if var>VAR_POS
    for i=1:3,rtk=initx(rtk,rtk.sol.pos(i),VAR_POS,i);end
    for i=4:6,rtk=initx(rtk,rtk.sol.vel(i-3),VAR_VEL,i);end
    for i=7:9,rtk=initx(rtk,1e-6,VAR_ACC,i);end
    return;
end

nx=0;ix=zeros(rtk.nx,1);
for i=1:rtk.nx
    if rtk.x(i)~=0&&rtk.P(i,i)>0
        ix(nx+1)=i;
        nx=nx+1;
    end
end
ix(nx+1:end)=[];

if nx<9,return;end

% state transition of position/velocity/acceleration
F=eye(nx); x=zeros(nx,1); P=zeros(nx,nx);
for i=1:6,F(i,i+3)=tt;end
for i=1:3,F(i,i+6)=tt^2*0.5;end

for i=1:nx
    x(i)=rtk.x(ix(i));
    for j=1:nx
        P(i,j)=rtk.P(ix(i),ix(j));
    end
end

xp=F*x; P=F*P*F';

for i=1:nx
    rtk.x(ix(i))=xp(i);
    for j=1:nx
        rtk.P(ix(i),ix(j))=P(i,j);
    end
end

% process noise added to only acceleration
Q(1,1)=rtk.opt.prn(4)^2*abs(tt);
Q(2,2)=rtk.opt.prn(4)^2*abs(tt);
Q(3,3)=rtk.opt.prn(5)^2*abs(tt);
[~,Cne]=xyz2blh(x(1:3));
Qv=Cne'*Q*Cne;

for i=1:3
    for j=1:3
        rtk.P(i+6,j+6)=rtk.P(i+6,j+6)+Qv(i,j);
    end
end

return


function title = p11_title ( )

%*****************************************************************************80
%
%% P11_TITLE returns the title for problem 11.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    28 July 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, string TITLE, the title of the problem.
%
  title = '1 / ( (1+x) * sqrt(x) )';

  return
end


function [b1, b2] = isManifoldMesh(varargin)
%ISMANIFOLDMESH Check whether the input mesh may be considered as manifold.
%
%   B = isManifoldMesh(V, F)
%   B = isManifoldMesh(V, E, F)
%   Checks if the specified mesh is a manifold. When mesh is a manifold,
%   all edges are connected to either 2 or 1 faces.
%
%   [B, HASBORDER] = isManifoldMesh(V, E, F)
%   Also checks whether the mesh contains border faces. Border faces
%   contains at least one edge which is ajacent to only one face.
%
%   Example
%     [V, F] = createOctahedron;
%     isManifoldMesh(V, F)
%     ans =
%       logical
%        1
%
%   See also
%     meshes3d, ensureManifoldMesh, trimMesh

% ------
% Author: David Legland
% E-mail: david.legland@inra.fr
% Created: 2019-01-31, using Matlab 9.5.0.944444 (R2018b)
% Copyright 2019-2022 INRA - Cepia Software Platform

vertices = varargin{1};
faces = varargin{2};

% compute edge to vertex array
if nargin == 3
    edges = faces;
    faces = varargin{3};
else
    % compute edge to vertex array
    edges = meshEdges(faces);
end

% compute face to edge indices array
% as a nFaces-by-3 array (each face connected to exactly three edges)
faceEdgeInds = meshFaceEdges(vertices, edges, faces);

% compute number of faces incident each edge
edgeFaces = trimeshEdgeFaces(faces);
edgeFaceDegrees = sum(edgeFaces > 0, 2);

% for each face, concatenate the face degree of each edge
faceEdgeDegrees = zeros(size(faces, 1), 3);
for iFace = 1:size(faces, 1)
    edgeInds = faceEdgeInds{iFace};
    faceEdgeDegrees(iFace, :) = edgeFaceDegrees(edgeInds);
end

regFaces = sum(ismember(faceEdgeDegrees, [1 2]), 2) == 3;
innerFaces = sum(faceEdgeDegrees == 2, 2) == 3;
borderFaces = regFaces & ~innerFaces;

% check if mesh is manifold: all faces are either regular or border
b1 = all(regFaces);

% check if some faces are border
b2 = any(borderFaces);


function r = times(a,b)
%TIMES        Taylor multiplication  a .* b
%

% written  05/21/09     S.M. Rump
% modified 08/26/12     S.M. Rump  global variables removed
%

  e = 1e-30;
  if 1+e==1-e                           % fast check for rounding to nearest
    rndold = 0;
  else
    rndold = getround;
    setround(0)
  end

  K1 = getappdata(0,'INTLAB_TAYLOR_ORDER') + 1;

  if ~isa(a,'taylor')           % non-taylor times taylor
    r = b;
    if isa(a,'intval')
      r.t = intval(r.t);
    end
    m = prod(size(a));
    if m==1                     % non-taylor scalar .* taylor
      r.t = a*r.t;
    else                        % non-taylor array .* taylor
      n = prod(b.size);
      if n==1                   % non-taylor array .* taylor scalar
        r.size = size(a);
        r.t = repmat(a(:).',K1,1) .* repmat(b.t,1,m);
      else                      % non-taylor array .* taylor array
        if ~isequal(size(a),b.size)
          error('Taylor multiplication : dimensions not compatible')
        end
        r.t = repmat(a(:).',K1,1) .* b.t;
      end
    end
  elseif ~isa(b,'taylor')       % taylor times non-taylor
    r = a;
    if isa(b,'intval')
      r.t = intval(r.t);
    end
    m = prod(size(b));
    if m==1                     % taylor scalar .* non-taylor
      r.t = r.t*b;
    else                        % taylor array .* non-taylor
      n = prod(a.size);
      if n==1                   % taylor array .* non-taylor scalar
        r.t = repmat(a.t,1,m) .* repmat(b(:).',K1,1);
      else                      % non-taylor array .* taylor array
        if ~isequal(size(b),a.size)
          error('Taylor multiplication : dimensions not compatible')
        end
        r.t = a.t .* repmat(b(:).',K1,1);
      end
    end
  else                          % both factors taylor
    m = prod(a.size);
    n = prod(b.size);
    if m==1                     % taylor scalar .* taylor
      r = b;
      if isa(a,'intval')
        r.t = intval(r.t);
      end
      for j=1:K1
        r.t(j,:) = sum(repmat(a.t(1:j),1,n).*b.t(j:-1:1,:),1);
      end
    else                        % taylor array .* taylor
      r = a;
      if isa(b.t,'intval')
        r.t = intval(r.t);
      end
      if n==1                   % taylor array .* taylor scalar
        for j=1:K1
          r.t(j,:) = sum(a.t(1:j,:).*repmat(b.t(j:-1:1),1,m),1);
        end
      else                      % taylor array .* taylor array
        if ~isequal(a.size,b.size)
          error('Taylor multiplication : dimensions not compatible')
        end
        for j=1:K1
          r.t(j,:) = sum(a.t(1:j,:).*b.t(j:-1:1,:),1);
        end
      end
    end
  end

  if rndold
    setround(rndold)
  end


function [x,omega] = plotFibre(odf,f,varargin)
% plot odf along a fibre
%
% Syntax
%   plotFibre(odf,f);
%
% Input
%  odf - @SO3Fun
%  f   - @fibre
%
% Options
%  resolution - resolution of each plot
%
% Example
%   odf = SantaFe;
%   f = fibre.gamma(odf.CS,odf.SS)
%   plotFibre(SantaFe,f)
%
% See also
% S2Grid/plot savefigure Plotting Annotations_demo ColorCoding_demo PlotTypes_demo
% SphericalProjection_demo

% get axis
[mtexFig,isNew] = newMtexFigure(varargin{:});

% extract fibre
if isa(f,'fibre')
  [ori,omega] = orientation(f,odf.CS,odf.SS);
elseif isa(varargin{1},'quaternion')
  omega = angle(f(1),f);
  ori = orientation(f,odf.CS,odf.SS);
end

% find loop
delta = angle(ori(2:end),ori(1));
fz = find(delta(:)<1e-2);

% remove values to close together
fz = fz([true;diff(fz)>1]);

if any(fz) && round(numel(delta) / fz(1)) == numel(fz) && ...
    ~check_option(varargin,'comlete')
  ind = 1:find(delta<1e-2,1,'first');
  ori = ori(ind);
  omega = omega(ind);
end

% evaluate the ODF
x = eval(odf,ori,varargin{:});

% plot the fibre
optiondraw(plot(omega./degree,x,'parent',mtexFig.gca),varargin{:});

if isNew
  xlim(mtexFig.gca,[min(omega),max(omega)]./degree);
  ylabel(mtexFig.gca,'Frequency (mrd)')
  xlabel(mtexFig.gca,['misorientation angle (degree) to ' char(ori(1))]);
  drawNow(mtexFig,varargin{:})
end

if nargout == 0, clear x omega; end


function scaledImg = scaleImg(img,range)
% scale image to range
%
% (c) Thomas Kuestner
% ---------------------------------------------------------------------

if(nargin < 2)
    range = [0 1];
end

if(length(range) == 1)
    range = [0 range];
end

scaledImg = ((img - min(img(:))) * (range(2)-range(1)))./(max(img(:)) - min(img(:)));

end


function example_bar_plot()
test_data =[18     0; 20     0;   21     2;    30    14;    35    34;    40    57;    45    65;    50    46;    55     9;    60     2;    65     1;    70     0];

% Create figure
figure1 = figure('Color',[1 1 1]);

subplot(1,2,1)

hb=barh(test_data(:,1),test_data(:,2),'DisplayName','Test Data');

ylabel('parameter [units]');
xlabel('#');
legend('show','Location','northwest');
subplot(1,2,2)

hb=bar(test_data(:,1),test_data(:,2),'DisplayName','Test Data');

xlabel('parameter [units]');
ylabel('#');
legend('show','Location','northwest');

xdata=test_data(:,1);
barWidth=test_getBarWidthInAbsolutUnits(hb);

x_l=xdata-barWidth/2;
x_u=xdata+barWidth/2;
max_y=max(test_data(:,2))*1.2;
x=[];
y=[];
for i=1:length(x_l)
    x = [x , x_l(i),x_l(i),nan,x_u(i),x_u(i),nan];
    y = [y,       0,max_y ,nan,0     ,max_y ,nan];

end
hold on
plot(x,y,'r');

matlab2tikz('figurehandle',figure1,'filename','example_v_bar_plot.tex' ,'standalone', true);

    function BarWidth=test_getBarWidthInAbsolutUnits(h)
        % astimates the width of a bar plot
        XData_bar=get(h,'XData');
        length_bar = length(XData_bar);
        BarWidth= get(h, 'BarWidth');
        if length_bar > 1
            BarWidth = min(diff(XData_bar))*BarWidth;
        end


%% housekeeping
clear
close all
clc()

%% Create dataset
clc

do_plot=true;

scale=100;

[db,varlist0]=create_dataset(scale,do_plot);

varlist=fieldnames(varlist0);
%% Choose a model type: see cell "create the structural VAR model" below

model_type=0;

%% set up the restrictions
close()

% create restrictions on parameters as well as markov chains
%------------------------------------------------------------
switch model_type
    case 0
        % constant-parameter model
        [restrictions,markov_chains,switch_prior]=create_restrictions_and_markov_chains0();
    case 1
        % Coefficients are switching regimes across all equations
        % (synchronized case)
        [restrictions,markov_chains,switch_prior]=create_restrictions_and_markov_chains1();
    case 2
        % Coefficients and variances have different chains, different
        % regimes, and different durations
        [restrictions,markov_chains,switch_prior]=create_restrictions_and_markov_chains2();
    case 3
        % Only coefficients in monetary policy equation are changing
        [restrictions,markov_chains,switch_prior]=create_restrictions_and_markov_chains3();
    case 4
        % Only variance in monetary policy equation is changing
        [restrictions,markov_chains,switch_prior]=create_restrictions_and_markov_chains4();
    case 5
        % Both coefficients and variances in monetary policy equation
        % change with two independent Markov processes
        [restrictions,markov_chains,switch_prior]=create_restrictions_and_markov_chains5();
    case 6 % ok
        % Only variances in ALL three equations switch
        [restrictions,markov_chains,switch_prior]=create_restrictions_and_markov_chains6();
    otherwise
        error('the coded model types are 0, 1, 2, 3, 4 and 6')
end

%% Create the VAR

clc

nlags=2;

exog={};

panel=[];

constant=true;

% first we create a template structure
% ------------------------------------
sv0=svar(varlist,exog,nlags,constant,panel,markov_chains);

%% set priors % prior=[];

var_prior=svar.prior_template();

var_prior.type='sz';

prior=struct('var',var_prior,'nonvar',switch_prior);

is_prior=true;

if ~is_prior

    prior=rmfield(prior,'var');

end

%% Find posterior mode
clc

sv=sv0;

sv=estimate(sv,db,{'1960Q1','2015Q2'},prior,restrictions);

%% estimates
clc

pmode=posterior_mode(sv)

%% Printing estimates
clc

print_structural_form(sv)

%% Printing solution
clc

print_solution(sv)

%% plot smoothed state and regime probabilities
clc
close all

plot_probabilities(sv)

%% plots probabilities against data
close all

plot_data_against_probabilities(sv,'regime')

%% Impulse responses

myirfs=irf(sv);

%% Posterior sampling

%% Marginal data density

%% Out-of sample forecasts

%% Conditional forecast


function qfsum = eiqf ( nt, t, mlt, wts, nwts, ndx, key, f )

%*****************************************************************************80
%
%% EIQF evaluates an interpolatory quadrature formula.
%
%  Discussion:
%
%   The knots, weights and integrand are supplied.
%
%   All knots with nonzero NDX are used.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    05 January 2010
%
%  Author:
%
%    Original FORTRAN77 version by Sylvan Elhay, Jaroslav Kautsky.
%    MATLAB version by John Burkardt.
%
%  Reference:
%
%    Sylvan Elhay, Jaroslav Kautsky,
%    Algorithm 655: IQPACK, FORTRAN Subroutines for the Weights of
%    Interpolatory Quadrature,
%    ACM Transactions on Mathematical Software,
%    Volume 13, Number 4, December 1987, pages 399-415.
%
%  Parameters:
%
%    Input, integer NT, the number of knots.
%
%    Input, real T(NT), the knots.
%
%    Input, integer MLT(NT), the multiplicity of the knots.
%
%    Input, real WTS(NWTS), the weights.
%
%    Input, integer NWTS, the number of weights.
%
%    Input, integer NDX(NT), used to index the array WTS.
%    If KEY = 1, then NDX need not be preset.  For more details see the
%    comments in CAWIQ.
%
%    Input, integer KEY, indicates the structure of the WTS
%    array.  It will normally be set to 1.  This will cause the weights to be
%    packed sequentially in array WTS.  For more details see the comments
%    in CAWIQ.
%
%    Input, function F, the name of a routine which
%    evaluates the function and some of its derivatives.  The routine
%    must have the form
%      function value = f ( x, i )
%    and return in VALUE the value of the I-th derivative of the function
%    at X.  The highest value of I will be the maximum value in MLT minus
%    one.  The value X will always be a knot.
%
%    Output, real QFSUM, the value of the quadrature formula
%    applied to F.
%
  l = abs ( key );

  if ( l < 1 || 4 < l )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'EIQF - Fatal error!\n' );
    fprintf ( 1, '  Magnitude of KEY must be between 1 and 4.\n' );
    error ( 'EIQF - Fatal error!' );
  end

  qfsum = 0.0;
  for j = 1 : nt
    l = abs ( ndx(j) );
    if ( l ~= 0 )
      p = 1.0;
      for i = 1 : mlt(j)
        qfsum = qfsum + wts(l+i-1) * f ( t(j), i - 1 ) / p;
        if ( key <= 0 )
          p = p * i;
        end
      end
    end
  end

  return
end


function [mm] = dm2mm(dm)
% Convert length from decimeters to millimeters.
% Chad A. Greene 2012
mm = dm*100;


function [hpol,radlab_h] = polarLabels(theta,rho,line_style,labelrotate,rlabshift,clear)
% [hpol,radlab_h] = polarLabels(theta,rho,line_style,labelrotate,rlabshift,clear)
%
% polarLabels   Polar coordinate plot. (with added options)
%   polarLabels(THETA, RHO) makes a plot using polar coordinates of
%   the angle THETA, in radians, versus the radius RHO.
%   polarLabels(THETA,RHO,S) uses the linestyle specified in string S.
%   See PLOT for a description of legal linestyles.
%
%   See also PLOT, LOGLOG, SEMILOGX, SEMILOGY.
%
% Additions
%   Plot is labelled +/-180 instead of 0-360
%   Additional input options
%       labelrotate     value (in degrees) to add to angle labels to facilitate rotation of LABEL
%                       def = 0
%       rlabshift       value to add to radial labels to facilitate impression of negative values
%                       def = 0
%       clear           make polar background clear
%                       def = false (0)
%
% Ex. polarlabels([0:360]*pi/180,abs(sin([0:360]*pi/180))*10,'b',-90,-10)
%
%   Additional output option
%       [hpol,radlab_h] = polarLabels(theta,rho,line_style,labelrotate,rlabshift,clear)
%       radlab_h           vector of handles to radial text labels
%
%       Backward compatible with standard POLAR
%       For multiple plots (hold on) should only need to be used with the first one

%   Revised by BFGK 26-mars-2002
%    For better access to labels
%   Revised by BFGK 27-mai-2002
%    Fix to work with full 360 plot
%   Revised by BFGK 22-mai-2003
%    Added "clear" option for special background application
%    Tidied up nargin section

if nargin < 1
    error('Requires at least 2 input arguments.')
elseif nargin == 2
    if isstr(rho)
        line_style = rho;
        rho = theta;
        [mr,nr] = size(rho);
        if mr == 1
            theta = 1:nr;
        else
            th = (1:mr)';
            theta = th(:,ones(1,nr));
        end
    else
        line_style = 'auto';
    end
elseif nargin == 1
    line_style = 'auto';
    rho = theta;
    [mr,nr] = size(rho);
    if mr == 1
        theta = 1:nr;
    else
        th = (1:mr)';
        theta = th(:,ones(1,nr));
    end
end

if ~isequal(size(theta),size(rho))
    error('THETA and RHO must be the same size.');
end

% Dealing with additional arguments
if nargin < 4,  labelrotate = 0 ;    end
if nargin < 5,  rlabshift = 0   ;    end
if nargin < 6,  clear = 0       ;    end

if isstr(theta) | isstr(rho) | isstr(labelrotate) | isstr(rlabshift)
    error('Input arguments must be numeric.');
end

% get hold state
cax = newplot;
next = lower(get(cax,'NextPlot'));
hold_state = ishold;

% get x-axis text color so grid is in same color
tc = get(cax,'xcolor');
ls = get(cax,'gridlinestyle');

% Hold on to current Text defaults, reset them to the
% Axes' font attributes so tick marks use them.
fAngle  = get(cax, 'DefaultTextFontAngle');
fName   = get(cax, 'DefaultTextFontName');
fSize   = get(cax, 'DefaultTextFontSize');
fWeight = get(cax, 'DefaultTextFontWeight');
fUnits  = get(cax, 'DefaultTextUnits');
set(cax, 'DefaultTextFontAngle',  get(cax, 'FontAngle'), ...
    'DefaultTextFontName',   get(cax, 'FontName'), ...
    'DefaultTextFontSize',   get(cax, 'FontSize'), ...
    'DefaultTextFontWeight', get(cax, 'FontWeight'), ...
    'DefaultTextUnits','data')

% only do grids if hold is off
if ~hold_state

% make a radial grid
    hold on;
    maxrho = max(abs(rho(:)));
    hhh=plot([-maxrho -maxrho maxrho maxrho],[-maxrho maxrho maxrho -maxrho]);
    set(gca,'dataaspectratio',[1 1 1],'plotboxaspectratiomode','auto')
    v = [get(cax,'xlim') get(cax,'ylim')];
    ticks = sum(get(cax,'ytick')>=0);
    delete(hhh);
% check radial limits and ticks
    rmin = 0; rmax = v(4); rticks = max(ticks-1,2);
    if rticks > 5   % see if we can reduce the number
        if rem(rticks,2) == 0
            rticks = rticks/2;
        elseif rem(rticks,3) == 0
            rticks = rticks/3;
        end
    end

% define a circle
    th = 0:pi/50:2*pi;
    xunit = cos(th);
    yunit = sin(th);
% now really force points on x/y axes to lie on them exactly
    inds = 1:(length(th)-1)/4:length(th);
    xunit(inds(2:2:4)) = zeros(2,1);
    yunit(inds(1:2:5)) = zeros(3,1);
% plot background if necessary
    if (~isstr(get(cax,'color')) & ~clear),
       patch('xdata',xunit*rmax,'ydata',yunit*rmax, ...
             'edgecolor',tc,'facecolor',get(gca,'color'),...
             'handlevisibility','off');
    end

% draw radial circles
    c82 = cos(82*pi/180);
    s82 = sin(82*pi/180);
    rinc = (rmax-rmin)/rticks;
    cnt = 1;
    for i=(rmin+rinc):rinc:rmax
        hhh = plot(xunit*i,yunit*i,ls,'color',tc,'linewidth',1,...
                   'handlevisibility','off');
        radlab_h(cnt) = text((i+rinc/20)*c82,(i+rinc/20)*s82, ...
            ['  ' num2str(i+rlabshift)],'verticalalignment','bottom',...
            'handlevisibility','off');
        cnt = cnt+1;
    end
    set(hhh,'linestyle','-') % Make outer circle solid

% plot spokes
    th = (1:6)*2*pi/12;
    cst = cos(th); snt = sin(th);
    cs = [-cst; cst];
    sn = [-snt; snt];
    plot(rmax*cs,rmax*sn,ls,'color',tc,'linewidth',1,...
         'handlevisibility','off')

% annotate spokes in degrees
    rt = 1.1*rmax;
    for i = 1:length(th)
        angTextNum = (i*30)+labelrotate    ;
        text(rt*cst(i),rt*snt(i),int2str(angTextNum),...
             'horizontalalignment','center',...
             'handlevisibility','off');
        if i == length(th)
            loc = int2str(0+labelrotate);
        else
            angTextNum = 180+(i*30)+labelrotate    ;
            if angTextNum > 180, angTextNum = angTextNum - 360; end
            loc = int2str(angTextNum);
        end
        text(-rt*cst(i),-rt*snt(i),loc,'horizontalalignment','center',...
             'handlevisibility','off')
    end

% set view to 2-D
    view(2);
% set axis limits
    axis(rmax*[-1 1 -1.15 1.15]);
end

% Reset defaults.
set(cax, 'DefaultTextFontAngle', fAngle , ...
    'DefaultTextFontName',   fName , ...
    'DefaultTextFontSize',   fSize, ...
    'DefaultTextFontWeight', fWeight, ...
    'DefaultTextUnits',fUnits );

% transform data to Cartesian coordinates.
xx = rho.*cos(theta);
yy = rho.*sin(theta);

% plot data on top of grid
if strcmp(line_style,'auto')
    q = plot(xx,yy);
else
    q = plot(xx,yy,line_style);
end
if nargout > 0
    hpol = q;
end
if ~hold_state
    set(gca,'dataaspectratio',[1 1 1]), axis off; set(cax,'NextPlot',next);
end
set(get(gca,'xlabel'),'visible','on')
set(get(gca,'ylabel'),'visible','on')


classdef (HandleCompatible) AndNode < Node
    % AndNode are an class that represents AND connections in a logical formula
    % For further documentation please have a look at the Node Class.
    % .. Authors
    %     - Thomas Pfau 2016
    properties
    end

    methods
        function res = evaluate(self,assignment, printLevel)
            if ~exist('printLevel','var')
                printLevel = 0;
            end
            res = true;
            for i=1:numel(self.children)
                child = self.children(i);
                if not(child.evaluate(assignment,printLevel))
                    res = false;
                end
            end
            if printLevel >= 1
                fprintf('%s : %i\n',self.toString(0),res);
            end
        end

        function tf = deleteLiteral(self,literalID, keepClauses)
            tf = true;
            if ~exist('keepClauses','var')
                keepClauses = true;
            end
            if ~keepClauses
                % reduce to properly delete elements
                self.reduce();
            end
            arrayfun(@(x) ~isa(x,'LiteralNode') && x.deleteLiteral(literalID, keepClauses), self.children);
            % originalNodeString = self.toString(1);
            literalMatches = arrayfun(@(x) (isa(x, 'LiteralNode') && x.contains(literalID) ), self.children);
            emptyChildren = arrayfun(@(x) (~isa(x,'LiteralNode') && numel(x.children) <= 1), self.children);
            if ~keepClauses
                % if we don't keep and clauses containing the literal
                if any(literalMatches)
                    % and the literal is a direct child of this clause
                    % we empty this node
                    self.children(:) = [];
                    return
                end
            end
            % otherwise, we only remove the child.
            % and check for one element entries
            mergeChildren = arrayfun(@(x) ~isa(x,'LiteralNode') && numel(x.children) == 1, self.children);
            toDelete = literalMatches|emptyChildren;
            if any(mergeChildren)
                childsToMerge = self.children(mergeChildren);
                childrenToAdd = AndNode();
                for i = 1:numel(childsToMerge)
                    cchild = childsToMerge(i);
                    childrenToAdd(i) = cchild.children;
                end
                % the following works only on 2017b or newer, but is more
                % efficient.
                %childrenToAdd = arrayfun(@(x) x.children, self.children(mergeChildren));
            end
            self.children(toDelete) = [];
            if exist('childrenToAdd','var')
                for child = 1:numel(childrenToAdd)
                    newChild = childrenToAdd(child);
                    self.children(end+1) = newChild;
                    newChild.parent = self;
                end
            end
            %fprintf('Removing Literal %s from the following node:\n%s\nLeads to the node:\n%s\n',literalID,originalNodeString,self.toString(1));
        end

        function res = toString(self,PipeAnd)
            if nargin < 2
                PipeAnd = 0;
            end
            res = '';
            for i=1:numel(self.children)
                child = self.children(i);
                if PipeAnd
                    res = [res child.toString(PipeAnd) ' & '];
                else
                    res = [res child.toString(PipeAnd) ' and '];
                end

            end
            if length(res) > 2
                if PipeAnd
                    res = res(1:end-3);
                else
                    res = res(1:end-5);
                end
            end
        end
        function cnfNode = convertToCNF(self)
            cnfNode = AndNode();
            for i = 1:numel(self.children)
                if isa(self.children(i),'LiteralNode')
                    CNFChild = self.children(i).copy();
                else
                    CNFChild = self.children(i).convertToCNF();
                end
                cnfNode.addChild(CNFChild);
            end
        end

        function dnfNode = convertToDNF(self)
            dnfNode = OrNode();
            childNodes = [];
            sizes = [];
            for c=1:numel(self.children)
                child = self.children(c);
                if isempty(childNodes)
                    childNodes = child.convertToDNF();
                else
                    childNodes(end+1) = child.convertToDNF();
                end
                convNode = childNodes(end);
                sizes(end+1) = numel(convNode.children);
            end
            %Now make and combinations of all items in the children
            step = ones(numel(sizes),1);
            while self.isValid(sizes,step)
                nextNode = AndNode();
                for i=1:numel(step)
                    convNode = childNodes(i);
                    if strcmp(class(convNode),'LiteralNode')
                        nextNode.addChild(convNode);
                    else
                        nextNode.addChild(convNode.children(step(i)));
                    end
                end
                dnfNode.addChild(nextNode);
                step = self.nextcombination(sizes,step);
            end
            %finally, remove all duplicate literal nodes from this node.

            for c = 1:numel(dnfNode.children)
                literals = {};
                childrenToRemove = [];
                childNode = dnfNode.children(c);
                for i = 1 : numel(childNode.children)
                    if isa(childNode.children(i),'LiteralNode')
                        if ~any(~cellfun(@isempty, strfind(literals,childNode.children(i).toString())))
                            literals{end+1} = childNode.children(i).toString();
                        else
                            childrenToRemove(end+1) = i;
                        end
                    end
                end
                childNode.children(childrenToRemove) = [];
            end
        end

        function res = isValid(self,sizes,step)
            % Check whether a given step is a valid possibility (no step
            % element larger than sizes
            % USAGE:
            %    res = Node.isValid(sizes,step)
            %
            % INPUTS:
            %    sizes:     An array of sizes
            %    step:      An array of suggested selections
            %
            % OUTPUTS:
            %    res:       ~any(step > sizes')
            %
            res = ~any(step > sizes');
        end

        function combination = nextcombination(self,sizes,step)
            % Get the next combination given the current combination
            % USAGE:
            %    combination = Node.nextcombination(sizes,step)
            %
            % INPUTS:
            %    sizes:     An array of maximal sizes
            %    step:      The current combination
            %
            % OUTPUTS:
            %    combination:   The next allowed element of step
            %                   incremented, and potentially others reset
            %                   to 1.
            %
            combination = step;
            combination(1) = combination(1) + 1;
            for i=1:numel(sizes)
                if combination(i) > sizes(i)
                    if i < numel(sizes)
                        combination(i) = 1;
                        combination(i+1) = combination(i+1)  + 1;
                    end
                else
                    break;
                end
            end
        end

        function reduce(self)
            %we can merge any children of and nodes directly.
            mergeNode.children = [];
            childrenChanged = false;
            for i = 1:numel(self.children)
                cchild = self.children(i);
                cchild.reduce()
                %Check if the child has exactly one child. I
                if numel(cchild.children) == 1
                    %If there is only one child, we can directly add the
                    %child to this node.
                    mergeNode.children = [mergeNode.children,cchild.children];
                    childrenChanged = true;
                elseif isa(cchild,'AndNode')
                    mergeNode.children = [mergeNode.children,cchild.children];
                    childrenChanged = true;
                else
                    mergeNode.children = [mergeNode.children,cchild];
                end
            end
            if childrenChanged
                self.children = mergeNode.children;
                for i = 1:numel(self.children)
                    self.children(i).parent = self;
                end
            end
        end
    end

end


function [ceq,ceqJac] = autoGen_cst_steplength(q1m,q2m,q4m,q5m,l1,l2,l4,l5,stepLength)
%AUTOGEN_CST_STEPLENGTH
%    [CEQ,CEQJAC] = AUTOGEN_CST_STEPLENGTH(Q1M,Q2M,Q4M,Q5M,L1,L2,L4,L5,STEPLENGTH)

%    This function was generated by the Symbolic Math Toolbox version 6.3.
%    25-Oct-2015 18:36:52

t2 = cos(q1m);
t3 = l1.*t2;
t4 = cos(q2m);
t5 = l2.*t4;
t6 = cos(q4m);
t7 = cos(q5m);
t8 = sin(q1m);
t9 = sin(q2m);
t10 = sin(q4m);
t11 = l4.*t10;
t12 = sin(q5m);
t13 = l5.*t12;
ceq = [-stepLength+t11+t13-l1.*t8-l2.*t9;t3+t5-l4.*t6-l5.*t7];
if nargout > 1
    ceqJac = reshape([0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-t3,-l1.*t8,-t5,-l2.*t9,0.0,0.0,l4.*t6,t11,l5.*t7,t13,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0],[2,32]);
end


%Script that explains how to combine computeGTOM output with a hierarchical
%clustering
%   Joaquin Goñi <jgoni@unav.es> & Iñigo Martincorena
%   <imartincore@alumni.unav.es>
%   University of Navarra - Dpt. of Physics and Applied Mathematics &
%   Centre for Applied Medical Research.  Pamplona (Spain).
%
%   November 22nd 2007
%
load adjExample.mat    %example of an adjacency matrix
step = 3;   %value to compute GTOMstep (GTOM0,GTOM1,GTOM2, etc)
[GTOM]=computeGTOM(adjExample,step);
dist = ones(size(adjExample)) - GTOM;  %GTOM dissimilarity matrix
distVector = squareform(dist,'tovector');   %conversion to vector taking upper triangular values
Z = linkage(distVector,'average');  %linkage with average criteria
subplot(2,1,1), [H,T,PERM] = dendrogram(Z,0,'colorthreshold',0.35); %dendrogram plot with colorthreshold set to 0.35
GTOMOrdered = GTOM(PERM,PERM); %GTOM ordered by dendrogram
subplot(2,1,2), imagesc(GTOMOrdered); axis square; %plot of GTOMordered to check modules detection
%Automatic figure resizing and better merging to be done


function F = acsch(F, varargin)
%ACSCH   Inverse hyperbolic cosecant of a CHEBFUN.
%   ACSCH(F) computes the inverse hyperbolic cosecant of the CHEBFUN F.
%
%   ACSCH(F, PREF) does the same but uses the CHEBFUNPREF object PREF when
%   computing the composition.
%
% See also CSCH.

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

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

end


%%
%   MATLAB code for DeepFool
%
%   adversarial_DeepFool_caffe(x,net):
%   computes the adversarial perturbations for a Caffe's model
%
%   INPUTS
%   x: image in W*H*C format
%   net: Caffe's network (without loss layer - do not forget to enable 'force_backward')
%   opts: A struct contains parameters (see README)
%   OUTPUTS
%   r_hat: minimum perturbation
%   l_hat: adversarial label
%   l: classified label
%   itr: number of iterations
%
%   please cite: S. Moosavi-Dezfooli, A. Fawzi, P. Frossard: DeepFool: a simple and accurate method to fool deep neural networks.
%                In Computer Vision and Pattern Recognition (CVPR 2016), IEEE, 2016.
%%
function [r_hat,l_hat,l,itr] = adversarial_DeepFool_caffe(x,net,opts)
size_x = size(x);
x = reshape(x,numel(x),1);
l = f(x,1);

if(nargin==3)
    adv = adversarial_perturbation(x,l,@Df,@f,opts);
else
    adv = adversarial_perturbation(x,l,@Df,@f);
end

l_hat = adv.new_label;
r_hat = reshape(adv.r,size_x);
itr = adv.itr;

    function out = f(y,flag)
        y = reshape(y,size_x);

        out = net.forward({y}); %do forward pass
        out = out{1}'; %convert 'out' from a cell array to a matrix

        %flag==0:compute the outputs
        %flag==1:compute the label
        if flag==1
            [~,out] = max(out);
        end
    end

    function dzdx = Df(y,label,idx)
        y = reshape(y,size_x);
        net.forward({y}); %do forward pass

        for i=1:numel(idx)
            dzdy = zeros(net.blobs(net.blob_names{end}).shape,'single');

            dzdy(idx(i)) = 1;

            res = net.backward({dzdy}); %do backward pass
            dzdx(:,i) = reshape(res{1},numel(y),1);
        end
        dzdx = dzdx-repmat(dzdx(:,idx==label),1,numel(idx));
    end
end


% fig_hyper1
% show hyperbola for various delta values

dlist = [1000 10 4 1];
tmax = 4;
ptype = 'hyper3';
plist = {'quad', 'huber2', 'hyper3', 'lange1', 'lange3', ...
	'cauchy', 'qgg2'};
t = tmax * linspace(-1, 1, 401)';
for ii=1:length(dlist)
%	ptype = plist{ii};
	delta = dlist(ii);
	leg{ii} = [ptype ' \delta = ' num2str(delta)];
	param = [];

	pot = potential_fun(ptype, delta, param);
	pp(:,ii) = pot.potk(t);
	pw(:,ii) = pot.wpot(t);
	pd(:,ii) = pot.dpot(t);
end

if im
	clf
	plot(t, pp), title 'potk'
	legend(leg)
	xlabel 't'
	ylabel 'p(t)'
end


% Test file for singfun/isfinite.m

function pass = test_isfinite(pref)

% Get preferences.
if ( nargin < 1 )
    pref = chebfunpref();
end

% The order of the exponents:
a = 0.64;
b = -0.64;
c = 1.28;
d = -1.28;

%%
% Check a few cases.

% fractional root at the left endpoint
data.exponents = [a 0];
data.singType = {'root', 'none'};
f = singfun(@(x) (1 + x).^a.*exp(x), data, pref);
pass(1) = isfinite(f);

% fractional pole at the left endpoint
data.exponents = [d 0];
data.singType = {'sing', 'none'};
f = singfun(@(x) (1 + x).^d.*sin(x), data, pref);
pass(2) = ~isfinite(f);

end


function r=risk(t,j,varargin)
%RISK Node risk.
%   R=RISK(T) returns an N-element vector R of the risk of the nodes in the
%   tree T, where N is the number of nodes.
%
%   R=RISK(T,J) takes an array J of node numbers and returns the risk
%   values for the specified nodes.
%
%   R=RISK(T,J,'criterion','error') returns risk vector R, where R(J) for
%   node J is the node error E(J) (classification error or mean squared
%   error for regression) weighted by the node probability P(J).
%
%   R=RISK(T,J,'criterion','impurity') computes risk by using the node
%   impurity measure for each node instead of the node error. This option
%   is only valid for classification trees grown using impurity measures
%   such as Gini index or deviance.
%
%   See also CLASSREGTREE, CLASSREGTREE/NODEERR, CLASSREGTREE/NODEPROB.

%   Copyright 2006-20097 The MathWorks, Inc.
%   $Revision: 1.1.8.4 $  $Date: 2009/05/07 18:32:51 $

if nargin>=2 && ~validatenodes(t,j)
    error('stats:classregtree:risk:InvalidNode',...
          'J must be an array of node numbers or a logical array of the proper size.');
end

args = {'criterion'};
defs = {'error'};
[~,emsg,crit] = getargs(args,defs,varargin{:});
if ~isempty(emsg)
    error('stats:classregtree:risk:InvalidInput','Invalid input: %s',emsg);
end

if isempty(strmatch(lower(crit),'error')) && isempty(strmatch(lower(crit),'impurity'))
    error('stats:classregtree:risk:InvalidInput',...
        '''crit'' argument must be either ''error'' or ''impurity''.');
end

if strcmpi(crit,'error')
    r = t.nodeprob .* t.nodeerr;
else
    if isempty(t.impurity)
        error('stats:classregtree:risk:InvalidInput',...
        'Node risk cannot be computed using impurity. This is either a regression tree or splits were not found using impurity.');
    end
    r = t.nodeprob .* t.impurity;
end

if nargin>=2
    r = r(j,:);
end
end


function xi = cvx_cleanup_structure( xi )

%CVX_CLEANUP_STRUCTURE   Canonicalizes a matrix structure basis.
%    CVX_CLEANUP_STRUCTURE(X), where X is an m x n matrix, converts X
%    to row reduced echelon form with the zero rows removed. The matrices
%    X are assumed to come from CVX's matrix structure facility, and as
%    such certain assumptions are made about both X and its RREF: that it
%    is sparse and its nonzero elements are ratios of small integers. As a
%    result this routine should not be used for general RREF computations
%    without modifying it to remove some of the cleanup code.

% Reduce using an LU factorization
[LL,xi,PP] = lu(xi); %#ok
[m,n] = size(xi);

% Remove the entries that are close to zero
tol = 16 * eps;
xi  = xi .* ( abs(xi) > tol * norm(xi,'inf') );

% Find the locations of the leading element in each row. To do this we first
% find the first element in each row. Transposing xi insures that the
% indices are sorted properly to accomplish this.
[jj,ii] = find(xi');
if isempty(jj),
    xi = sparse(0,n);
    return
end
dd = [true;diff(ii)~=0];
ii = ii(dd);
jj = jj(dd);

% Sort the rows so that the leftmost nonzero is first (the LU factorization
% does this already much of the time, but in rank-degenerate cases further
% sorting is needed.) From that select a unique set of columns to use.
[jj,jndx] = sort(jj);
dd = [true;diff(jj)~=0];
ii = ii(jndx(dd));
jj = jj(dd);

% Divide through the rows ii by this full-rank triangle. The other rows
% must already be zero or be dependent upon these rows, so we remove them.
% Q is the result except that its columns are scrambled.
rr = length(ii);
j2 = (1:n)'; j2(jj) = [];
Q  = xi(ii,jj)\xi(ii,j2);

% Reduce roundoff error by converting the values to ratios of integers.
[i3,j3,vv] = find(Q);
[vn,vd] = rat(vv,tol);
xi = sparse([(1:rr)';i3],[jj;j2(j3)],[ones(rr,1);vn./vd],rr,n);

% Copyright 2010 Michael C. Grant and Stephen P. Boyd.
% See the file COPYING.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function [t,f_new,g_new,funEvals,H] = WolfeLineSearch(...
    x,t,d,f,g,gtd,c1,c2,LS,maxLS,tolX,debug,doPlot,saveHessianComp,funObj,varargin)
%
% Bracketing Line Search to Satisfy Wolfe Conditions
%
% Inputs:
%   x: starting location
%   t: initial step size
%   d: descent direction
%   f: function value at starting location
%   g: gradient at starting location
%   gtd: directional derivative at starting location
%   c1: sufficient decrease parameter
%   c2: curvature parameter
%   debug: display debugging information
%   LS: type of interpolation
%   maxLS: maximum number of iterations
%   tolX: minimum allowable step length
%   doPlot: do a graphical display of interpolation
%   funObj: objective function
%   varargin: parameters of objective function
%
% Outputs:
%   t: step length
%   f_new: function value at x+t*d
%   g_new: gradient value at x+t*d
%   funEvals: number function evaluations performed by line search
%   H: Hessian at initial guess (only computed if requested

% Evaluate the Objective and Gradient at the Initial Step
if nargout == 5
    [f_new,g_new,H] = funObj(x + t*d,varargin{:});
else
    [f_new,g_new] = funObj(x+t*d,varargin{:});
end
funEvals = 1;
gtd_new = g_new'*d;

% Bracket an Interval containing a point satisfying the
% Wolfe criteria

LSiter = 0;
t_prev = 0;
f_prev = f;
g_prev = g;
gtd_prev = gtd;
done = 0;

while LSiter < maxLS

    %% Bracketing Phase
    if ~isLegal(f_new) || ~isLegal(g_new)
        if 0
            if debug
                fprintf('Extrapolated into illegal region, Bisecting\n');
            end
            t = (t + t_prev)/2;
            if ~saveHessianComp && nargout == 5
                [f_new,g_new,H] = funObj(x + t*d,varargin{:});
            else
                [f_new,g_new] = funObj(x + t*d,varargin{:});
            end
            funEvals = funEvals + 1;
            gtd_new = g_new'*d;
            LSiter = LSiter+1;
            continue;
        else
            if debug
                fprintf('Extrapolated into illegal region, switching to Armijo line-search\n');
            end
            t = (t + t_prev)/2;
            % Do Armijo
            if nargout == 5
                [t,x_new,f_new,g_new,armijoFunEvals,H] = ArmijoBacktrack(...
                  x,t,d,f,f,g,gtd,c1,max(0,min(LS-2,2)),tolX,debug,doPlot,saveHessianComp,...
                  funObj,varargin{:});
            else
                [t,x_new,f_new,g_new,armijoFunEvals] = ArmijoBacktrack(...
                  x,t,d,f,f,g,gtd,c1,max(0,min(LS-2,2)),tolX,debug,doPlot,saveHessianComp,...
                  funObj,varargin{:});
            end
            funEvals = funEvals + armijoFunEvals;
            return;
        end
    end

    if f_new > f + c1*t*gtd || (LSiter > 1 && f_new >= f_prev)
        bracket = [t_prev t];
        bracketFval = [f_prev f_new];
        bracketGval = [g_prev g_new];
        break;
    elseif abs(gtd_new) <= -c2*gtd
        bracket = t;
        bracketFval = f_new;
        bracketGval = g_new;
        done = 1;
        break;
    elseif gtd_new >= 0
        bracket = [t_prev t];
        bracketFval = [f_prev f_new];
        bracketGval = [g_prev g_new];
        break;
    end
    temp = t_prev;
    t_prev = t;
    minStep = t + 0.01*(t-temp);
    maxStep = t*10;
    if LS == 3
        if debug
            fprintf('Extending Braket\n');
        end
        t = maxStep;
    elseif LS ==4
        if debug
            fprintf('Cubic Extrapolation\n');
        end
        t = polyinterp([temp f_prev gtd_prev; t f_new gtd_new],doPlot,minStep,maxStep);
    else
        t = mixedExtrap(temp,f_prev,gtd_prev,t,f_new,gtd_new,minStep,maxStep,debug,doPlot);
    end

    f_prev = f_new;
    g_prev = g_new;
    gtd_prev = gtd_new;
    if ~saveHessianComp && nargout == 5
        [f_new,g_new,H] = funObj(x + t*d,varargin{:});
    else
        [f_new,g_new] = funObj(x + t*d,varargin{:});
    end
    funEvals = funEvals + 1;
    gtd_new = g_new'*d;
    LSiter = LSiter+1;
end

if LSiter == maxLS
    bracket = [0 t];
    bracketFval = [f f_new];
    bracketGval = [g g_new];
end

%% Zoom Phase

% We now either have a point satisfying the criteria, or a bracket
% surrounding a point satisfying the criteria
% Refine the bracket until we find a point satisfying the criteria
insufProgress = 0;
Tpos = 2;
LOposRemoved = 0;
while ~done && LSiter < maxLS

    % Find High and Low Points in bracket
    [f_LO LOpos] = min(bracketFval);
    HIpos = -LOpos + 3;

    % Compute new trial value
    if LS == 3 || ~isLegal(bracketFval) || ~isLegal(bracketGval)
        if debug
            fprintf('Bisecting\n');
        end
        t = mean(bracket);
    elseif LS == 4
        if debug
            fprintf('Grad-Cubic Interpolation\n');
        end
        t = polyinterp([bracket(1) bracketFval(1) bracketGval(:,1)'*d
            bracket(2) bracketFval(2) bracketGval(:,2)'*d],doPlot);
    else
        % Mixed Case %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        nonTpos = -Tpos+3;
        if LOposRemoved == 0
            oldLOval = bracket(nonTpos);
            oldLOFval = bracketFval(nonTpos);
            oldLOGval = bracketGval(:,nonTpos);
        end
        t = mixedInterp(bracket,bracketFval,bracketGval,d,Tpos,oldLOval,oldLOFval,oldLOGval,debug,doPlot);
    end

    % Test that we are making sufficient progress
    if min(max(bracket)-t,t-min(bracket))/(max(bracket)-min(bracket)) < 0.1
        if debug
            fprintf('Interpolation close to boundary');
        end
        if insufProgress || t>=max(bracket) || t <= min(bracket)
            if debug
                fprintf(', Evaluating at 0.1 away from boundary\n');
            end
            if abs(t-max(bracket)) < abs(t-min(bracket))
                t = max(bracket)-0.1*(max(bracket)-min(bracket));
            else
                t = min(bracket)+0.1*(max(bracket)-min(bracket));
            end
            insufProgress = 0;
        else
            if debug
                fprintf('\n');
            end
            insufProgress = 1;
        end
    else
        insufProgress = 0;
    end

    % Evaluate new point
    if ~saveHessianComp && nargout == 5
        [f_new,g_new,H] = funObj(x + t*d,varargin{:});
    else
        [f_new,g_new] = funObj(x + t*d,varargin{:});
    end
    funEvals = funEvals + 1;
    gtd_new = g_new'*d;
    LSiter = LSiter+1;

    if f_new > f + c1*t*gtd || f_new >= f_LO
        % Armijo condition not satisfied or not lower than lowest
        % point
        bracket(HIpos) = t;
        bracketFval(HIpos) = f_new;
        bracketGval(:,HIpos) = g_new;
        Tpos = HIpos;
    else
        if abs(gtd_new) <= - c2*gtd
            % Wolfe conditions satisfied
            done = 1;
        elseif gtd_new*(bracket(HIpos)-bracket(LOpos)) >= 0
            % Old HI becomes new LO
            bracket(HIpos) = bracket(LOpos);
            bracketFval(HIpos) = bracketFval(LOpos);
            bracketGval(:,HIpos) = bracketGval(:,LOpos);
            if LS == 5
                if debug
                    fprintf('LO Pos is being removed!\n');
                end
                LOposRemoved = 1;
                oldLOval = bracket(LOpos);
                oldLOFval = bracketFval(LOpos);
                oldLOGval = bracketGval(:,LOpos);
            end
        end
        % New point becomes new LO
        bracket(LOpos) = t;
        bracketFval(LOpos) = f_new;
        bracketGval(:,LOpos) = g_new;
        Tpos = LOpos;
    end

    if sum(abs(bracket(1)-bracket(2))*gtd_new) < tolX
        if debug
            fprintf('Line Search can not make further progress\n');
        end
        break;
    end

end

%%
if LSiter == maxLS
    if debug
        fprintf('Line Search Exceeded Maximum Line Search Iterations\n');
    end
end

[f_LO LOpos] = min(bracketFval);
t = bracket(LOpos);
f_new = bracketFval(LOpos);
g_new = bracketGval(:,LOpos);

% Evaluate Hessian at new point
if nargout == 5 && funEvals > 1 && saveHessianComp
    [f_new,g_new,H] = funObj(x + t*d,varargin{:});
    funEvals = funEvals + 1;
end

end

%%
function [t] = mixedExtrap(x0,f0,g0,x1,f1,g1,minStep,maxStep,debug,doPlot);
alpha_c = polyinterp([x0 f0 g0; x1 f1 g1],doPlot,minStep,maxStep);
alpha_s = polyinterp([x0 f0 g0; x1 sqrt(-1) g1],doPlot,minStep,maxStep);
if alpha_c > minStep && abs(alpha_c - x1) < abs(alpha_s - x1)
    if debug
        fprintf('Cubic Extrapolation\n');
    end
    t = alpha_c;
else
    if debug
        fprintf('Secant Extrapolation\n');
    end
    t = alpha_s;
end
end

%%
function [t] = mixedInterp(bracket,bracketFval,bracketGval,d,Tpos,oldLOval,oldLOFval,oldLOGval,debug,doPlot);

% Mixed Case %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
nonTpos = -Tpos+3;

gtdT = bracketGval(:,Tpos)'*d;
gtdNonT = bracketGval(:,nonTpos)'*d;
oldLOgtd = oldLOGval'*d;
if bracketFval(Tpos) > oldLOFval
    alpha_c = polyinterp([oldLOval oldLOFval oldLOgtd
        bracket(Tpos) bracketFval(Tpos) gtdT],doPlot);
    alpha_q = polyinterp([oldLOval oldLOFval oldLOgtd
        bracket(Tpos) bracketFval(Tpos) sqrt(-1)],doPlot);
    if abs(alpha_c - oldLOval) < abs(alpha_q - oldLOval)
        if debug
            fprintf('Cubic Interpolation\n');
        end
        t = alpha_c;
    else
        if debug
            fprintf('Mixed Quad/Cubic Interpolation\n');
        end
        t = (alpha_q + alpha_c)/2;
    end
elseif gtdT'*oldLOgtd < 0
    alpha_c = polyinterp([oldLOval oldLOFval oldLOgtd
        bracket(Tpos) bracketFval(Tpos) gtdT],doPlot);
    alpha_s = polyinterp([oldLOval oldLOFval oldLOgtd
        bracket(Tpos) sqrt(-1) gtdT],doPlot);
    if abs(alpha_c - bracket(Tpos)) >= abs(alpha_s - bracket(Tpos))
        if debug
            fprintf('Cubic Interpolation\n');
        end
        t = alpha_c;
    else
        if debug
            fprintf('Quad Interpolation\n');
        end
        t = alpha_s;
    end
elseif abs(gtdT) <= abs(oldLOgtd)
    alpha_c = polyinterp([oldLOval oldLOFval oldLOgtd
        bracket(Tpos) bracketFval(Tpos) gtdT],...
        doPlot,min(bracket),max(bracket));
    alpha_s = polyinterp([oldLOval sqrt(-1) oldLOgtd
        bracket(Tpos) bracketFval(Tpos) gtdT],...
        doPlot,min(bracket),max(bracket));
    if alpha_c > min(bracket) && alpha_c < max(bracket)
        if abs(alpha_c - bracket(Tpos)) < abs(alpha_s - bracket(Tpos))
            if debug
                fprintf('Bounded Cubic Extrapolation\n');
            end
            t = alpha_c;
        else
            if debug
                fprintf('Bounded Secant Extrapolation\n');
            end
            t = alpha_s;
        end
    else
        if debug
            fprintf('Bounded Secant Extrapolation\n');
        end
        t = alpha_s;
    end

    if bracket(Tpos) > oldLOval
        t = min(bracket(Tpos) + 0.66*(bracket(nonTpos) - bracket(Tpos)),t);
    else
        t = max(bracket(Tpos) + 0.66*(bracket(nonTpos) - bracket(Tpos)),t);
    end
else
    t = polyinterp([bracket(nonTpos) bracketFval(nonTpos) gtdNonT
        bracket(Tpos) bracketFval(Tpos) gtdT],doPlot);
end
end

%%
function [legal] = isLegal(v)
legal = sum(any(imag(v(:))))==0 & sum(isnan(v(:)))==0 & sum(isinf(v(:)))==0;
end


function B=shiftmat(A,n,dim,pad)
%SHIFTMAT  Shift matrix along specified dimension.
%   SHIFTMAT(X), returns X.
%   SHIFTMAT(X,N), moves elements in matrix X with N steps. The trailing
%      elements becomes zeros. Shifting will be done row-wise.
%      Positive N will mean that elements are moved towards higher
%      row indicies. First row will be filled with zeros,
%      aso. Negative N will make the elements move upwards towards
%      lower row indicies. Last row will be filled with zeros,
%      aso. If N is zero or empty, no shifting will occur
%      and X will be returned.
%   SHIFTMAT(X,N,DIM), shifts matrix elements along dimension DIM.
%      If DIM is a singleton dimension, X will be returned.
%      Likewise if DIM < 1 or DIM > ndims(X), nothing will happen.
%      N must be scalar valued.
%   SHIFTMAT(X,N,DIM,PAD), uses PAD to pad the trailing elements with
%      another value rather than zeros.
%      PAD must be scalar valued.
%
%   Examples:
%      X=rand(3,3,3)          %X is 3x3x3.
%      shiftmat(X,1)          %shifts one step down.
%      shiftmat(X,-2)         %shifts two steps up.
%      shiftmat(X,1,2)        %shifts ones step right.
%      shiftmat(X,1,3)        %shifts one step "down" along 3:rd dimension.
%      shiftmat(X,-2,2,NaN)   %shifts two steps left with trailing NaNs.
%
%   See also DELMAT, INSMAT, ROTMAT, REPMAT, RESHAPE, FLIPDIM.

% Copyright (c) 2003-10-28, B. Rasmus Anthin.
% Revision 2003-10-29.
% GPL license, freeware.

error(nargchk(1,4,nargin))
if nargin<2, n=0;end                    %do nothing
if isempty(n), n=0;end
if prod(size(n))~=1, error('N must be a scalar.'),end
n=round(n);
if nargin<3, dim=1;end                  %rotate row vectors
if dim<1, dim=ndims(A)+1;end            %if less than one, do nothing
if nargin<4, pad=0;end                  %trailing elements are zeros as default
if prod(size(pad))~=1, error('PAD must be a scalar.'),end
dims=[dim:max(ndims(A),dim) 1:dim-1];
if dims(1)<=ndims(A) & n
   A=permute(A,dims);                             %move dimension to front
   sizA=size(A);                                  %get dimension sizes
   A=reshape(A,[sizA(1) prod(sizA(2:end))]);      %reshape to a 2-D matrix
   idx=1:sizA(1);                                 %the row indices
   if n<0
      idx=idx(1-n:end);                           %remove low valued indices
      B=A(idx,:);                                 %truncate matrix
      B=[B;pad*ones(min(-n,sizA(1)),prod(sizA(2:end)))];    %pad with zeros (or PAD)
   elseif n>0
      idx=idx(1:end-n);                           %remove high valued indices
      B=A(idx,:);                                 %truncate matrix
      B=[pad*ones(min(n,sizA(1)),prod(sizA(2:end)));B];     %pad with zeros (or PAD)
   end
   B=reshape(B,[size(B,1) sizA(2:end)]);          %back to previous shape minus removed vectors
   B=ipermute(B,dims);                            %replace dimensions to initial location
else
   B=A;
end


function lambda = rutis5_eigenvalues ( )

%*****************************************************************************80
%
%% RUTIS5_EIGENVALUES returns the eigenvalues of the RUTIS5 matrix.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    20 October 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, real LAMBDA(4,1), the eigenvalues.
%
  n = 4;
  lambda = zeros ( n, 1 );

  lambda(1:4,1) = [ ...
    19.122479087555860; ...
    10.882816916492464; ...
     8.994169735037230; ...
     0.000534260914449 ];

  return
end


function [ a, b ] = p26_lim ( )

%*****************************************************************************80
%
%% P26_LIM returns the integration limits for problem 26.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 November 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, real A, B, the limits of integration.
%
  a = 0.0;
  b = 2.0 * pi;

  return
end


function out=factorial(x)

precision=x(1).precision;
out_rval=cell(size(x));
out_ival=cell(size(x));

for ii=1:numel(x)
 imag=false;
 [xrval,xival]=getVals(x,ii);
 if hasimag(xival), imag=true; end
 if imag
  error('Factorial must be on nonegative integers');
 else
  out_rval{ii}=mpfr_factorial(precision,xrval);
 end
end % for ii=1:max(ex,
out=class(struct('rval',out_rval,...
                  'ival',out_ival,...
                  'precision',precision),'mp');


classdef CEC2010_F6 < PROBLEM
% <single> <real> <constrained>
% CEC'2010 constrained optimization benchmark problem

%------------------------------- Reference --------------------------------
% R. Mallipeddi and P. N. Suganthan, Problem definitions and evaluation
% criteria for the CEC 2010 competition on constrained real-parameter
% optimization, Nanyang Technological University, Singapore, 2010.
%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

    properties
        O;      % Optimal decision vector
        Mat;	% Rotation matrix
    end
    methods
        %% Default settings of the problem
        function Setting(obj)
            CallStack = dbstack('-completenames');
            load(fullfile(fileparts(CallStack(1).file),'CEC2010.mat'),'Data');
            obj.O = Data{6}.O;
            obj.M = 1;
            if isempty(obj.D) || obj.D < 30
                obj.D   = 10;
                obj.Mat = Data{6}.M_10;
            else
                obj.D   = 30;
                obj.Mat = Data{6}.M_30;
            end
            if isempty(obj.D); obj.D = 10; end
            obj.D = min(obj.D,length(obj.O));
            obj.lower    = zeros(1,obj.D) - 600;
            obj.upper    = zeros(1,obj.D) + 600;
            obj.encoding = ones(1,obj.D);
        end
        %% Calculate objective values
        function PopObj = CalObj(obj,PopDec)
            Z = PopDec - repmat(obj.O(1:size(PopDec,2)),size(PopDec,1),1);
            PopObj = max(Z,[],2);
        end
        %% Calculate constraint violations
        function PopCon = CalCon(obj,PopDec)
            Z = PopDec - repmat(obj.O(1:size(PopDec,2)),size(PopDec,1),1);
            Y = (Z+483.6106)*obj.Mat - 483.6106;
            PopCon(:,1) = abs(mean((-Y.*sin(sqrt(abs(Y)))),2)) - 1e-4;
            PopCon(:,2) = abs(mean((-Y.*cos(0.5*sqrt(abs(Y)))),2)) - 1e-4;
        end
    end
end


classdef X2kKernel < Kernel
    % Object of type kernel but optimized for log so that the computation of the
    % radial quadrature goes faster
    properties (Access = public)
        C = 1;
        k = 1; % such that G(r) =C*r^(2*k)
    end

    methods
      	function[kernel] = X2kKernel(kk,CC)
            if nargin == 0
                kk = 1;
            end
            if nargin <= 1
                CC = 1;
            end
            kernel@Kernel(@(x)(CC*x.^(2*kk)),@(x)(2*kk*CC*x.^(2*kk - 1)))
            kernel.scalFunc = @(a,b,rho)(CC*X2kSP([a,b],rho,kk));
            kernel.normFunc = @(a,b)(abs(CC)*sqrt(2*pi*4*kk^2/(4*kk - 1)*(b^(4*kk - 1) - a^(4*kk- 1))));
            kernel.gamma_est = @X2kKernel.gamma_est;
            kernel.k = kk;
            kernel.C = CC;
            kernel.singular = false;
        end
    end
    methods (Access = public)
        function[out] = dilatation(this,lambda)
            out = X2kKernel(this.k,lambda^(2*this.k));
            % No changes in gamma_est, scalFunc nor normFunc
        end
        function[out] = mtimes(this,mu)
            if isa(this,'Kernel')
                assert(and(isa(mu,'double'),isscalar(mu)));
                out = X2kKernel(this.k,mu*this.C);
            else
                out = mtimes(mu,this);
            end
        end
        function[out] = radialQuadKernel(this,a,tol,varargin)
            Cmem = this.C;
            this = (1/Cmem)*this;
            rq = RadialQuadrature(a,this,tol/abs(Cmem),varargin{:});
            out = Cmem*rq;
        end
    end
    methods (Access = protected)

    end
    methods (Static, Access = protected)
        function[low,up] = gamma_est(~)
            % Helps the radial quadrature to guess the number of components
            up = 4;
            low= 0;
        end
    end

end


function test_ft_componentanalysis_methods

% MEM 2gb
% WALLTIME 00:10:00
% DEPENDENCY ft_componentanalysis ft_rejectcomponent ft_checkdata runica fastica sobi jader dss parafac

% note 3) binica does not run on all computers, which is why it is disabled
% note 9) parafac depends on an external toolbox, which I don't have access to at the moment

% construct a simple and minimalistic raw data representation
nchan  = 10;
ntime  = 1000;
ntrial = 5;
data = [];
data.fsample = 1;
for i=1:nchan
  data.label{i} = sprintf('chan%d', i);
end
for i=1:ntrial
  data.trial{i} = sqrt(abs(randn(nchan,ntime)));
  data.time{i} = 1:ntime;
end

% run the decomposition with various methods
cfg = [];
cfg.method = 'fastica';
comp1f = ft_componentanalysis(cfg, data);
cfg.numcomponent = nchan-1;
comp1s = ft_componentanalysis(cfg, data);

cfg = [];
cfg.method = 'runica';
cfg.runica.maxsteps = 50;
comp2f = ft_componentanalysis(cfg, data);
cfg.numcomponent = nchan-1;
comp2s = ft_componentanalysis(cfg, data);

% cfg = [];
% cfg.method = 'binica';
% comp3f = ft_componentanalysis(cfg, data);
% cfg.numcomponent = nchan-1;
% comp3s = ft_componentanalysis(cfg, data);

cfg = [];
cfg.method = 'jader';
comp4f = ft_componentanalysis(cfg, data);
cfg.numcomponent = nchan-1;
comp4s = ft_componentanalysis(cfg, data);

cfg = [];
cfg.method = 'varimax';
comp5f = ft_componentanalysis(cfg, data);
cfg.numcomponent = nchan-1;
comp5s = ft_componentanalysis(cfg, data);

cfg = [];
cfg.method = 'cca';
comp6f = ft_componentanalysis(cfg, data);
cfg.numcomponent = nchan-1;
comp6s = ft_componentanalysis(cfg, data);

cfg = [];
cfg.method = 'pca';
comp7f = ft_componentanalysis(cfg, data);
cfg.numcomponent = nchan-1;
comp7s = ft_componentanalysis(cfg, data);

cfg = [];
cfg.method = 'svd';
comp8f = ft_componentanalysis(cfg, data);
cfg.numcomponent = nchan-1;
comp8s = ft_componentanalysis(cfg, data);

% cfg = [];
% cfg.method = 'parafac';
% comp9f = ft_componentanalysis(cfg, data);
% cfg.numcomponent = nchan-1;
% comp9s = ft_componentanalysis(cfg, data);

cfg = [];
cfg.method = 'dss';
comp10f = ft_componentanalysis(cfg, data);
cfg.numcomponent = nchan-1;
comp10s = ft_componentanalysis(cfg, data);

cfg = [];
cfg.method = 'sobi';
comp11f = ft_componentanalysis(cfg, data);
cfg.numcomponent = nchan-1;
comp11s = ft_componentanalysis(cfg, data);

% reproject the data to the channel level
cfg = [];
[dataout] = ft_rejectcomponent(cfg, comp1f);
[dataout] = ft_rejectcomponent(cfg, comp2f);
% [dataout] = ft_rejectcomponent(cfg, comp3f);
[dataout] = ft_rejectcomponent(cfg, comp4f);
[dataout] = ft_rejectcomponent(cfg, comp5f);
[dataout] = ft_rejectcomponent(cfg, comp6f);
[dataout] = ft_rejectcomponent(cfg, comp7f);
[dataout] = ft_rejectcomponent(cfg, comp8f);
% [dataout] = ft_rejectcomponent(cfg, comp9f);
[dataout] = ft_rejectcomponent(cfg, comp10f);
[dataout] = ft_rejectcomponent(cfg, comp11f);

cfg = [];
[dataout] = ft_rejectcomponent(cfg, comp1s);
[dataout] = ft_rejectcomponent(cfg, comp2s);
% [dataout] = ft_rejectcomponent(cfg, comp3s);
[dataout] = ft_rejectcomponent(cfg, comp4s);
[dataout] = ft_rejectcomponent(cfg, comp5s);
[dataout] = ft_rejectcomponent(cfg, comp6s);
[dataout] = ft_rejectcomponent(cfg, comp7s);
[dataout] = ft_rejectcomponent(cfg, comp8s);
% [dataout] = ft_rejectcomponent(cfg, comp9s);
[dataout] = ft_rejectcomponent(cfg, comp10s);
[dataout] = ft_rejectcomponent(cfg, comp11s);

cfg = [];
cfg.component = [1 3];
[dataout] = ft_rejectcomponent(cfg, comp1f);
[dataout] = ft_rejectcomponent(cfg, comp2f);
% [dataout] = ft_rejectcomponent(cfg, comp3f);
[dataout] = ft_rejectcomponent(cfg, comp4f);
[dataout] = ft_rejectcomponent(cfg, comp5f);
[dataout] = ft_rejectcomponent(cfg, comp6f);
[dataout] = ft_rejectcomponent(cfg, comp7f);
[dataout] = ft_rejectcomponent(cfg, comp8f);
% [dataout] = ft_rejectcomponent(cfg, comp9f);
[dataout] = ft_rejectcomponent(cfg, comp10f);
[dataout] = ft_rejectcomponent(cfg, comp11f);

cfg = [];
cfg.component = [1 3];
[dataout] = ft_rejectcomponent(cfg, comp1s);
[dataout] = ft_rejectcomponent(cfg, comp2s);
% [dataout] = ft_rejectcomponent(cfg, comp3s);
[dataout] = ft_rejectcomponent(cfg, comp4s);
[dataout] = ft_rejectcomponent(cfg, comp5s);
[dataout] = ft_rejectcomponent(cfg, comp6s);
[dataout] = ft_rejectcomponent(cfg, comp7s);
[dataout] = ft_rejectcomponent(cfg, comp8s);
% [dataout] = ft_rejectcomponent(cfg, comp9s);
[dataout] = ft_rejectcomponent(cfg, comp10s);
[dataout] = ft_rejectcomponent(cfg, comp11s);

% perform some checks on the decomposed data properties
assert(length(comp1f.label)==nchan);
assert(length(comp2f.label)==nchan);
% assert(length(comp3f.label)==nchan);
assert(length(comp4f.label)==nchan);
assert(length(comp5f.label)==nchan);
assert(length(comp6f.label)==nchan);
assert(length(comp7f.label)==nchan);
assert(length(comp8f.label)==nchan);
assert(length(comp8f.label)==nchan);
% assert(length(comp9f.label)==nchan);
assert(length(comp10f.label)==nchan);
assert(length(comp11f.label)==nchan);

% see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=903
assert(length(comp1s.label)==nchan-1);
assert(length(comp2s.label)==nchan-1);
% assert(length(comp3s.label)==nchan);
assert(length(comp4s.label)==nchan-1);
assert(length(comp5s.label)==nchan-1);
assert(length(comp6s.label)==nchan-1);
assert(length(comp7s.label)==nchan-1);
assert(length(comp8s.label)==nchan-1);
% assert(length(comp9s.label)==nchan-1);
assert(length(comp10s.label)==nchan-1);
assert(length(comp11s.label)==nchan-1);


% Gps
p_drone.sd_gps_pn = 0.21; % standard deviation (sd)
p_drone.sd_gps_pe = 0.21;
p_drone.sd_gps_ph = 0.4;

p_drone.sd_gps_vn = 0.05; % standard deviation (sd)
p_drone.sd_gps_ve = 0.05;
p_drone.sd_gps_vh = 0.01;
p_drone.Ts_gps = 1; % [s]
p_drone.k_gps = 1/1100;

% Gyroscope
p_drone.sd_gyro = deg2rad(0.13); % standard deviation (sd) [deg/s]

% Acceleration
p_drone.sd_accel = 0.0025*p_physics.gravity; % standard deviation (sd) [m/s^2]

% Pressure
p_drone.pres0 = 101325; % static pressure at sea level    [Pa]
p_drone.sd_static_pres = 10; % standard deviation (sd)    [Pa]
p_drone.sd_diff_pres = 2; % standard deviation (sd)       [Pa]

p_drone.bias_gyro_x = 0.01;
p_drone.bias_gyro_y = 0.01;
p_drone.bias_gyro_z = 0.01;

p_drone.a_gyro            = 0.1;
p_drone.a_static_pres     = 0.1;
p_drone.a_diff_pres       = 0.5;
p_drone.a_accel           = 0.1;
p_drone.a_gps_speed       = 0;
p_drone.a_gps_pos         = 0;

p_drone.Q = [ p_drone.sd_gyro^2, 0;...
        0,           p_drone.sd_gyro^2];

p_drone.R = ([ p_drone.sd_accel, 0,          0;...
        0,           p_drone.sd_accel, 0;...
        0,           0,          p_drone.sd_accel]).^2;

p_drone.b_chidot  = 1.2;
p_drone.b_chi     = 1;
p_drone.b_hdot    = 1.7;
p_drone.b_h       = 1.7;
p_drone.b_Va      = 8;
p_drone.gamma_max = 10;

p_drone.bias_gyro_x = 0;
p_drone.bias_gyro_y = 0;
p_drone.bias_gyro_z = 0;


%dir=0 -> q=qab (vb=Cab*va)
%dir=1 -> q=qba (vb=Cba'*va)
function vb=quatrot(qab,va,dir)

va=[0;va(1);va(2);va(3)];
if dir==0
    q=qab;
else
    q=qab;
    q(2:4)=-q(2:4);
end
vr_a=quatmult_v001(q,va,0);
q(2:4)=-q(2:4);
vb=quatmult_v001(vr_a,q,0);
vb=vb(2:4);


function [Cyy] = global2localCov(Cxx, X)

% SYNTAX:
%   [Cyy] = global2localCov(Cxx, X);
%
% INPUT:
%   Cxx = input covariance matrices
%   X   = position vectors
%
% OUTPUT:
%   Cyy = output covariance matrices
%
% DESCRIPTION:
%   Covariance propagation from Earth-fixed reference frame to local-level reference frame

%--- * --. --- --. .--. ... * ---------------------------------------------
%               ___ ___ ___
%     __ _ ___ / __| _ | __|
%    / _` / _ \ (_ |  _|__ \
%    \__, \___/\___|_| |___/
%    |___/                    v 1.0RC1
%
%--------------------------------------------------------------------------
%  Copyright (C) 2021 Geomatics Research & Development srl (GReD)
%  Written by:
%  Contributors:     ...
%  A list of all the historical goGPS contributors is in CREDITS.nfo
%--------------------------------------------------------------------------
%
%   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/>.
%
%--------------------------------------------------------------------------
% 01100111 01101111 01000111 01010000 01010011
%--------------------------------------------------------------------------

%initialize new covariance matrices
Cyy = zeros(size(Cxx));

for i = 1 : size(X,2)

    %geodetic coordinates
    [phi, lam] = cart2geod(X(1,i), X(2,i), X(3,i));

    %rotation matrix from global to local reference system
    R = [-sin(lam) cos(lam) 0;
         -sin(phi)*cos(lam) -sin(phi)*sin(lam) cos(phi);
         +cos(phi)*cos(lam) +cos(phi)*sin(lam) sin(phi)];

    %covariance propagation
    Cyy(:,:,i) = R * Cxx(:,:,i) * R';
end

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


%

function [f, df] = sampleEijOpt_6(x)
% optimization code for six wall case

% param
vert = x(6:11);
w_res = x(12);

x0 = x(1); y0 = x(2); % camera center
yc = x(3); % corner
xd = x(4);
yf = x(5);

% assume vertical lines are fixed
a_aob = (vert(2) - vert (1))/w_res*2*pi;
a_boc = (vert(3) - vert (2))/w_res*2*pi;
a_cod = (vert(4) - vert (3))/w_res*2*pi;
a_doe = (vert(5) - vert (4))/w_res*2*pi;
a_eof = (vert(6) - vert (5))/w_res*2*pi;
a_foa = (vert(1) + w_res - vert (6))/w_res*2*pi;

% energy
v_ao  = [x0 y0]; v_bo = [x0-1 y0]; v_co = [x0-1 y0 - yc];
v_do = [x0-xd y0-yc];  v_eo = [x0-xd y0-yf]; v_fo = [x0 y0-yf];

n_v_ao = norm(v_ao); n_v_bo = norm(v_bo); n_v_co = norm(v_co);
n_v_do = norm(v_do); n_v_eo = norm(v_eo); n_v_fo = norm(v_fo);

b_aob = acos(dot(v_ao, v_bo)/n_v_ao/n_v_bo);
if det([v_ao;v_bo]) < 0
    b_aob = 2*pi - b_aob;
end
b_boc = acos(dot(v_bo, v_co)/n_v_bo/n_v_co);
if det([v_bo;v_co]) < 0
    b_boc = 2*pi - b_boc;
end
b_cod = acos(dot(v_co, v_do)/n_v_co/n_v_do);
if det([v_co;v_do]) < 0
    b_cod = 2*pi - b_cod;
end
b_doe = acos(dot(v_do, v_eo)/n_v_do/n_v_eo);
if det([v_do;v_eo]) < 0
    b_doe = 2*pi - b_doe;
end
b_eof = acos(dot(v_eo, v_fo)/n_v_eo/n_v_fo);
if det([v_eo;v_fo]) < 0
    b_eof = 2*pi - b_eof;
end
b_foa = acos(dot(v_fo, v_ao)/n_v_fo/n_v_ao);
if det([v_fo;v_ao]) < 0
    b_foa = 2*pi - b_foa;
end

f = (b_aob - a_aob)^2 + (b_boc - a_boc)^2 + (b_cod - a_cod)^2 + ...
    (b_doe - a_doe)^2 + (b_eof - a_eof)^2 + (b_foa - a_foa)^2;

% gradient
% x0
d_aob_x0 = (2*x0-1)*n_v_ao*n_v_bo + dot(v_ao, v_bo) * (x0*n_v_bo/n_v_ao + (x0-1)*n_v_ao/n_v_bo);
d_aob_x0 = d_aob_x0 * (-1/(sqrt(1-cos(b_aob)*cos(b_aob))+eps))/n_v_ao/n_v_ao/n_v_bo/n_v_bo;
if det([v_ao;v_bo]) < 0
    d_aob_x0 = -d_aob_x0;
end
d_aob_x0 = 2*(b_aob - a_aob) * d_aob_x0;

d_boc_x0 = 2*(x0-1)*n_v_bo*n_v_co + dot(v_bo, v_co) * ((x0-1)*n_v_co/n_v_bo + (x0-1)*n_v_bo/n_v_co);
d_boc_x0 = d_boc_x0 * (-1/(sqrt(1-cos(b_boc)*cos(b_boc))+eps))/n_v_bo/n_v_bo/n_v_co/n_v_co;
if det([v_bo;v_co]) < 0
    d_boc_x0 = -d_boc_x0;
end
d_boc_x0 = 2*(b_boc - a_boc) * d_boc_x0;

d_cod_x0 = (2*x0-xd-1)*n_v_co*n_v_do + dot(v_co, v_do) * ((x0-1)*n_v_do/n_v_co + (x0-xd)*n_v_co/n_v_do);
d_cod_x0 = d_cod_x0 * (-1/(sqrt(1-cos(b_cod)*cos(b_cod))+eps))/n_v_co/n_v_co/n_v_do/n_v_do;
if det([v_co;v_do]) < 0
    d_cod_x0 = -d_cod_x0;
end
d_cod_x0 = 2*(b_cod - a_cod) * d_cod_x0;

d_doe_x0 = 2*(x0-xd)*n_v_do*n_v_eo + dot(v_do, v_eo) * ((x0-xd)*n_v_eo/n_v_do + (x0-xd)*n_v_do/n_v_eo);
d_doe_x0 = d_doe_x0 * (-1/(sqrt(1-cos(b_doe)*cos(b_doe))+eps))/n_v_do/n_v_do/n_v_eo/n_v_eo;
if det([v_do;v_eo]) < 0
    d_doe_x0 = -d_doe_x0;
end
d_doe_x0 = 2*(b_doe - a_doe) * d_doe_x0;

d_eof_x0 = (2*x0-xd)*n_v_eo*n_v_fo + dot(v_eo, v_fo) * ((x0-xd)*n_v_fo/n_v_eo + x0*n_v_eo/n_v_fo);
d_eof_x0 = d_eof_x0 * (-1/(sqrt(1-cos(b_eof)*cos(b_eof))+eps))/n_v_eo/n_v_eo/n_v_fo/n_v_fo;
if det([v_eo;v_fo]) < 0
    d_eof_x0 = -d_eof_x0;
end
d_eof_x0 = 2*(b_eof - a_eof) * d_eof_x0;

d_foa_x0 = 2*x0*n_v_fo*n_v_ao + dot(v_fo, v_ao) * (x0*n_v_ao/n_v_fo + x0*n_v_fo/n_v_ao);
d_foa_x0 = d_foa_x0 * (-1/(sqrt(1-cos(b_foa)*cos(b_foa))+eps))/n_v_fo/n_v_fo/n_v_ao/n_v_ao;
if det([v_fo;v_ao]) < 0
    d_foa_x0 = -d_foa_x0;
end
d_foa_x0 = 2*(b_foa - a_foa) * d_foa_x0;

% y0
d_aob_y0 = 2*y0*n_v_ao*n_v_bo + dot(v_ao, v_bo) * (y0*n_v_bo/n_v_ao + y0*n_v_ao/n_v_bo);
d_aob_y0 = d_aob_y0 * (-1/(sqrt(1-cos(b_aob)*cos(b_aob))+eps))/n_v_ao/n_v_ao/n_v_bo/n_v_bo;
if det([v_ao;v_bo]) < 0
    d_aob_y0 = -d_aob_y0;
end
d_aob_y0 = 2*(b_aob - a_aob) * d_aob_y0;

d_boc_y0 = (2*y0-yc)*n_v_bo*n_v_co + dot(v_bo, v_co) * (y0*n_v_co/n_v_bo + (y0-yc)*n_v_bo/n_v_co );
d_boc_y0 = d_boc_y0 * (-1/(sqrt(1-cos(b_boc)*cos(b_boc))+eps))/n_v_bo/n_v_bo/n_v_co/n_v_co;
if det([v_bo;v_co]) < 0
    d_boc_y0 = -d_boc_y0;
end
d_boc_y0 = 2*(b_boc - a_boc) * d_boc_y0;

d_cod_y0 = 2*(y0-yc)*n_v_co*n_v_do + dot(v_co, v_do) * ((y0-yc)/n_v_co*n_v_do + (y0-yc)/n_v_do*n_v_co);
d_cod_y0 = d_cod_y0 * (-1/(sqrt(1-cos(b_cod)*cos(b_cod))+eps))/n_v_co/n_v_co/n_v_do/n_v_do;
if det([v_co;v_do]) < 0
    d_cod_y0 = -d_cod_y0;
end
d_cod_y0 = 2*(b_cod - a_cod) * d_cod_y0;

d_doe_y0 = (2*y0-yf-yc)*n_v_do*n_v_eo + dot(v_do, v_eo)*((y0-yc)/n_v_do*n_v_eo + (y0-yf)/n_v_eo*n_v_do);
d_doe_y0 = d_doe_y0 * (-1/(sqrt(1-cos(b_doe)*cos(b_doe))+eps))/n_v_do/n_v_do/n_v_eo/n_v_eo;
if det([v_do;v_eo]) < 0
    d_doe_y0 = -d_doe_y0;
end
d_doe_y0 = 2*(b_doe - a_doe) * d_doe_y0;

d_eof_y0 = 2*(y0-yf)*n_v_eo*n_v_fo + dot(v_eo, v_fo)*((y0-yf)/n_v_eo*n_v_fo + (y0-yf)/n_v_fo*n_v_eo);
d_eof_y0 = d_eof_y0 * (-1/(sqrt(1-cos(b_eof)*cos(b_eof))+eps))/n_v_eo/n_v_eo/n_v_fo/n_v_fo;
if det([v_eo;v_fo]) < 0
    d_eof_y0 = -d_eof_y0;
end
d_eof_y0 = 2*(b_eof - a_eof) * d_eof_y0;

d_foa_y0 = (2*y0-yf)*n_v_fo*n_v_ao + dot(v_fo, v_ao)*((y0-yf)/n_v_fo*n_v_ao + y0/n_v_ao*n_v_fo);
d_foa_y0 = d_foa_y0 * (-1/(sqrt(1-cos(b_foa)*cos(b_foa))+eps))/n_v_fo/n_v_fo/n_v_ao/n_v_ao;
if det([v_fo;v_ao]) < 0
    d_foa_y0 = -d_foa_y0;
end
d_foa_y0 = 2*(b_foa - a_foa) * d_foa_y0;

% yc
d_boc_yc = (-y0)*n_v_bo*n_v_co + dot(v_bo, v_co) * n_v_bo* (yc-y0)/n_v_co;
d_boc_yc = d_boc_yc/n_v_bo/n_v_bo/n_v_co/n_v_co;
if det([v_bo;v_co]) < 0
    d_boc_yc = -d_boc_yc;
end
d_boc_yc = 2*(b_boc - a_boc) * d_boc_yc;

d_cod_yc = 2*(yc-y0)*n_v_co*n_v_do + dot(v_co, v_do)*((yc-y0)/n_v_co*n_v_do + (yc-y0)/n_v_do*n_v_co);
d_cod_yc = d_cod_yc * (-1/(sqrt(1-cos(b_cod)*cos(b_cod))+eps))/n_v_co/n_v_co/n_v_do/n_v_do;
if det([v_co;v_do]) < 0
    d_cod_yc = -d_cod_yc;
end
d_cod_yc = 2*(b_cod - a_cod) * d_cod_yc;

d_doe_yc = (yf-y0)*n_v_do*n_v_eo + dot(v_do, v_eo)*(yc-y0)/n_v_do*n_v_eo;
d_doe_yc = d_doe_yc * (-1/(sqrt(1-cos(b_doe)*cos(b_doe))+eps))/n_v_do/n_v_do/n_v_eo/n_v_eo;
if det([v_do;v_eo]) < 0
    d_doe_yc = -d_doe_yc;
end
d_doe_yc = 2*(b_doe - a_doe) * d_doe_yc;

% xd
d_cod_xd = (1-x0)*n_v_co*n_v_do + dot(v_co, v_do)*(xd-x0)*n_v_co/n_v_do;
d_cod_xd = d_cod_xd * (-1/(sqrt(1-cos(b_cod)*cos(b_cod))+eps))/n_v_co/n_v_co/n_v_do/n_v_do;
if det([v_co;v_do]) < 0
    d_cod_xd = -d_cod_xd;
end
d_cod_xd = 2*(b_cod - a_cod) * d_cod_xd;

d_doe_xd = 2*(xd-x0)*n_v_do*n_v_eo + dot(v_do, v_eo)*((xd-x0)/n_v_do*n_v_eo + (xd-x0)/n_v_eo*n_v_do);
d_doe_xd = d_doe_xd * (-1/(sqrt(1-cos(b_doe)*cos(b_doe))+eps))/n_v_do/n_v_do/n_v_eo/n_v_eo;
if det([v_do;v_eo]) < 0
    d_doe_xd = -d_doe_xd;
end
d_doe_xd = 2*(b_doe - a_doe) * d_doe_xd;

d_eof_xd = (-x0)*n_v_eo*n_v_fo + dot(v_eo, v_fo)*(xd-x0)/n_v_eo*n_v_fo;
d_eof_xd = d_eof_xd * (-1/(sqrt(1-cos(b_eof)*cos(b_eof))+eps))/n_v_eo/n_v_eo/n_v_fo/n_v_fo;
if det([v_eo;v_fo]) < 0
    d_eof_xd = -d_eof_xd;
end
d_eof_xd = 2*(b_eof - a_eof) * d_eof_xd;

% yf
d_doe_yf = (yc-y0)*n_v_do*n_v_eo + dot(v_do, v_eo)*(yf-y0)/n_v_eo*n_v_do;
d_doe_yf = d_doe_yf * (-1/(sqrt(1-cos(b_doe)*cos(b_doe))+eps))/n_v_do/n_v_do/n_v_eo/n_v_eo;
if det([v_do;v_eo]) < 0
    d_doe_yf = -d_doe_yf;
end
d_doe_yf = 2*(b_doe - a_doe) * d_doe_yf;

d_eof_yf = 2*(yf-y0)*n_v_eo*n_v_fo + dot(v_eo, v_fo)*((yf-y0)/n_v_eo*n_v_fo + (yf-y0)/n_v_fo*n_v_eo);
d_eof_yf = d_eof_yf * (-1/(sqrt(1-cos(b_eof)*cos(b_eof))+eps))/n_v_eo/n_v_eo/n_v_fo/n_v_fo;
if det([v_eo;v_fo]) < 0
    d_eof_yf = -d_eof_yf;
end
d_eof_yf = 2*(b_eof - a_eof) * d_eof_yf;

d_foa_yf = (-y0)*n_v_fo*n_v_ao + dot(v_fo, v_ao)*(yf-y0)/n_v_fo*n_v_ao;
d_foa_yf = d_foa_yf * (-1/(sqrt(1-cos(b_foa)*cos(b_foa))+eps))/n_v_fo/n_v_fo/n_v_ao/n_v_ao;
if det([v_fo;v_ao]) < 0
    d_foa_yf = -d_foa_yf;
end
d_foa_yf = 2*(b_foa - a_foa) * d_foa_yf;

d_x0 = d_aob_x0 + d_boc_x0 + d_cod_x0 + d_doe_x0 + d_eof_x0 + d_foa_x0;
d_y0 = d_aob_y0 + d_boc_y0 + d_cod_y0 + d_doe_y0 + d_eof_y0 + d_foa_y0;
d_yc = d_boc_yc + d_cod_yc + d_doe_yc;
d_xd = d_cod_xd + d_doe_xd + d_eof_xd;
d_yf = d_doe_yf + d_eof_yf + d_foa_yf;

df = [d_x0; d_y0; d_yc; d_xd; d_yf; 0; 0; 0; 0; 0;0;0];


function [c,mx,my] = covc(x, y, dim)

if nargin==2,
  dim = y;
  y   = x;
end

if dim==1,
  c  = x'*y;
elseif dim==2,
  c = x*y';
end

mx = sum(x,dim);
my = sum(y,dim);


classdef VademecumTxiRhoPlotter < VademecumPlotter

    properties (SetAccess = private, GetAccess = public)
        feasibleIndex
    end

    properties (Access = protected)
       name = 'TxiRho';
    end

    properties (Access = private)
        mxT
        myT
        chi
    end

    methods (Access = public)

        function obj = VademecumTxiRhoPlotter(d)
            obj.init(d);
            obj.computeTxiMxMyVariables();
            obj.computeFeasibleIndex();
            obj.feasibleIndex = 1:length(obj.mxV)*length(obj.myV);
            ind = obj.feasibleIndex;
            obj.xV = obj.chi(ind);
            obj.yV = obj.volume(ind);
        end

        function plot(obj)
            obj.plotMxMy();
            obj.plotHomogenizedTensor();
            obj.plotHomogenizedTensorIsotropy();
            obj.plotAmplificatorTensor();
        end

    end

    methods (Access = private)

        function computeTxiMxMyVariables(obj)
            for i = 1:length(obj.mxV)
                for j = 1:length(obj.myV)
                    mx = obj.mxV(i);
                    my = obj.myV(j);
                    obj.chi(i,j) = atan(mx/my);
                    obj.mxT(i,j) = mx;
                    obj.myT(i,j) = my;
                end
            end
        end

        function computeFeasibleIndex(obj)
            d.mx = obj.mxV;
            d.my = obj.myV;
            d.chi = obj.chi;
            d.rho = obj.volume;
            fC = FeasibleIndexComputer(d);
            obj.feasibleIndex = fC.index;
        end

        function plotMxMy(obj)
            obj.printWidthVariable(obj.mxT,'m_1');
            obj.printWidthVariable(obj.myT,'m_2');
        end

        function printWidthVariable(obj,val,name)
            obj.fileName    = name;
            obj.titleName   = name;
            obj.value2print = val;
            obj.plotFigure();
            obj.printFigure();
        end

    end

    methods (Access = protected)

        function plotFigure(obj)
            x(:,1) = obj.xV;
            y(:,1) = obj.yV;
            z(:,1) = obj.value2print(obj.feasibleIndex);

            s.fileName = fullfile(obj.outPutPath,[obj.fileName,'XiRho']);
            s.title    = obj.titleName;
            s.axisAdder = XiRhoAxisAdder();
            p  = SuperEllipseExponentContourPlotter(s);
            p.plot(x,y,z);
%
%             ncolors = 50;
%             tri = delaunay(x,y);
%             obj.fig = figure;
%             tricontour(tri,x,y,z,ncolors)
%             colorbar
%             hold on
%             plot(x,y,'+');
%             ylim([0 1])
%             xlabel('$\xi$','Interpreter','latex');
%             ylabel('\rho');
%             tN = obj.titleName;
%             title(['$',tN,'$'],'interpreter','latex')
%             set(gca,'xtick',[0:pi/8:pi/2]) % where to set the tick marks
%             set(gca,'xticklabels',{'0','\pi/8','\pi/4','3\pi/8','\pi/2'})
        end

    end

end


%   TTeMPS Toolbox.
%   Michael Steinlechner, 2013-2016
%   Questions and contact: michael.steinlechner@epfl.ch
%   BSD 2-clause license, see LICENSE.txt
function [X, residuum, cost, times] = alsLinsolve_rankOne( L, F, X, opts )

t_start = tic();
% set default opts
if ~exist( 'opts', 'var');       opts = struct();       end
if ~isfield( opts, 'nSweeps');   opts.nSweeps = 4;      end
if ~isfield( opts, 'solver');    opts.solver = 'pcg';   end

d = X.order;
n = X.size;

normF = norm(F);
g = apply(L, X) - F;
cost = cost_function_res( X, g );
residuum = norm( g ) / normF;
times = toc(t_start);

X = orthogonalize(X, 1);
for sweep = 1:opts.nSweeps
    % ====================================================================
    % LEFT-TO-RIGHT SWEEP
    % ====================================================================
    disp( ['STARTING SWEEP ', num2str(sweep), ' from left to right'] )
    disp( '===========================================================')
    for idx = 1:d-1
        disp( ['Current core: ', num2str(idx)] )

        Fi = contract( X, F, idx );
        sz = [X.rank(idx), X.size(idx), X.rank(idx+1)];

        if strcmpi( opts.solver, 'direct' )
            % if system very small
            Li = contract( X, apply(L,X), idx );
            Ui = Li \ Fi(:);
            X.U{idx} = reshape( Ui, sz );

        elseif strcmpi( opts.solver, 'pcg' )

            [left, right] = Afun_prepare( L, X, idx );
            B1 =  prepare_precond( L.A{1}, X, idx );

            Ui = pcg( @(y) Afun( L, y, idx, sz, left, right), ...
                     Fi(:), ...
                     1e-10, 1000, ...
                     @(y) apply_precond( L.A{1}, B1, y, sz ), [],...
                     X.U{idx}(:) );

            X.U{idx} = reshape( Ui, sz );

        elseif strcmpi( opts.solver, 'diag' )
            X.U{idx} = solve_inner( L.L0, X, Fi, idx );

        else
            error( 'Unknown opts.solver type. Use either ''direct'', ''pcg'' (default) or ''diag''.' )
        end

        X = orth_at( X, idx, 'left', true );

        g = apply(L, X) - F;
        residuum = [residuum; norm( g ) / normF];
        cost = [cost; cost_function_res( X, g )];
        times = [times; toc(t_start)];
    end

    % ====================================================================
    % RIGHT-TO-LEFT
    % ====================================================================
    disp( 'Starting right-to-left half-sweep:')
    for idx = d:-1:2
        disp( ['Current core: ', num2str(idx)] )

        Fi = contract( X, F, idx );
        sz = [X.rank(idx), X.size(idx), X.rank(idx+1)];

        if strcmpi( opts.solver, 'direct' )
            % if system very small
            Li = contract( X, apply(L, X), idx );
            Ui = Li \ Fi(:);
            X.U{idx} = reshape( Ui, sz );

        elseif strcmpi( opts.solver, 'pcg' )

            [left, right] = Afun_prepare( L, X, idx );
            B1 =  prepare_precond( L.A{1}, X, idx );

            Ui = pcg( @(y) Afun( L, y, idx, sz, left, right), ...
                     Fi(:), ...
                     1e-10, 1000, ...
                     @(y) apply_precond( L.A{1}, B1, y, sz ), [],...
                     X.U{idx}(:) );

            X.U{idx} = reshape( Ui, sz );

        elseif strcmpi( opts.solver, 'diag' )
            X.U{idx} = solve_inner( L.L0, X, Fi, idx );

        else
            error( 'Unknown opts.solver type. Use either ''direct'', ''pcg'' (default) or ''diag''.' )
        end

        X = orth_at( X, idx, 'right', true );

        g = apply(L, X) - F;
        residuum = [residuum; norm( g ) / normF];
        cost = [cost; cost_function_res( X, g )];
        times = [times; toc(t_start)];
    end

end

end

function res = cost_function( L, X, F )
res = 0.5*innerprod( X, apply(L, X) ) - innerprod( X, F );
end

function res = cost_function_res( X, res )
res = 0.5*innerprod( X, res );
end

function [left, right] = Afun_prepare( A, x, idx )
    y = A.apply(x);
    if idx == 1
        right = innerprod( x, y, 'RL', idx+1 );
        left = [];
    elseif idx == x.order
        left = innerprod( x, y, 'LR', idx-1 );
        right = [];
    else
        left = innerprod( x, y, 'LR', idx-1 );
        right = innerprod( x, y, 'RL', idx+1 );
    end
end

function res = Afun( A, U, idx, sz, left, right )

    V = reshape( U, sz );
    V = A.apply( V, idx );

    if idx == 1
        tmp = tensorprod_ttemps( V, right, 3 );
    elseif idx == A.order
        tmp = tensorprod_ttemps( V, left, 1 );
    else
        tmp = tensorprod_ttemps( V, right, 3);
        tmp = tensorprod_ttemps( tmp, left, 1);
    end

    res = tmp(:);
end

function B1 = prepare_precond( L0, X, idx )

    if idx == 1
        B1 = [];
        return
    end

    n = size(L0, 1);
    r = X.rank;

    X1 = matricize( X.U{1}, 2);
    Y = X;
    Y.U{1} = tensorize( L0*X1, 2, [r(1), n(1), r(2)] );
    B1 = innerprod( X, Y, 'LR', idx-1);
end

function res = apply_precond( L0, B1, rhs, sz )

    n = size(L0, 1);
    rhs = reshape( rhs, sz );
    if isempty(B1) %idx == 1
        res = L0 \ unfold( rhs, 'left' );
        res = reshape( res, sz );
    else
        res = B1 \ unfold(rhs, 'right');
        res = reshape( res, sz );
    end
    res = res(:);
end


function [vec,rotMat]=TEME2GCRS(x,Jul1,Jul2,deltaTTUT1,xpyp,dXdY,LOD)
%%TEME2GCRS Convert from the True Equator Mean Equinox (TEME) of date
%           coordinate system to the Geocentric Celestrial Reference System
%           (GCRS), a type of Earth-Centered Inertial (ECI) coordinate
%           system. The TEME system is non-standard and is generally
%           only used in the Specialized General Perturbations 4 (SGP4)
%           orbit propagation algorithm.
%
%INPUTS: x The NXnumVec collection of vectors in TEME coordinates to
%          convert. N can be 3, or 6. If the vectors are 3D, then they are
%          position. 6D vectors are assumed to be position and velocity,
%          whereby the angular velocity of the Earth's rotation is taken
%          into account using a non-relativistic formula.
% Jul1, Jul2 Two parts of a Julian date given in terrestrial time (TT).
%          The units of the date are days. The full date is the sum of both
%          terms. The date is broken into two parts to provide more bits of
%          precision. It does not matter how the date is split.
% deltaTTUT1 An optional parameter specifying the difference between TT and
%          UT1 in seconds. This information can be obtained from
%          http://www.iers.org/nn_11474/IERS/EN/DataProducts/EarthOrientationData/eop.html?__nnn=true
%          or
%          http://www.usno.navy.mil/USNO/earth-orientation/eo-products
%          If this parameter is omitted or if an empty matrix is passed,
%          then the value provided by the function getEOP will be used
%          instead.
%     xpyp xpyp=[xp;yp] are the polar motion coordinates in radians
%          including the effects of tides and librations. If this parameter
%          is omitted or if an empty matrix is passed, the value from the
%          function getEOP will be used.
%     dXdY dXdY=[dX;dY] are the celestial pole offsets with respect to the
%          IAU 2006/2000A precession/nutation model in radians If this
%          parameter is omitted or if an empty matrix is passed, the value
%          from the function getEOP will be used.
%      LOD The difference between the length of the day using terrestrial
%          time, international atomic time, or UTC without leap seconds and
%          the length of the day in UT1. This is an instantaneous parameter
%          (in seconds) proportional to the rotation rate of the Earth.
%          This is only needed if more than just position components are
%          being converted.
%
%OUTPUTS: vec A 3XN or 6XN matrix of vectors converted from TEME
%             coordinates to GCRS coordinates.
%      rotMat The 3X3 rotation matrix used for the conversion of the
%             positions. That is, vec(1:3)=rotMat*x(1:3)
%
%This function just calls the functions TEME2ITRS and ITRS2GCRS, reusing
%the same Earth orientation parameters across calls.
%
%Different celestial coordinate systems are compared in [1].
%
%REFERENCES:
%[1] D. F. Crouse, "An Overview of Major Terrestrial, Celestial, and
%    Temporal Coordinate Systems for Target Tracking," Formal Report, Naval
%    Research Laboratory, no. NRL/FR/5344--16-10,279, 10 Aug. 2016, 173
%    pages.
%
%January 2015 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

%If more EOPs are needed.
if(nargin<7&&size(x,1)==6||nargin<6||isempty(dXdY)||isempty(xpyp)||isempty(deltaTTUT1))
    [JulUTC1,JulUTC2]=TT2UTC(Jul1,Jul2);
    [xpypget,dXdYget,~,deltaTTUT1get,LODget]=getEOP(JulUTC1,JulUTC2);
end

if(nargin<7||isempty(LOD))
   LOD=LODget;
end

if(nargin<6||isempty(dXdY))
    dXdY=dXdYget;
end

if(nargin<5||isempty(xpyp))
    xpyp=xpypget;
end

if(nargin<4||isempty(deltaTTUT1))
    deltaTTUT1=deltaTTUT1get;
end

[x,rotMat1]=TEME2ITRS(x,Jul1,Jul2,deltaTTUT1,xpyp,LOD);
[vec,rotMat2]=ITRS2GCRS(x,Jul1,Jul2,deltaTTUT1,xpyp,dXdY,LOD);

%The combined rotation matrix.
rotMat=rotMat2*rotMat1;
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 [result]=sv_NodeCalcSchuster(params,mCatalog)
% function [result]=sv_NodeCalcSchuster(params,mCatalog)
% ----------------------------------------------------
% Function to calculate Schuster's test and fast Mc (not EMR method)
% estimates; calculates also uncertainties for Schuster's test
%
% Incoming variables:
% mCatalog     : current earthquake catalog
% params       : See sv_calcMc for parameters
%
% Outgoing variable:
% result.fMc_max    : magnitude of completeness using maximum cuvature approach
% result.fMc_90     : magnitude of completeness using GR-law fit at 90% goodness fit level
% result.fMc_95     : magnitude of completeness using GR-law fit at 95% goodness fit level
% result.fMc_com    : magnitude of completeness using GR-law fit at 90% goodness fit level,
%                     GR-law fit at 95% goodness fit level, and maximum cuvature approach
% result.fMcSch      : magnitude of completeness using Schusters method
% result.flogProbSch : log10(Probability) to obtain vector of length >= R from a random walkout
% result.v1Sigma     : 1Sigma (16 and 84 percentiles) for probability to obtain vector of length >= R
%                      from a random walkout from bootstrapping the catalog times
% result.flogv1Sigma : 1Sigma (16 and 84 percentiles) for log10(probability) to obtain vector of length >= R
%                      from a random walkout from bootstrapping the catalog times
% result.v1Srange    : 1Sigma range (84-16 percentile)
% result.flogv1Srange: 1Sigma log10 range (84-16 percentile)
%
% Author: J. Woessner
% woessner@seismo.ifg.ethz.ch
% last update: 17.04.03

% Init variable
result=[];

% Determine Mc by maximum curvature
nCalculateMC = 1;
result.fMc_max = calc_Mc(mCatalog, nCalculateMC);
if isempty(result.fMc_max)
    result.fMc_max = NaN;
end

% Determine Mc by goodness of fit 90%
nCalculateMC = 3;
result.fMc_90 = calc_Mc(mCatalog, nCalculateMC);
if isempty(result.fMc_90)
    result.fMc_90 = NaN;
end

% Determine Mc by goodness of fit 95%
nCalculateMC = 4;
result.fMc_95 = calc_Mc(mCatalog, nCalculateMC);
if isempty(result.fMc_95)
    result.fMc_95 = NaN;
end

% Determine Mc by best combination
nCalculateMC = 5;
result.fMc_com = calc_Mc(mCatalog, nCalculateMC);
if isempty(result.fMc_com)
    result.fMc_com = NaN;
end

% % Mc determination by modelling entire magnitude range using a NORMAL CDF
% [mResult result.fProbMcNorm result.fMcNorm fMu fSigma mDatPredBest vPredBest result.fBvalue] = calc_McCdfnormal(mCatalog, params.fBinning);
%
% if (isempty(result.fProbMcNorm) | isempty(result.fMcNorm))
%     result.fProbMcNorm = NaN;
%     result.fMcNorm = NaN;
% end
% if (isempty(result.fBvalue))
%     result.fBvalue = NaN;
% end

% Mc determination by Schuster
[mResult fMcSch,  fProbability] =  calc_SchusterMc(mCatalog,0.3);
[mWalkout fR95 fProbSch PHI,  R] = calc_Schusterwalk(mCatalog);
try
    result.fMcSch = fMcSch;
    result.flogProbSch = log10(fProbSch);
catch
    result.fMcSch = NaN;
    result.flogProbSch = NaN;
end

% Determine uncertainty of Schuster test
[vPerc v1Sigma,  fStdProb] = calc_BstSchuster(mCatalog,params.fBinning,params.fBstnum);
try
    result.v1Sigma = v1Sigma;
    result.flogv1Sigma = log10(v1Sigma);
    result.v1Srange = (v1Sigma(1,2) - v1Sigma(1,1));
    result.flogv1Srange = log10(result.v1Srange);
catch
    result.fv1Sigma= NaN;
    result.flogv1Sigma = [NaN NaN];
    result.v1Srange = NaN;
    result.flogv1Srange = NaN;
end


function [T, M, S, DISTR, df] = dtiValTestStat(g1, g2, Y, mask)

% Computes voxel-wise statistics for two groups from a data array of
% diffusion tensors in dt6 format.
%
% The test is H0: both groups have the same eigenvalues, with possibly
% different unknown eigenvectors.
%
%   [T, M, S, DISTR, df] = dtiValTestStat(g1, g2, DT_ARRAY, [MASK])
%
% Input:
%   g1, g2      List of indices that correspond to each group out of 1:N
%                   E.g: g1 = 1:7, g2 = 8:14, N = 14
%   DT_ARRAY    Data array of size XxYxZx6xN (or nx6xN), where X, Y, Z are the volume
%                   dimensions and N is the number of subjects.
%                   (n is the number of voxels).
%   MASK        Optional XxYxZ binary array. Values of T, M and S are computed
%                   where mask = 1; in other voxels, T, M and S are set to 0.
%                   Default is entire volume.
%
% Output:
%   T           XxYxZx1 (or nx1) array of test statistics (0 where mask = 0)
%   M           XxYxZx6x2 (or nx6x2) array of mean tensors (0 where mask = 0)
%   S           XxYxZx1 (or nx1) array of variances (0 where mask = 0)
%   DISTR       'chi2' or 'f'
%   df          degrees of freedom of the appropriate distribution
%
% Utilities:    ndfun.m, dtiSplitTensor.m
%
% WARNING: If using Pentium 4, eliminate NaN's from array before running
% (processor bug).
%
% Copyright by Armin Schwartzman, 2005

% HISTORY:
%   2004.08.29 ASH (armins@stanford.edu) wrote it.
%

% Check inputs
if (ndims(Y)==2 | ndims(Y)==3),
    Ind = 1;    % Data in indexed nx6xN format
    Y = shiftdim(Y, -2);
else
    Ind = 0;    % Data in XxYxZx6xN format
end
if (ndims(Y)<4 | ndims(Y)>5),
    error('Wrong input format');
end
if (~exist('mask')),
    mask = ones([size(Y,1) size(Y,2) size(Y,3)]);
end

% Computations
N1 = length(g1);
N2 = length(g2);
N  = N1 + N2;

q = size(Y, 4);
p = max(roots([1/2 1/2 -q]));
Yavg1 = mean(Y(:,:,:,:,g1),5);
Yavg2 = mean(Y(:,:,:,:,g2),5);
Yavg = mean(Y(:,:,:,:,:),5);
M = cat(5, Yavg1, Yavg2);

[V1,L1] = dtiSplitTensor(Yavg1);
[V2,L2] = dtiSplitTensor(Yavg2);
[V,L] = dtiSplitTensor(Yavg);

% Total variance
d1 = Y(:,:,:,:,g1) - repmat(Yavg1,[1 1 1 1 N1]);
d2 = Y(:,:,:,:,g2) - repmat(Yavg2,[1 1 1 1 N2]);
S = sum(d1(:,:,:,1:p,:).^2, 4) + 2*sum(d1(:,:,:,p+1:q,:).^2, 4) + ...
    sum(d2(:,:,:,1:p,:).^2, 4) + 2*sum(d2(:,:,:,p+1:q,:).^2, 4);
S = sum(S, 5)/(q*(N-2));

% F version
DISTR = 'f';
df = [p, q*(N-2)];
T = N1*N2/N^2 * sum((L1 - L2).^2, 4);
T = df(2)/df(1) * T./(S*(N-2)/N) / q;

% Adjust output
if Ind,
    T = shiftdim(T, 2);
    M = shiftdim(M, 2);
    S = shiftdim(S, 2);
    L = shiftdim(L, 2);
end

return