% This is material illustrating the methods from the book
% Financial Modelling  - Theory, Implementation and Practice with Matlab
% source
% Wiley Finance Series
% ISBN 978-0-470-74489-5
%
% Date: 02.05.2012
%
% Authors:  Joerg Kienitz
%           Daniel Wetterau
%
% Please send comments, suggestions, bugs, code etc. to
% kienitzwetterau_FinModelling@gmx.de
%
% (C) Joerg Kienitz, Daniel Wetterau
%
% Since this piece of code is distributed via the mathworks file-exchange
% it is covered by the BSD license
%
% This code is being provided solely for information and general
% illustrative purposes. The authors will not be responsible for the
% consequences of reliance upon using the code or for numbers produced
% from using the code.

% Discretization of a 2d Variance Gamma process

% Monte Carlo parameters
NBatches = 1;           % Number of batches
NSim = 10000;%100000;           % Number of paths per batch
Nt = 250;                 % Number of time steps until T!

% Asset parameters
S0 = [1.0 1.0];             % spot price of stock index
r =  0.042;              % risk free rate
d =  [0.00 0.00];              % dividend yield
T = 0.5;                % Time horizon (in years)
rho = 0.5;
lnS1 = zeros(NSim, Nt+1); % log spot prices asset 1
lnS2 = zeros(NSim, Nt+1); % log spot prices asset 2

% Model parameters (theta, sigma, nu representation)
theta = [-0.6094 -0.8301];      % parameter of VG
sigma = [0.0325 0.9406];        % parameter of VG
nu = 0.2570;                    % parameter of VG
omegaT = -1/nu * [log(1-theta(1)*nu - nu*sigma(1)^2/2) log(1-theta(2)*nu - nu*sigma(2)^2/2)];
drift = [r-d(1) r-d(2)];       % parameter of VG

%Corr = [1 .6495; .6495 1];
Corr = [1 rho; rho 1];
%Corr = [1 .9; .9 1];
%Corr = [1 -.9; -.9 1];
R = chol(Corr);

% Option parameters
value = ones(NBatches,1);   % Stores the option value per batch

% precomputed constants
deltaT = T / Nt;                            % delta for time discretization
lnS1(:,1) = log(S0(1));                         % Set the starting spot price
lnS2(:,1) = log(S0(2));

%oNt = ones(Nt,1);                       % used during simulation
oNs = ones(NSim,1);
% Start Monte Carlo here
tic;
for number = 1 : NBatches
    % Time discretization

    for m=1:Nt
        %G = nu*gamrnd(deltaT/nu, oNt);      % Gamma Subordinator
        G = nu * gamrnd(deltaT/nu,oNs);
        W = randn(NSim,2);
        W = W*R;
        lnS1(:,m+1) = lnS1(:,m) + (drift(1)-omegaT(1)) * deltaT ...
                       + theta(1) * G + sqrt(G) * sigma(1) .* W(:,1);
        lnS2(:,m+1) = lnS2(:,m) + (drift(2)-omegaT(2))* deltaT ...
                      + theta(2) * G + sqrt(G) * sigma(2) .* W(:,2);
    end

    S1 = exp(lnS1);         % Simulated prices for asset 1
    S2 = exp(lnS2);         % Simulated prices for asset 2

    if(NSim ==1)
        figure1 = figure;
        axes1 = axes('Parent',figure1);
        hold on;
        plot1 = plot(S1,'Parent',axes1,'MarkerSize',4,'Marker','o','Color',[0 0 1],'DisplayName','Asset 1');
        plot1 = plot(S2, 'Marker','.','Color',[1 0 0],'DisplayName','Asset 2');
        %plot(S1,'b');
        %plot(S2,'r');

        % Create xlabel
        xlabel('step');

        % Create ylabel
        ylabel('S(t)');

        % Create title
        title({'2d Variance Gamma Process','- zero correlation -'},...
        'FontWeight','bold','FontSize',12,'FontName','Arial');

        % Create legend
        legend1 = legend(axes1,'show');
        set(legend1,'Position',[0.8206 0.831 0.08047 0.06204]);

    end

    % Option Pricing
    value(number) = exp(-r*T)* WorstOfCall(S1,S2);
    %value(number) = exp(-r*T)* BestOfCall(S1,S2);
    %value(number) = exp(-r*T)* Spread(S1,S2);

end

mean(value)      % Output of Option price
%Elapsed_Time = toc              % Time spend on MC simulation


function kernel = MimNormalisedGaussianKernel(voxel_size_mm, filter_size_mm, minimum_grid_size_mm)
    % MimNormalisedGaussianKernel.
    %
    %
    %     The input and output images are of class PTKImage.
    %
    %
    %     Licence
    %     -------
    %     Part of the TD MIM Toolkit. https://github.com/tomdoel
    %     Author: Tom Doel, Copyright Tom Doel 2014.  www.tomdoel.com
    %     Distributed under the MIT licence. Please see website for details.
    %

    if nargin < 3
        minimum_grid_size_mm = [];
    end

    if numel(minimum_grid_size_mm) == 1
        minimum_grid_size_mm = repmat(minimum_grid_size_mm, [1, 3]);
    end

    sigma_mm = filter_size_mm;

    epsilon = 1e-3;
    sigma_voxels = sigma_mm./voxel_size_mm;
    grid_size = 2*(ceil((sigma_voxels).*sqrt(-2*log(sqrt(2*pi).*(sigma_voxels)*epsilon)))) + 1;

    if ~isempty(minimum_grid_size_mm)
        minimum_grid_size = 2*(ceil((minimum_grid_size_mm./voxel_size_mm)/2));
        grid_size = max(grid_size, minimum_grid_size);
    end

    grid_size_i = grid_size(1);
    grid_size_j = grid_size(2);
    grid_size_k = grid_size(3);

    center_i = grid_size_i/2 + 0.5;
    center_j = grid_size_j/2 + 0.5;
    center_k = grid_size_k/2 + 0.5;

    n_i = 1 : grid_size_i;
    n_j = 1 : grid_size_j;
    n_k = 1 : grid_size_k;

    sigmai = sigma_voxels(1);
    sigmaj = sigma_voxels(2);
    sigmak = sigma_voxels(3);

    keri = zeros(1, 1, grid_size_i, 'single');
    kerj = zeros(1, 1, grid_size_j, 'single');
    kerk = zeros(1, 1, grid_size_k, 'single');

    keri(1,1,:) = (1/((2*pi*sigmai.^2).^(1/2))) * exp(-((n_i - center_i).^2)/(2*sigmai.^2));
    kerj(1,1,:) = (1/((2*pi*sigmaj.^2).^(1/2))) * exp(-((n_j - center_j).^2)/(2*sigmaj.^2));
    kerk(1,1,:) = (1/((2*pi*sigmak.^2).^(1/2))) * exp(-((n_k - center_k).^2)/(2*sigmak.^2));

    % Normalise
    keri = keri./sum(keri);
    kerj = kerj./sum(kerj);
    kerk = kerk./sum(kerk);

    ker1 = repmat(shiftdim(keri, 2), [1, grid_size_j, grid_size_k]);
    ker2 = repmat(shiftdim(kerj, 1), [grid_size_i, 1, grid_size_k]);
    ker3 = repmat(kerk, [grid_size_i, grid_size_j, 1]);
    kernel = ker1.*ker2.*ker3;

    kernel = kernel/max(kernel(:));
end


function lambda = chow_eigenvalues ( alpha, beta, n )

%*****************************************************************************80
%
%% CHOW_EIGENVALUES returns the eigenvalues of the CHOW matrix.
%
%  Example:
%
%    ALPHA = 2, BETA = 3, N = 5
%
%    9.49395943
%    6.10991621
%    3.0
%    3.0
%    3.0
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    28 September 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real ALPHA, the ALPHA value.  A typical value is 1.0.
%
%    Input, real BETA, the BETA value.  A typical value is 0.0.
%
%    Input, integer N, the order of A.
%
%    Output, real LAMBDA(N,1), the eigenvalues of A.
%
  lambda = zeros ( n, 1 );

  k = n - round ( ( n + 1 ) / 2 );

  for i = 1 : k
    angle = i * pi / ( n + 2 );
    lambda(i,1) = beta + 4.0 * alpha * ( cos ( angle ) )^2;
  end

  lambda(k+1:n,1) = beta;

  return
end


function ciu = consensus_und(d,tau,reps)
% CONSENSUS_UND      Consensus clustering
%
%   CIU = CONSENSUS(D,TAU,REPS) seeks a consensus partition of the
%   agreement matrix D. The algorithm used here is almost identical to the
%   one introduced in Lancichinetti & Fortunato (2012): The agreement
%   matrix D is thresholded at a level TAU to remove an weak elements. The
%   resulting matrix is then partitions REPS number of times using the
%   Louvain algorithm (in principle, any clustering algorithm that can
%   handle weighted matrixes is a suitable alternative to the Louvain
%   algorithm and can be substituted in its place). This clustering
%   produces a set of partitions from which a new agreement is built. If
%   the partitions have not converged to a single representative partition,
%   the above process repeats itself, starting with the newly built
%   agreement matrix.
%
%   NOTE: In this implementation, the elements of the agreement matrix must
%   be converted into probabilities.
%
%   NOTE: This implementation is slightly different from the original
%   algorithm proposed by Lanchichinetti & Fortunato. In its original
%   version, if the thresholding produces singleton communities, those
%   nodes are reconnected to the network. Here, we leave any singleton
%   communities disconnected.
%
%   Inputs:     D,      agreement matrix with entries between 0 and 1
%                       denoting the probability of finding node i in the
%                       same cluster as node j
%               TAU,    threshold which controls the resolution of the
%                       reclustering
%               REPS,   number of times that the clustering algorithm is
%                       reapplied
%
%   Outputs:    CIU,    consensus partition
%
%   References: Lancichinetti & Fortunato (2012). Consensus clustering in
%   complex networks. Scientific Reports 2, Article number: 336.
%
%   Richard Betzel, Indiana University, 2012
%
%   modified on 3/2014 to include "unique_partitions"

n = length(d); flg = 1;
while flg == 1

    flg = 0;
    dt = d.*(d >= tau).*~eye(n);
    if nnz(dt) == 0
        ciu = (1:n)';
    else
        ci = zeros(n,reps);
        for iter = 1:reps
            ci(:,iter) = community_louvain(dt);
        end
        ci = relabel_partitions(ci);
        ciu = unique_partitions(ci);
        nu = size(ciu,2);
        if nu > 1
            flg = 1;
            d = agreement(ci)./reps;
        end
    end

end

function cinew = relabel_partitions(ci)
[n,m] = size(ci);
cinew = zeros(n,m);
for i = 1:m
    c = ci(:,i);
    d = zeros(size(c));
    count = 0;
    while sum(d ~= 0) < n
        count = count + 1;
        ind = find(c,1,'first');
        tgt = c(ind);
        rep = c == tgt;
        d(rep) = count;
        c(rep) = 0;
    end
    cinew(:,i) = d;
end

function ciu = unique_partitions(ci)
ci = relabel_partitions(ci);
ciu = [];
count = 0;
c = 1:size(ci,2);
while ~isempty(ci)
    count = count + 1;
    tgt = ci(:,1);
    ciu = [ciu,tgt];                %#ok<AGROW>
    dff = sum(abs(bsxfun(@minus,ci,tgt))) == 0;
    ci(:,dff) = [];
    c(dff) = [];
end


% This is material illustrating the methods from the book
% Financial Modelling  - Theory, Implementation and Practice with Matlab
% source
% Wiley Finance Series
% ISBN 978-0-470-74489-5
%
% Date: 02.05.2012
%
% Authors:  Joerg Kienitz
%           Daniel Wetterau
%
% Please send comments, suggestions, bugs, code etc. to
% kienitzwetterau_FinModelling@gmx.de
%
% (C) Joerg Kienitz, Daniel Wetterau
%
% Since this piece of code is distributed via the mathworks file-exchange
% it is covered by the BSD license
%
% This code is being provided solely for information and general
% illustrative purposes. The authors will not be responsible for the
% consequences of reliance upon using the code or for numbers produced
% from using the code.

% Script chap::2::script
% Density NIG Model with Gamma Ornstein Uhlenbeck stochastic clock
%
%
%
T = 5;                                      % maturity
f0 = 100;                                  % spot value
r=0;
d=0;
ad = 600;                            % spot value
N = 1024;                            % number of grid points
x = ( (0:N-1) - N/2 ) / ad;          % range

%f = 90:.01:110;                            % range

alpha = 2;
beta = 0;                            % CEV exponent base scenario
delta = .3;
lambda = 3;
a = 1;
b = 1;

legend = 'Base';
title_plot = 'NIG-OU Density';

func = @(x)  cf_nigou(x,T,0,r,d,alpha, beta, delta, lambda,a,b);
y = fftdensity(func,ad,N);
%% Changing a
a_low = .5;
a_high = 2;

func_low = @(x) cf_nigou(x,T,0,r,d,alpha, beta, delta, lambda, a_low,b);
y_low = fftdensity(func_low,ad,N);
func_high = @(x) cf_nigou(x,T,0,r,d,alpha, beta, delta, lambda, a_high,b);
y_high = fftdensity(func_high,ad,N);
legend_low = 'Changing a low';
legend_high = 'Changing a high';

createfigure_density(x,y,y_low,y_high,title_plot,legend,legend_low,legend_high);

%% Changing b
b_low = .5;
b_high = 2;

func_low = @(x) cf_nigou(x,T,0,r,d,alpha, beta, delta, lambda, a,b_low);
y_low = fftdensity(func_low,ad,N);
func_high = @(x) cf_nigou(x,T,0,r,d,alpha, beta, delta, lambda, a,b_high);
y_high = fftdensity(func_high,ad,N);
legend_low = 'Changing b low';
legend_high = 'Changing b high';

createfigure_density(x,y,y_low,y_high,title_plot,legend,legend_low,legend_high);

%% Changing lambda
lambda_low = 1;
lambda_high = 20;

func_low = @(x) cf_nigou(x,T,0,r,d,alpha, beta, delta, lambda_low, a,b);
y_low = fftdensity(func_low,ad,N);
func_high = @(x) cf_nigou(x,T,0,r,d,alpha, beta, delta, lambda_high, a,b);
y_high = fftdensity(func_high,ad,N);
legend_low = 'Changing \lambda low';
legend_high = 'Changing \lambda high';

createfigure_density(x,y,y_low,y_high,title_plot,legend,legend_low,legend_high);


function out = cov(f, g, varargin)
%COV   Covariance of a CHEBFUN.
%   COV(F) is the same as VAR(F) if F is a scalar-valued CHEBFUN.
%   COV(F) returns the covariance of the array-valued CHEBFUN F.
%   COV(F, G) returns the covariance matrix of the columns of F and G.
%
% See also VAR, MEAN.

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

% Empty case:
if ( isempty(f) )
    out = NaN;
    return
end

% Error checking:
if ( (nargin == 2) && ~all(size(f) == size(g)) )
    error('CHEBFUN:CHEBFUN:cov:size',' CHEBFUN dimensions do not agree.');
end
if ( nargin == 3 )
    error('CHEBFUN:CHEBFUN:cov:nargin', ...
        'CHEBFUN/COV does not support normalization.');
end

% Deal with row CHEBFUN objects:
if ( f(1).isTransposed )
    if ( nargin == 1 )
        out = transpose(cov(transpose(f)));
    else
        out = transpose(cov(transpose(f), transpose(g)));
    end
    return
end

% Conditional on COV(f) and COV(f, g).
if ( nargin == 1 ) % COV(f)

    if ( numColumns(f) == 1 )
        % The covariance of a scalar-valued CHEBFUN is the same as the variance:
        out = var(f);
        return

    else
        % Array-valued CHEBFUN or quasimatrix.

        Y = f - mean(f);
        out = diag(mean(Y.*conj(Y)));
        % Convert Y to a cell array of scalar-valued CHEBFUN objects.
        Y = mat2cell(Y);
        % Loop over each of the columns:
        for j = 1:numel(Y)
            for k = j+1:numel(Y)
                % Compute the scaled inner product of the jth and kth columns:
                out(j,k) = mean(Y{j}.*conj(Y{k}));
                % Use symmetry:
                out(k,j) = conj(out(j,k));
            end
        end

    end

else               % COV(f, g)

    % Convert to cell arrays of scalar-valued CHEBFUN objects:
    Y = cheb2cell(f - mean(f));
    Z = cheb2cell(g - mean(g));
    % Initialise output matrix:
    out = zeros(numel(f));
    % Loop over each of the columns:
    for j = 1:numel(Y)
        for k = 1:numel(Y)
            out(j,k) = mean(Y{j}.*conj(Z{k}));
        end
    end

end

end


%   AUTHORSHIP
%   Primary Developer: Stephen Meehan <swmeehan@stanford.edu>
%   Math Lead & Secondary Developer:  Connor Meehan <connor.gw.meehan@gmail.com>
%   Bioinformatics Lead:  Wayne Moore <wmoore@stanford.edu>
%   Provided by the Herzenberg Lab at Stanford University
%   License: BSD 3 clause
%
classdef ProbabilityDensity2 < handle
    properties(Constant)
        DEFAULT_BAND_WIDTH=.014;
        DEFAULT_GRID_SIZE=256;
        N_MIN=5000;
    end

    properties(SetAccess=private)
        deltas;
        onScale;
        xyData;
        xgrid;
        ygrid;
        wmat;
        fmat;
        fmatVector;
        ye;
        xm;
        ym;
        h;
        M;
        N;
        D;
        mins;
        maxs;
        dataBinIdxs;
    end

    methods
        function this=ProbabilityDensity2(xyData, mins, maxs, gridSize, bandWidth)
            assert(nargin>0);
            [this.N, this.D]=size(xyData);
            assert(this.D==2); %2D only
            if nargin<5
                bandWidth=this.DEFAULT_BAND_WIDTH;
                if nargin<4
                    gridSize=this.DEFAULT_GRID_SIZE;
                    if nargin<3
                        maxs=[];
                        if nargin<2
                            mins=[];
                        end
                    end
                end
            end
            needsScaling=~isempty(maxs) || ~isempty(mins);
            if isempty(maxs)
                maxs=max(xyData);
            end
            if isempty(mins)
                mins=min(xyData);
            end
            if needsScaling
                this.onScale=MatBasics.FindOnScale(xyData, mins, maxs);
                cntEdge=size(xyData, 1)-sum(this.onScale);
                if cntEdge>0
                    xyData=xyData(this.onScale, :);
                    this.N=this.N-cntEdge;
                end

            end
            this.mins=mins;
            this.maxs=maxs;
            this.M =gridSize;
            this.deltas=1/(this.M-1)*(maxs-mins);
            this.xyData=xyData;
            this.h=zeros(1, this.D);
            for i =1:this.D
                if this.N<ProbabilityDensity2.N_MIN
                    this.h(i)=(this.N/ProbabilityDensity2.N_MIN)^(-1/6)*1.7...
                        *bandWidth*(maxs(i)-mins(i));
                else
                    this.h(i)=bandWidth*(maxs(i)-mins(i));
                end
            end
            this.computeWeight;
            this.computeDensity;
        end

        function drawJetColors(this, ax, numberOfJetColors)
            if nargin<3
                numberOfJetColors=128;
            end
            this.drawColors(ax, numberOfJetColors);
        end

        function drawContourOutliers(this, ax, hContours)
            levelList=get(hContours,'LevelList');
            outDensity=find(this.fmatVector<=levelList(1));
            outEvents=ismember(this.dataBinIdxs, outDensity);
            if isempty(this.onScale)
                outsideLastContour=outEvents;
            else
                outsideLastContour=false(length(this.onScale),1);
                outsideLastContour(this.onScale)=outEvents;
            end
            plot(ax, this.xyData(outsideLastContour, 1), ...
                this.xyData(outsideLastContour,2), ...
                '.', 'MarkerSize', 4, ...
                'MarkerEdgeColor', 'black',...
                'LineStyle', 'none');
        end

        function H=drawContours(this, ax, percent, color, lineWidth)
            if nargin<5
                lineWidth=1;
                if nargin<4
                    color=[.5 .5 .6];
                    if nargin<3
                        percent=10;
                    end
                end
            end
            numLevels=floor(100/percent);
            levels=this.computeLevels(numLevels);
            [~,H]=contour(ax, this.xm, this.ym, this.fmat, levels, ...
                'k', 'color', color, 'LineStyle', '-', 'LineWidth', lineWidth);
        end

        function drawColors(this, ax, numberOfJetColors, subsetOfData, ...
            colorRangeStart, colorRangeEnd)
            wasHeld=ishold(ax);
            if ~wasHeld
                hold(ax);
            end
            if nargin<5
                isJetColor=true;
                if nargin<4
                    subsetOfData=[];
                    if  nargin<3
                        numberOfJetColors=64;
                    end
                end
            else
                isJetColor=false;
            end
            if isempty(subsetOfData)
                data=this.xyData;
            else
                if size(subsetOfData, 1)==length(this.onScale)
                    data=subsetOfData(this.onScale, :);
                else
                    onScale_=MatBasics.FindOnScale(subsetOfData, ...
                        this.mins, this.maxs);
                    data=subsetOfData(onScale_, :);
                end
            end
            z=reshape(1:this.M^2,this.M,this.M);
            eb=interp2(this.xgrid, this.ygrid, z',...
                data(:,1),data(:,2),'nearest');  %this associates each data point with its nearest grid point
            [x1,~,x3]=unique(eb);
            if isJetColor
                colors=jet(numberOfJetColors);
            else
                if nargin<6
                    colors=colorRangeStart;
                else
                    a1=mean(colorRangeEnd);
                    a2=mean(colorRangeStart);
                    if a1<a2
                        m1=max(colorRangeEnd);
                        if m1>.75
                            f=.75/m1;
                            colorRangeEnd=colorRangeEnd*f;
                        end
                    end
                    nColors=32;
                    colors=zeros(nColors,3);
                    colors(1,:)=colorRangeStart;
                    colors(nColors,:)=colorRangeEnd;
                    gap=zeros(1,3);
                    for i=1:3
                        gap(i)=colorRangeEnd(i)-colorRangeStart(i);
                    end
                    for i=2:nColors-1
                        for j=1:3
                            colors(i,j)=colors(1,j)+(i/nColors*gap(1,j));
                        end
                    end
                end
            end
            nColors=length(colors);
            try
                levels=this.computeLevels(nColors);
            catch ex
            end
            if size(data,1)<10
                color=colors(1, :);
                plot(ax, data(:,1), data(:,2), 'd',...
                    'markersize', 2, 'MarkerEdgeColor',...
                    color, 'LineStyle', 'none');
                if ~wasHeld
                    hold(ax);
                end
                return;
            end
            try
                colormap(colors);
            catch ex
                disp('huh');
            end
            densities=this.fmatVector(x1);
            lookup=bsearch(levels,densities);
            eventColors=lookup(x3);
            usedColors=unique(eventColors);
            N2=length(usedColors);
            sz=size(data,1);
            if sz<10000
                marker='d';
                ms=2;
            else
                marker='.';
                ms=2;
            end
            for i=1:N2
                colorIdx=usedColors(i);
                li=eventColors==colorIdx;
                plot(ax, data(li,1), data(li,2), marker,...
                    'markersize', ms, 'MarkerEdgeColor',...
                    colors(colorIdx, :), 'LineStyle', 'none');
            end
            if ~wasHeld
                hold(ax);
            end
        end
    end

    methods(Access=private)

        function computeWeight(this)
            this.ye=zeros(2, this.M);
            pointLL=zeros(this.N,2);  %this will be the "lower left" gridpoint to each data point
            for ii = 1:2
                this.ye(ii,:) = linspace(this.mins(ii), this.maxs(ii), this.M);
                pointLL(:,ii)=floor((this.xyData(:,ii)-this.mins(ii))./this.deltas(ii)) + 1;
            end
            pointLL(pointLL==this.M)=this.M-1;  %this avoids going over grid boundary
            %% assign each data point to its closest grid point
            [this.xgrid, this.ygrid]=meshgrid(this.ye(1,:),this.ye(2,:));
            z=reshape(1:this.M^2, this.M, this.M);
            this.dataBinIdxs=interp2(this.xgrid, this.ygrid,z',...
                this.xyData(:,1),this.xyData(:,2),'nearest');  %this associates each data point with its nearest grid point

            %% compute w
            Deltmat=repmat(this.deltas, this.N,1);
            shape=this.M*ones(1,2);
            wmat_=zeros(this.M, this.M);
            for ii=0:1  %number of neighboring gridpoints in 2 dimensions
                for j=0:1
                    pointm=pointLL+repmat([j ii],this.N,1);  %indices of ith neighboring gridpoints
                    pointy=zeros(this.N,2);
                    for k=1:2
                        pointy(:,k)=this.ye(k,pointm(:,k));  %y-values of ith neighboring gridpoints
                    end
                    W=prod(1-(abs(this.xyData-pointy)./Deltmat),2);  %contribution to w from ith neighboring gridpoint from each datapoint
                    wmat_=wmat_+accumarray(pointm,W,shape);  %sums contributions for ith gridpoint over data points and adds to wmat
                end
            end
            this.wmat=wmat_;

        end

        function computeDensity(this)
            Z_=zeros(1, this.D);
            Zin=cell(1, this.D);
            for i =1:this.D
                Z_(i)=min(floor(4*this.h(i)/this.deltas(i)), this.M-1);
                Zin{i}=-Z_(i):Z_(i);
            end
            phi = @(x) 1/sqrt(2*pi)*exp(-x.^2./2);
            [L_{1},L_{2}]=meshgrid(Zin{1},Zin{2});
            Phix=phi(L_{1}*this.deltas(1)./this.h(1))./this.h(1);
            Phiy=phi(L_{2}*this.deltas(2)./this.h(2))./this.h(2);
            Phimat = (Phix.*Phiy)';
            fMat = 1/this.N*conv2(this.wmat,Phimat,'same');
            this.fmatVector=reshape(fMat,[1, this.M^2]);
            this.fmat=fMat';
            [this.xm, this.ym]=meshgrid(this.ye(1,:),this.ye(2,:));
        end

        function levels=computeLevels(this, numberOfLevels)
            T=sort(reshape(this.fmat, 1, this.M^this.D));
            CT=cumsum(T);
            NT=CT/CT(end);
            levels=zeros(1, numberOfLevels);
            for level=1:numberOfLevels
                idx=bsearch(NT, level/numberOfLevels);
                levels(level)=T(idx);
            end
        end

    end

    methods(Static)
        function Draw(ax, data, doContours, doJetColors, reset, ...
                stretchPerc, contourPerc)
            if nargin<7
                contourPerc=10;
                if nargin<6
                    stretchPerc=0;
                    if nargin<5
                        reset=true;
                        if nargin<4
                            doJetColors=true;
                            if nargin<3
                                doContours=true;
                            end
                        end
                    end
                end
            end
            if reset
                cla(ax, 'reset');
            end
            try
                if stretchPerc>0
                    pb=ProbabilityDensity2(MatBasics.StretchXyData(...
                        data, stretchPerc));
                else
                    pb=ProbabilityDensity2(data);
                end
                wasHeld=ishold(ax);
                if ~wasHeld
                    hold(ax, 'on');
                end
                if doJetColors
                    pb.drawJetColors(ax);
                end
                if doContours
                    hContour=pb.drawContours(ax, contourPerc);
                    if ~doJetColors
                        pb.drawContourOutliers(ax, hContour);
                    end
                end
                if ~wasHeld
                    hold(ax, 'off');
                end
            catch ex
                ex.getReport
                plot(ax, data(:,1), data(:,2));
            end
        end

        function [fncMotion, javaLegend, btns, btnLbls, plots, labelHs]=DrawLabeled(ax, ...
                data, lbls, lblMap, doContours, reset, priorFcn, doubleClicker, ...
                xMargin, yMargin, doJavaLegend, oldJavaBtns, southComponent, ...
                selectedCallback, stretchPerc)
            fncMotion=[];
            javaLegend=[];
            btns=[];
            btnLbls=[];
            plots=[];
            if nargin<15
                stretchPerc=0;
                if nargin<14
                    selectedCallback=[];
                    if nargin<13
                        southComponent=[];
                        if nargin<12
                            oldJavaBtns=[];
                            if nargin<11
                                doJavaLegend=false;
                                if nargin<10
                                    yMargin=-0.007;
                                    if nargin<9
                                        xMargin=-0.007;
                                        if nargin<8
                                            doubleClicker=[];
                                            if nargin<7
                                                priorFcn=[];
                                                if nargin<6
                                                    reset=true;
                                                    if nargin<5
                                                        doContours=10;
                                                        if nargin<4
                                                            lblMap=[];
                                                        end
                                                    end
                                                end
                                            end
                                        end
                                    end
                                end
                            end
                        end
                    end
                end
            end
            [addTrainingHtml, sup1, sup2, trStart, trEnd]=...
                LabelBasics.AddTrainingHtml(lblMap, doJavaLegend);
            [R, C]=size(data);
            assert(C==2, 'data''s 2nd dimension must be size 2!');
            [RL, CL]=size(lbls);
            if RL==1 && CL==R
            else
                assert(CL==1, 'Labels'' 2nd dimension must be size 1!');
                assert(R==RL, 'Labels'' 1st dimension size !- data''s 1st!');
            end
            if stretchPerc>0
                pb=ProbabilityDensity2(...
                    MatBasics.StretchXyData(data, stretchPerc));
            else
                pb=ProbabilityDensity2(data);
            end
            if reset
                cla(ax, 'reset');
            end
            try
                if doContours
                    ms=1;
                else
                    ms=2;
                end
                wasHeld=ishold(ax);
                if ~wasHeld
                    hold(ax, 'on');
                end
                u=unique(lbls);
                N=length(u);
                labelHs=zeros(1,N);
                if isempty(lblMap)
                    for i=1:N
                        l=lbls==u(i);
                        clr=Gui.HslColor(i, N);
                        labelHs(i)=plot(ax, ...
                            data(l,1), data(l,2), '.', 'MarkerSize', ms,...
                            'MarkerEdgeColor', clr, 'LineStyle', 'none');
                    end
                else
                    names={};
                    labelIdxs=[];
                    for i=1:N
                        [key, keyColor, keyTraining]=LabelBasics.Keys(u(i));
                        l=lbls==u(i);
                        colorString=char(lblMap.get(keyColor));
                        if ~isempty(colorString)
                            clr=str2num(colorString);
                            if any(clr>1)
                                clr=clr/256;
                            end
                        else
                            if u(i)==0
                                clr=[.9 .9 .9261];
                            else
                                clr=Gui.HslColor(i, N);
                            end
                            colorString=num2str(floor(clr*256));
                            lblMap.put(keyColor, colorString);
                        end
                        labelHs(i)=plot(ax, ...
                            data(l,1), data(l,2), '.', 'MarkerSize', ms,...
                            'MarkerEdgeColor', clr, 'LineStyle', 'none');
                        name=char(lblMap.get(java.lang.String(key)));
                        if addTrainingHtml
                            name=[name trStart lblMap.get(keyTraining) trEnd];
                        end
                        if ~isempty(name)
                            if doJavaLegend
                                if contains(name, '^{')
                                    name=strrep(name, '^{', sup1);
                                    name=strrep(name, '}', sup2);
                                end
                            end
                            names{end+1}=name;
                            labelIdxs(end+1)=i;
                        else
                            if u(i)==0
                                names{end+1}='unsupervised';
                            else
                                if u(i)<0
                                    names{end+1}=['Subset #' ...
                                        num2str(0-u(i)) ];
                                else
                                    names{end+1}=['Subset #' char(key)];
                                end
                            end
                            labelIdxs(end+1)=i;
                            %disp([id ' NOT found' ]);
                        end
                    end
                    if ~isempty(names)
                        [javaLegend, fncMotion, btns, sortI, plots]=...
                            Plots.Legend(labelHs,...
                             names, labelIdxs, xMargin, yMargin, true,...
                            [], priorFcn, doubleClicker, doJavaLegend, ...
                            oldJavaBtns, southComponent, selectedCallback);
                        btnLbls=u(sortI);
                    end
                end
                if (islogical(doContours) && doContours)
                    hContour=pb.drawContours(ax, 10, [0 0 0]);
                    pb.drawContourOutliers(ax, hContour);
                elseif ~isempty(doContours) && doContours>0
                    hContour=pb.drawContours(ax, doContours, [0 0 0]);
                    pb.drawContourOutliers(ax, hContour);
                end
                if ~wasHeld
                    hold(ax, 'off');
                end
            catch ex
                ex.getReport
            end
        end
    end
end


%% Options
%
%%
%
% Many functions provided by MTEX can be customized by options. An option
% is passed to a method as a string parameter followed by a value. For
% example, almost all plotting methods support the option *resolution*
% followed by a double value specifying the resolution in radians.  The code below
% demonstrates the effect of changing this parameter.

odf = SantaFe
plotPDF(odf,Miller(1,0,0,odf.CS),'resolution',10*degree,'contour','linewidth',2);

%%

plotPDF(odf,Miller(1,0,0,odf.CS),'resolution',2.5*degree,'contour','linewidth',2);

%%
% Options that are not followed by a value are called flags. In the above
% example, *contour* is a flag that tells the plotting routine to plot
% contour lines. Options and flags to a function are always optional and
% can be passed in any order. If conflicting options or flags are passed,
% i.e., the resolution is specified twice, the later option in the list is
% considered to be the right one.
%


%% Copyright (C) 2016, 2018 Colin B. Macdonald
%%
%% This file is part of OctSymPy.
%%
%% OctSymPy 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 software 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 software; see the file COPYING.
%% If not, see <http://www.gnu.org/licenses/>.

%% -*- texinfo -*-
%% @documentencoding UTF-8
%% @defmethod  @@sym polylog (@var{s}, @var{z})
%% Symbolic polylogarithm function.
%%
%% Returns the polylogarithm of order @var{s} and argument @var{z}.
%%
%% Example:
%% @example
%% @group
%% syms z s
%% polylog(s, z)
%%   @result{} ans = (sym) polylog(s, z)
%% diff(ans, z)
%%   @result{} (sym)
%%       polylog(s - 1, z)
%%       ─────────────────
%%               z
%% @end group
%% @end example
%%
%% The polylogarithm satisfies many identities, for example:
%% @example
%% @group
%% syms s positive
%% polylog (s+1, 1)
%%   @result{} (sym) ζ(s + 1)
%% zeta (s+1)
%%   @result{} (sym) ζ(s + 1)
%% @end group
%% @end example
%%
%% @seealso{@@sym/dilog, @@sym/zeta}
%% @end defmethod

function L = polylog(s, z)
  if (nargin ~= 2)
    print_usage ();
  end

  L = elementwise_op ('polylog', sym(s), sym(z));
end

%!assert (isequal (polylog (sym('s'), 0), sym(0)))

%!assert (isequal (double (polylog (1, sym(-1))), -log(2)))

%!assert (isequal (double (polylog (0, sym(2))), -2))
%!assert (isequal (double (polylog (-1, sym(2))), 2))
%!assert (isequal (double (polylog (-2, sym(3))), -1.5))
%!assert (isequal (double (polylog (-3, sym(2))), 26))
%!assert (isequal (double (polylog (-4, sym(3))), -15))

%!assert (isequal (double (polylog (1, sym(1)/2)), log(2)))

%!test
%! % round trip
%! syms s z
%! f = polylog (s, z);
%! h = function_handle (f, 'vars', [s z]);
%! A = h (1.1, 2.2);
%! B = polylog (1.1, 2.2);
%! assert (A, B)


function az = azimuth(varargin)

    report_this_filefun(mfilename('fullpath'));

    %AZIMUTH  Calculates azimuth between points on a geoid
    %
    %  az = AZIMUTH(lat1,lon1,lat2,lon2) computes the great circle
    %  bearing between the two points on the globe.  The inputs
    %  can be matrices of equal size.  The azimuth is reported from
    %  0 to 360 degrees, clockwise from north, by convention.
    %
    %  az = AZIMUTH(lat1,lon1,lat2,lon2,geoid) computes the great circle
    %  bearing assuming that the points lie on the ellipsoid defined by
    %  the input geoid.  The geoid vector is of the form
    %  [semimajor axes, eccentricity].  If omitted, the unit sphere,
    %  geoid = [1 0], is assumed.
    %
    %  az = AZIMUTH(lat1,lon1,lat2,lon2,'units') uses the input string 'units'
    %  to define the angle units of the input and output data.  If
    %  'units' is omitted, 'degrees' is assumed.
    %
    %  az = AZIMUTH(lat1,lon1,lat2,lon2,geoid,'units') is a valid calling form.
    %
    %  az = AZIMUTH('track',...) uses the input string 'track' to define
    %  either a great circle bearing or rhumb line heading.  If 'track' = 'gc',
    %  then the great circle bearings are computed.  If 'track' = 'rh', then
    %  the rhumb line headings are computed.  If omitted, 'gc' is assumed.
    %
    %  az = AZIMUTH(pt1,pt2) uses the input form pt1 = [lat1 lon1] and
    %  pt2 = [lat2 lon2], where lat1, lon1, lat2 and lon2 are column vectors.
    %
    %  az = AZIMUTH(pt1,pt2,geoid), az = AZIMUTH(pt1,pt2,'units'),
    %  az = AZIMUTH(pt1,pt2,geoid,'units') and az = AZIMUTH('track',pt1,...)
    %  are all valid calling forms.
    %
    %  See also DISTANCE, RECKON

    %  Copyright (c)  1995 by Systems Planning and Analysis, Inc.
    %  Written by:  E. Byrns, E. Brown
    %   $Revision: 1399 $    $Date: 2006-08-11 11:19:27 +0200 (Fr, 11 Aug 2006) $

    if nargin < 1
        error('Incorrect number of arguments')
    else
        if ischar(varargin{1})
            str = varargin{1};    varargin(1) = [];
        else
            str = [];
        end
    end

    %  Test the track string and call the appropriate function

    if isempty(str)
        [az,msg] = bearing(varargin{:});
    else
        validstr = ['gc';'rh'];
        indx     = strmatch(lower(str),validstr);
        if length(indx) ~= 1
            error('Unrecognized track string')
        elseif indx == 1
            [az,msg] = bearing(varargin{:});
        elseif indx == 2
            [az,msg] = heading(varargin{:});
        end
    end

    %  Error out if necessary

    if ~isempty(msg);   error(msg);   end

    %************************************************************************
    %************************************************************************
    %************************************************************************

function [az,msg] = bearing(in1,in2,in3,in4,in5,in6)

    %BEARING:  Calculates great circle azimuth between points on a geoid
    %
    %  Purpose
    %
    %  Computes the great circle bearing between two
    %  points on a globe.  The default angle input
    %  is degrees.  The default output is in degrees.
    %  The default geoid is a sphere, but this can be
    %  redefined to an ellipsoid using the geoid input.
    %
    %  Synopsis
    %
    %       az = bearing(pt1,pt2)
    %       az = bearing(pt1,pt2,geoid)
    %       az = bearing(pt1,pt2,'units')
    %       az = bearing(pt1,pt2,geoid,'units')
    %
    %       az = bearing(lat1,lon1,lat2,lon2)
    %       az = bearing(lat1,lon1,lat2,lon2,geoid)
    %       az = bearing(lat1,lon1,lat2,lon2,'units')
    %       az = bearing(lat1,lon1,lat2,lon2,geoid,'units')
    %
    %       [az,errmsg] = bearing(....
    %            If two output arguments are supplied, then error condition
    %            messages are returned to the calling function for processing.

    %   REFERENCES:
    %   For the ellipsoid:  D. H. Maling, Coordinate Systems and
    %   Map Projections, 2nd Edition Pergamon Press, 1992, pp. 74-76.
    %   This forumula can be shown to be equivalent for a sphere to
    %   J. P. Snyder,  "Map Projections - A Working Manual,"  US Geological
    %   Survey Professional Paper 1395, US Government Printing Office,
    %   Washington, DC, 1987,  pp. 29-32.

    %  Copyright (c)  1995 by Systems Planning and Analysis, Inc.
    %  Written by:  E. Byrns, E. Brown
    %  Revision 1.0:  11/7/95
    %  Revision 1.1:  11/26/95  elliptical calcs added   EVB

    %  Initialize outputs

    if nargout ~= 0;  az = [];   msg = [];  end

    %  Test inputs

    if nargin == 2
      if size(in1,2) == 2  && size(in2,2) == 2  && ...
                ndims(in1) == 2 & ndims(in2) == 2
            lat1 = in1(:,1);	lon1 = in1(:,2);
            lat2 = in2(:,1);	lon2 = in2(:,2);
        else
            msg = 'Incorrect latitude and longitude data matrices';
            if nargout < 2;  error(msg);  end
            return
        end

        geoid = [];      units  = [];

    elseif nargin == 3
      if size(in1,2) == 2  && size(in2,2) == 2  && ...
                ndims(in1) == 2 & ndims(in2) == 2
            lat1 = in1(:,1);	lon1 = in1(:,2);
            lat2 = in2(:,1);	lon2 = in2(:,2);
        else
            msg = 'Incorrect latitude and longitude data matrices';
            if nargout < 2;  error(msg);  end
            return
        end

        if ischar(in3)
            units  = in3;               geoid = [];
        else
            units  = [];                geoid = in3;
        end

    elseif nargin == 4

        if ischar(in4)
          if size(in1,2) == 2  && size(in2,2) == 2  && ...
                    ndims(in1) == 2 & ndims(in2) == 2
                lat1 = in1(:,1);	lon1 = in1(:,2);
                lat2 = in2(:,1);	lon2 = in2(:,2);
            else
                msg = 'Incorrect latitude and longitude data matrices';
                if nargout < 2;  error(msg);  end
                return
            end

            geoid = in3;     units  = in4;

        else
            lat1 = in1;	             lon1 = in2;
            lat2 = in3;	             lon2 = in4;
            geoid = [];              units = [];
        end

    elseif nargin == 5

        lat1 = in1;	    lon1 = in2;
        lat2 = in3;	    lon2 = in4;
        if ischar(in5)
            units  = in5;             geoid = [];
        else
            units  = [];              geoid = in5;
        end

    elseif nargin == 6

        lat1 = in1;	    lon1 = in2;
        lat2 = in3;	    lon2 = in4;
        geoid = in5;    units  = in6;

    else
        msg = 'Incorrect number of arguments';
        if nargout < 2;  error(msg);  end
        return
    end

    %  Empty argument tests.  Allows users to pass in an empty argument
    %  and still not crash.

    if isempty(units);   units = 'degrees';   end
    if isempty(geoid)         %  Unlike related functions reckongc
        geoid = [1 0];     %  and distgc, the first argument of geoid
    elseif geoid(1) == 0      %  can not be zero.  Calculations blow up
        geoid(1) = 1;     %  (1/0) if geoid(1) = 0
    end

    %  Dimension tests

    if ~isequal(size(lat1),size(lon1),size(lat2),size(lon2))
        msg = 'Inconsistent dimensions for latitude and longitude';
        if nargout < 2;  error(msg);  end
        return
    end

    %  Angle unit conversion

    lat1 = angledim(lat1,units,'radians');
    lon1 = angledim(lon1,units,'radians');
    lat2 = angledim(lat2,units,'radians');
    lon2 = angledim(lon2,units,'radians');

    %  Test the geoid parameter

    [geoid,msg] = geoidtst(geoid);
    if ~isempty(msg)
        if nargout < 2;  error(msg);  end
        return
    end

    az = zeros(size(lat1));     % Preallocate memory for output
    epsilon = epsm('radians');      % Set tolerance to the pole

    % Identify those cases where a pole is a starting
    % point or a destination, and those cases where it is not

    indx1 = find(lat1 >= pi/2-epsilon); % north pole starts
    indx2 = find(lat1 <= epsilon-pi/2); % south pole starts
    indx3 = find(lat2 >= pi/2-epsilon); % north pole ends
    indx4 = find(lat2 <= epsilon-pi/2); % south pole ends

    indx=1:numel(az);           % All cases,
    indx([indx1;indx2;indx3;indx4])=[];  %   less the special ones

    % Handle the special cases.  For example, anything starting
    % at the north pole must go south (pi).  Starting point
    % has priority in degenerate cases; i.e. when going from
    % north pole to north pole, result will be pi, not zero.

    if ~isempty(indx4);  az(indx4) = pi;   end  %  Arrive going south
    if ~isempty(indx3);  az(indx3) = 0;    end  %  Arrive going north
    if ~isempty(indx2);  az(indx2) = 0;    end  %  Depart going north
    if ~isempty(indx1);  az(indx1) = pi;   end  %  Depart going south

    %  Compute the bearing for either a spherical or elliptical geoid.
    %  Note that for a sphere, ratio = 1, par1 = lat1, par2 = lat2
    %  and fact4 = 0.

    if ~isempty(indx)
        par1 = geod2par(lat1(indx),geoid,'radians');    %  Parametric latitudes
        par2 = geod2par(lat2(indx),geoid,'radians');

        ratio = minaxis(geoid) / geoid(1);  %  Semiminor/semimajor (b/a)
        ratio = ratio^2;

        fact1 = cos(lat2(indx)) .* sin(lon2(indx)-lon1(indx));
        fact2 = ratio * cos(lat1(indx)) .* sin(lat2(indx));
        fact3 = sin(lat1(indx)) .* cos(lat2(indx)) .* cos(lon2(indx)-lon1(indx));
        fact4 = (1-ratio) * sin(lat1(indx)) .* cos(lat2(indx)) .* ...
            cos(par1) ./ cos(par2);

        az(indx) = atan2(fact1,fact2-fact3+fact4);
    end

    %  Transform the bearing data to the proper range and units

    az = zero22pi(az,'radians','exact');
    az = angledim(az,'radians',units);

    %************************************************************************
    %************************************************************************
    %************************************************************************

function [course,msg] = heading(in1,in2,in3,in4,in5,in6)

    %HEADING:  Calculates rhumb-line direction between points on a geoid
    %
    %  Purpose
    %
    %  Computes the rhumb line direction between two
    %  points on a globe.  The rhumb line is a line of
    %  constant angular direction, a "course to steer".
    %  The default angle input is degrees.  The default output
    %  is in degrees. The default geoid is a sphere, but this
    %  can be redefined to an ellipsoid using the geoid input.
    %
    %  Synopsis
    %
    %       course = heading(pt1,pt2)
    %       course = heading(pt1,pt2,geoid)
    %       course = heading(pt1,pt2,'units')
    %       course = heading(pt1,pt2,geoid,'units')
    %
    %       course = heading(lat1,lon1,lat2,lon2)
    %       course = heading(lat1,lon1,lat2,lon2,geoid)
    %       course = heading(lat1,lon1,lat2,lon2,'units')
    %       course = heading(lat1,lon1,lat2,lon2,geoid,'units')
    %
    %       [course,errmsg] = heading(....
    %            If two output arguments are supplied, then error condition
    %            messages are returned to the calling function for processing.

    %  Copyright (c)  1995 by Systems Planning and Analysis, Inc.
    %  Written by:  E. Brown, E. Byrns
    %  Revision 1.0:  11/7/95
    %  Revision 1.1:  11/28/95  V5 matrix assignment.  Mercalc calls.  EVB

    %  Initialize outputs

    if nargout ~= 0;  course = [];   msg = [];  end

    %  Test inputs

    if nargin == 2
        if size(in1,2) == 2 && size(in2,2) == 2 && ...
                ndims(in1) == 2 && ndims(in2) == 2
            lat1 = in1(:,1);	lon1 = in1(:,2);
            lat2 = in2(:,1);	lon2 = in2(:,2);
        else
            msg = 'Incorrect latitude and longitude data matrices';
            if nargout < 2;  error(msg);  end
            return
        end

        geoid = [];    units  = [];

    elseif nargin == 3
        if size(in1,2) == 2 && size(in2,2) == 2 && ...
                ndims(in1) == 2 && ndims(in2) == 2
            lat1 = in1(:,1);	lon1 = in1(:,2);
            lat2 = in2(:,1);	lon2 = in2(:,2);
        else
            msg = 'Incorrect latitude and longitude data matrices';
            if nargout < 2;  error(msg);  end
            return
        end

        if ischar(in3)
            units  = in3;      geoid = [];
        else
            units  = [];       geoid = in3;
        end

    elseif nargin == 4

        if ischar(in4)
            if size(in1,2) == 2 && size(in2,2) == 2 && ...
                    ndims(in1) == 2 && ndims(in2) == 2
                lat1 = in1(:,1);	lon1 = in1(:,2);
                lat2 = in2(:,1);	lon2 = in2(:,2);
            else
                msg = 'Incorrect latitude and longitude data matrices';
                if nargout < 2;  error(msg);  end
                return
            end

            geoid = in3;    units  = in4;

        else
            lat1 = in1;	              lon1 = in2;
            lat2 = in3;	              lon2 = in4;
            geoid = [];               units = [];
        end

    elseif nargin == 5

        lat1 = in1;	    lon1 = in2;
        lat2 = in3;	    lon2 = in4;
        if ischar(in5)
            units  = in5;         geoid = [];
        else
            units  = [];          geoid = in5;
        end

    elseif nargin == 6

        lat1 = in1;	    lon1 = in2;
        lat2 = in3;	    lon2 = in4;
        geoid = in5;    units  = in6;

    else
        msg = 'Incorrect number of arguments';
        if nargout < 2;  error(msg);  end
        return
    end

    %  Empty argument tests.  Allows users to pass in an empty argument
    %  and still not crash.

    if isempty(units);   units = 'degrees';   end
    if isempty(geoid)         %  Unlike related functions reckonrh
        geoid = [1 0];     %  and distrh, the first argument of geoid
    elseif geoid(1) == 0      %  can not be zero.  Merccalc always returns
        geoid(1) = 1;     %  [x,y] = 0 if geoid(1) = 0
    end

    %  Dimension tests

    if  ~isequal(size(lat1),size(lon1),size(lat2),size(lon2))
        msg = 'Inconsistent dimensions for latitude and longitude';
        if nargout < 2;  error(msg);  end
        return
    end

    %  Angle unit conversion

    lat1 = angledim(lat1,units,'radians');
    lon1 = angledim(lon1,units,'radians');
    lat2 = angledim(lat2,units,'radians');
    lon2 = angledim(lon2,units,'radians');

    %  Test the geoid parameter

    [geoid,msg] = geoidtst(geoid);
    if ~isempty(msg)
        if nargout < 2;  error(msg);  end
        return
    end

    course=zeros(size(lat1));     % Preallocate memory for output
    epsilon=epsm('radians');      % Set tolerance to the pole

    % Identify those cases where a pole is a starting
    % point or a destination, and those cases where it is not

    indx1 = find(lat1 >= pi/2-epsilon); % north pole starts
    indx2 = find(lat1 <= epsilon-pi/2); % south pole starts
    indx3 = find(lat2 >= pi/2-epsilon); % north pole ends
    indx4 = find(lat2 <= epsilon-pi/2); % south pole ends

    indx=1:numel(course);           % All cases,
    indx([indx1;indx2;indx3;indx4])=[];  %   less the special ones

    % Handle the special cases.  For example, anything starting
    % at the north pole must go south (pi).  Starting point
    % has priority in degenerate cases; i.e. when going from
    % north pole to north pole, result will be pi, not zero.

    if ~isempty(indx4);  course(indx4) = pi;   end  %  Arrive going south
    if ~isempty(indx3);  course(indx3) = 0;    end  %  Arrive going north
    if ~isempty(indx2);  course(indx2) = 0;    end  %  Depart going north
    if ~isempty(indx1);  course(indx1) = pi;   end  %  Depart going south

    %  Now find the course for the general cases by calculating the
    %  heading angle in a Mercator coordinate system.  The function
    %  MERCCALC handles both spherical and elliptical geoids

    if ~isempty(indx)
        [x1,y1] = merccalc(lat1(indx),lon1(indx),'forward','radians',geoid);
        [x2,y2] = merccalc(lat2(indx),lon2(indx),'forward','radians',geoid);

        %  Find points greater than 180 deg apart.  Take shorter distance route
        %  Allow for some roundoff error

        epsilon = 1E-10;
        shift = find( abs((x2-x1)) > pi*geoid(1)-epsilon);
        if ~isempty(shift)
            x1(shift) = x1(shift) + sign(x2(shift))*2*pi*geoid(1);
        end

        course(indx) = atan2(x2-x1, y2-y1);
    end

    %  Transform the heading data to the proper range and units

    course = zero22pi(course,'radians','exact');
    course = angledim(course,'radians',units);


%{
    Tests total-variation problem

    min_x ||x||_TV
s.t.
    || A(x) - b || <= eps

The solvers solve a regularized version

see also test_sBP.m and test_sBPDN_W.m

requires the image processing toolbox for this demo
(but the TFOCS solver does not rely on this toolbox)

See also the TV examples in examples/largescale

%}

% Before running this, please add the TFOCS base directory to your path

myAwgn = @(x,snr) x + ...
        10^( (10*log10(sum(abs(x(:)).^2)/length(x(:))) - snr)/20 )*randn(size(x));

% Try to load the problem from disk
fileName = fullfile('reference_solutions','tv_problem1_smoothed_noisy');
randn('state',245);
rand('state',245);
n = 32;
n1 = n;
n2 = n-1;           % testing the code with non-square signals
N = n1*n2;
M = round(N/2);
A = randn(M,N);
if exist([fileName,'.mat'],'file')
    load(fileName);
    fprintf('Loaded problem from %s\n', fileName );
else

    % Generate a new problem

    n = max(n1,n2);
    x = phantom(n);
    x = x(1:n1,1:n2);
    x_original = x;

    mat = @(x) reshape(x,n1,n2);
    vec = @(x) x(:);

    b_original = A*vec(x_original);
    snr = 40;  % SNR in dB
    b   = myAwgn(b_original,snr);
    EPS = norm(b-b_original);

    tv = linop_TV( [n1,n2], [], 'cvx' );

    mu = .005*norm( tv(x_original) ,Inf);
    x0 = zeros(n1,n2);

    % get reference via CVX
    tic
    cvx_begin
        cvx_precision best
        variable xcvx(n1,n2)
        minimize tv(xcvx) + mu/2*sum_square(vec(xcvx)-vec(x0) )
        subject to
            norm(A*vec(xcvx) - b ) <= EPS
    cvx_end
    time_IPM = toc;
    x_ref = xcvx;
    obj_ref = tv(x_ref) + mu/2*sum_square(vec(x_ref)-vec(x0) );

    save(fileName,'x_ref','b','x_original','mu',...
        'EPS','b_original','obj_ref','x0','time_IPM','snr');
    fprintf('Saved data to file %s\n', fileName);

end

imshow( [x_original, x_ref] );

[M,N]           = size(A);
[n1,n2]         = size(x_original);
norm_x_ref      = norm(x_ref,'fro');
norm_x_orig     = norm(x_original,'fro');
er_ref          = @(x) norm(vec(x)-vec(x_ref))/norm_x_ref;
er_signal       = @(x) norm(x-x_original)/norm_x_orig;
resid           = @(x) norm(A*vec(x)-b)/norm(b);  % change if b is noisy

%% Call the TFOCS solver
er              = er_ref;  % error with reference solution (from IPM)
opts = [];
opts.restart    = 1000;
opts.errFcn     = { @(f,dual,primal) er(primal), ...
                    @(f,dual,primal) obj_ref - f  };
opts.maxIts     = 1000;

W   = linop_TV( [n1,n2] );
normW           = linop_TV( [n1,n2], [], 'norm' );
opts.normW2     = normW^2;
z0  = [];   % we don't have a good guess for the dual
tic;
[ x, out, optsOut ] = solver_sBPDN_W( A, W, b, EPS, mu, vec(x0), z0, opts );
time_TFOCS = toc;

fprintf('Solution has %d nonzeros.  Error vs. IPM solution is %.2e\n',...
    nnz(x), er(x) );

% Check that we are within allowable bounds
if out.err(end,1) < 1e-4
    disp('Everything is working');
else
    error('Failed the test');
end

% TFOCS v1.3 by Stephen Becker, Emmanuel Candes, and Michael Grant.
% Copyright 2013 California Institute of Technology and CVX Research.
% See the file LICENSE for full license information.


function [varargout]=tubeplot(x,y,z,varargin)

% TUBEPLOT - plots a tube r along the space curve x,y,z.
%
% tubeplot(x,y,z) plots the basic tube with radius 1
% tubeplot(x,y,z,r) plots the basic tube with variable radius r (either a vector or a value)
% tubeplot(x,y,z,r,v) plots the basic tube with coloring dependent on the values in the vector v
% tubeplot(x,y,z,r,v,s) plots the tube with s tangential subdivisions
% (default is 6)
%
% [X,Y,Z]=tubeplot(x,y,z) returns [Nx3] matrices suitable for mesh or surf
%
% Note that the tube may pinch at points where the normal and binormal
% misbehaves. It is suitable for general space curves, not ones that
% contain straight sections. Normally the tube is calculated using the
% Frenet frame, making the tube minimally twisted except at inflexion points.
%
% To deal with this problem there is an alternative frame:
% tubeplot(x,y,z,r,v,s,vec) calculates the tube by setting the normal to
% the cross product of the tangent and the vector vec. If it is chosen so
% that it is always far from the tangent vector the frame will not twist unduly
%
% Example:
%
%  t=0:(2*pi/100):(2*pi);
%  x=cos(t*2).*(2+sin(t*3)*.3);
%  y=sin(t*2).*(2+sin(t*3)*.3);
%  z=cos(t*3)*.3;
%  tubeplot(x,y,z,0.14*sin(t*5)+.29,t,10)
%
% Written by Anders Sandberg, asa@nada.kth.se, 2005

  subdivs = 6;

  N=size(x,1);
  if (N==1)
    x=x';
    y=y';
    z=z';
    N=size(x,1);
  end

  if (nargin == 3)
    r=x*0+1;
  else
    r=varargin{1};
    if (size(r,1)==1 & size(r,2)==1)
      r=r*ones(N,1);
    end
  end
  if (nargin > 5)
    subdivs=varargin{3}+1;
  end
  if (nargin > 6)
    vec=varargin{4};
    [t,n,b]=frame(x,y,z,vec);
  else
    [t,n,b]=frenet(x,y,z);
  end

  X=zeros(N,subdivs);
  Y=zeros(N,subdivs);
  Z=zeros(N,subdivs);

  theta=0:(2*pi/(subdivs-1)):(2*pi);

  for i=1:N
    X(i,:)=x(i) + r(i)*(n(i,1)*cos(theta) + b(i,1)*sin(theta));
    Y(i,:)=y(i) + r(i)*(n(i,2)*cos(theta) + b(i,2)*sin(theta));
    Z(i,:)=z(i) + r(i)*(n(i,3)*cos(theta) + b(i,3)*sin(theta));
  end

  if (nargout==0)
    if (nargin > 4)
      V=varargin{2};
      if (size(V,1)==1)
	V=V';
      end
      V=V*ones(1,subdivs);
      surf(X,Y,Z,V);
    else
      surf(X,Y,Z);
    end
  else
    varargout(1) = {X};
    varargout(2) = {Y};
    varargout(3) = {Z};
  end


function [logp, yhat, res] = tapas_cdfgaussian_obs(r, infStates, ptrans)
% Calculates the log-probability of response y under a cumulative Gaussian distribution. This
% model has no free parameters.
%
% --------------------------------------------------------------------------------------------------
% Copyright (C) 2012-2015 Christoph Mathys, TNU, UZH & ETHZ
%
% This file is part of the HGF toolbox, which is released under the terms of the GNU General Public
% Licence (GPL), version 3. You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version). For further details, see the file
% COPYING or <http://www.gnu.org/licenses/>.

% Initialize returned log-probabilities as NaNs so that NaN is
% returned for all irregualar trials
n = size(infStates,1);
logp = NaN(n,1);
yhat = NaN(n,1);
res  = NaN(n,1);

% Weed irregular trials out from inferred states and responses
mu2 = infStates(:,2,3);
mu2(r.irr) = [];
sa2 = infStates(:,2,4);
sa2(r.irr) = [];
y = r.y(:,1);
y(r.irr) = [];

% Probability mass for x2 < 0
x2lt0 = 0.5*(1 +erf((0 -mu2)./(sa2.*sqrt(2))));

% Probability of observed choice
probc = y.*(1 -x2lt0) +(1 -y).*x2lt0;

% Calculate log-probabilities for non-irregular trials
% Note: 8*atan(1) == 2*pi (this is used to guard against
% errors resulting from having used pi as a variable).
reg = ~ismember(1:n,r.irr);
logp(reg) = log(probc);
yh = 1 -x2lt0;
yhat(reg) = yh;
res(reg) = (y -yh)./sqrt(yh.*(1 -yh));

return;


%File Description:
%  Unknown parameters in accelerometer error model are calculated using the
%  lm optimization algorithm.
close all
clc
clear

load AccRaw
%@ g = 9.8;
m = length(AccRaw);

y_dat = g*ones(m,1);  % expected gravitational acceleration
p0 = [1 1 1 0 0 0]';
p_init = [1.0 1.0 1.0 0.1 0.1 0.1]';  % initial value of unknown parameters

y_raw = calFunc(AccRaw, p0);  % gravitational acceleration measured by accelerometer
y_raw = y_raw(:);
r_raw = y_dat - y_raw;
p_fit = lm('calFunc', p_init, AccRaw, y_dat);
y_lm = calFunc(AccRaw,p_fit);  % gravitational acceleration measured by calibrated accelerometer
y_lm = y_lm(:);
r_lm = y_dat - y_lm;

kx = p_fit(1);
ky = p_fit(2);
kz = p_fit(3);
bx = p_fit(4);
by = p_fit(5);
bz = p_fit(6);

Ka1=[kx 0 0;0 ky 0;0 0 kz]
ba1=[bx by bz]'
save('calP1','Ka1','ba1')

figure
bar([r_raw'*r_raw, r_lm'*r_lm])
grid on;
set(gca,'XTickLabel', {'raw','lm'});
ylabel('fa');

t=1:m;
figure
title('Accelerometer Calibration')
plot(t, r_raw, t, r_lm)
legend('Uncalibrated', 'Calibrated-LM')
xlabel('Sampling sequence')
ylabel('Residual')


function [interp_value] = grid_bilin_interp(X_approx, Y_approx, grid, ncols, nrows, cellsize, Xll, Yll, nodata)

% SYNTAX:
%   [interp_value] = grid_bilin_interp(X_approx, Y_approx, grid, ncols, nrows, cellsize, Xll, Yll, nodata);
%
% INPUT:
%   X_approx = X coordinate of the interpolation point
%   Y_approx = Y coordinate of the interpolation point
%   grid = matrix containing the grid
%   ncols = number of columns of the grid
%   nrows = number of rows of the grid
%   cellsize = ground size of a cell
%   Xll = X coordinate of the center of the lower left cell
%   Yll = Y coordinate of the center of the lower left cell
%   nodata = value used for cells not containing data
%
% OUTPUT:
%   interp_value = interpolated value
%
% DESCRIPTION:
%   Function that applies a bilinear interpolation of the four nearest nodes
%   of a georeferenced grid in correspondence of a point of given coordinates.

%--- * --. --- --. .--. ... * ---------------------------------------------
%               ___ ___ ___
%     __ _ ___ / __| _ | __|
%    / _` / _ \ (_ |  _|__ \
%    \__, \___/\___|_| |___/
%    |___/                    v 1.0RC1
%
%--------------------------------------------------------------------------
%  Copyright (C) 2021 Geomatics Research & Development srl (GReD)
%  Written by:       Mirko Reguzzoni
%  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
%--------------------------------------------------------------------------

%preparation of the grid axes
X = (Xll : cellsize : Xll + (ncols - 1) * cellsize)';
Y = (Yll : cellsize : Yll + (nrows - 1) * cellsize)';

if (X_approx <= X(1) | X_approx >= X(end) | Y_approx <= Y(1) | Y_approx >= Y(end))
    interp_value = nodata;
    return
end

%detection of the grid node nearest to the interpolation point
[mX, posX] = min(abs(X - X_approx));
[mY, posY] = min(abs(Y - Y_approx));

%definition of the four grid nodes that sorround the interpolation point
% (i,j) image coordinates (upper-left origin)
% (X,Y) ground coordinates (bottom-left origin)
if (X(posX) > X_approx) | (mX ==0)
    j_left = posX - 1;
    j_right = posX;
    X_left = X(posX - 1);
else
    j_left = posX;
    j_right = posX + 1;
    X_left = X(posX);
end

if (Y(posY) > Y_approx) | (mY ==0)
    i_up = nrows + 1 - posY;
    i_down = i_up + 1;
    Y_down = Y(posY - 1);
else
    i_down = nrows + 1 - posY;
    i_up = i_down - 1;
    Y_down = Y(posY);
end

%if one of the interp_value values of the four sorrounding points is a nodata value, do not interpolate and return nodata value
if (grid(i_up,j_left) == nodata | grid(i_up,j_right) == nodata | grid(i_down,j_left) == nodata | grid(i_down,j_right) == nodata)
    interp_value = nodata;
    return
end

%computation of the parameters of the bilinear function
%f(X, Y) = a*X*Y + b*X + c*Y + d

A = [0 0 cellsize 1; ...
     cellsize^2 cellsize cellsize 1; ...
     0 0 0 1; ...
     0 cellsize 0 1];

B = [grid(i_up,j_left);...
     grid(i_up,j_right);...
     grid(i_down,j_left);...
     grid(i_down,j_right)];

bilin_param = A\B;

i_approx = Y_approx - Y_down;
j_approx = X_approx - X_left;

%computation of the interpolated value
interp_value = bilin_param(1) * j_approx * i_approx + bilin_param(2) * j_approx + bilin_param(3) * i_approx + bilin_param(4);
interp_value = double(interp_value);


% NUMDIM - estimate a lower bound on the (minimum) number of discrete sources
%            in the data via their second-order statistics.
% Usage:
%   >> num = numdim( data );
%
% Inputs:
%   data   - 2-D data (nchannel x npoints)
%
% Outputs:
%   num    - number of sources (estimated from second order measures)
%
% References:
%   WACKERMANN, J. 1996. Beyond mapping: estimating complexity
%   of multichannel EEG recordings. Acta Neurobiologiae
%   Experimentalis, 56, 197-208.
%   WACKERMANN, J. 1999. Towards a quantitative characterization
%   of functional states of the brain: from non-linear methodology
%   to the global linear description. International Journal of
%   Psychophysiology, 34, 65-80.
%
% Author: Arnaud Delorme, CNL / Salk Institute, 23 January 2003

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

function lambda = numdim( a )

    if nargin < 1
        help numdim;
        return;
    end

% Akaike, Identification toolbox (linear identification)

    a = a';
    b = a'*a/100; % correlation
    [v d] = eig(b);
    %det(d-b); % checking

    l = diag(d);
    l = l/sum(l);
    lambda = real(exp(-sum(l.*log(l))));

    return;

    % testing by duplicating columns
    a = rand(100,5)*2-1;
    a = [a a];
    numdim( a )


function [logp, s] = kde(train, test, s)

%KDE Kernel Density Estimation.
%    This function computes a kernel density estimator from a set of examples,
%    by placing Gaussian kernels (with identical masses) on each training data
%    point and adjusting the "widths" to maximize the sum of leave-one-out log
%    densities. In multivariate data, either isotropic or diagonal covariance
%    matrix Gaussians are used.
%
%    usage: [logp, s] = kde(train, test, s)
%
%    inputs:  train (n by D) is a matrix of n training points in D dimensions
%             test  (N by D) is a matrix of test points
%             s     scalar or (1 by D) is a start guess for std devs (optional)
%
%    outputs: logp  (1 by N) is the vector of test log densities
%             s     final std devs
%
%    The size of the initial guess for s indicates whether isotropic or
%    diagonal covariance is desired. If no initial guess is supplied, diagonal
%    is assumed. The method uses a Newton scheme in the log of s, and usually
%    converges in very few iterations. The Newton steps are checked to ensure
%    that a reasonable fraction (half) of the expected improvement is achieved;
%    otherwise smaller steps are tried. The computational complexity is order
%    (nD)^2 + nND, memory requirement order Dn(N+n). The algorithm may
%    encounter numerical problems if initial guess is too small.
%
%    (C) Copyright Carl Edward Rasmussen, July 4th 2000.

[N, D] = size(test); [n, D] = size(train);  % get number of cases and dimension
if nargin == 2                                % if no start guess is given then
  s = std(train)/(n^(0.5/D));      % use scaled empirical axis aligned std devs
end
P = length(s);                                    % number of parameters to fit

t = repmat(train,[1,1,n]);
if P == 1                                    % if we are fitting a single width
  c = sum((permute(t,[1,3,2])-permute(t,[3,1,2])).^2,3);
else                                                 % else multiple parameters
  c = (permute(t,[1,3,2])-permute(t,[3,1,2])).^2;
end

G = 1; TINY = 1e-10;
ec = exp(-sum(c./repmat(permute(2*s.^2,[1,3,2]),[n,n,1]),3));
secd = repmat(sum(ec-eye(n),2),[1,P]);
f_old = sum(log(secd(:,1)))-n*sum(log(s));
while max(abs(G)) > TINY
  x = shiftdim(sum(repmat(ec,[1,1,P]).*c,1))./secd;
  DE = sum(x,1)./s.^2;
  xx = repmat(x,[1 1 P]);
  for i=1:P        % rewriting this loop as matrix expr would cost too much mem
    DDE(i,1:P) = sum(shiftdim(sum(c.*repmat(ec.*c(:,:,i),[1,1,P])))./secd);
  end
  DDE = (DDE - shiftdim(sum(xx.*permute(xx,[1,3,2]))))./(s'*s).^2;
  [v, l] = eig(DDE-2*diag(DE));                               % eigs of Hessian
  l = max(abs(diag(l)),min(l(:)/TINY));    % control sign and magnitude of eigs
  G = (n*D/P-DE)*v*diag(-1./l)*v';                        % compute Newton step
  G = G/max(1, sqrt(G*G'));                       % don't take too large a step
  eta = 1; s_old = s;
  while eta == 1 | f_new < f_old - eta*G*(n*D/P-DE')/2 - TINY    % improvement?
    s = s_old.*exp(G*eta);
    eta = eta/2;           % if we fail, then try smaller step next time around
    ec = exp(-sum(c./repmat(permute(2*s.^2,[1,3,2]),[n,n,1]),3));
    secd = repmat(sum(ec-eye(n),2),[1,P]);
    f_new = sum(log(secd(:,1)))-n*sum(log(s));
  end
  f_old = f_new;                   % remember function value for next iteration
end

x = repmat(2*s.^2,[n,D/P]);
logp = zeros(N, 1);
for i=1:N          % rewriting this loop as matrix expr would cost too much mem
  cc = sum((repmat(test(i,:),[n,1])-train).^2./x,2);
  hh = min(cc);
  logp(i) = log(mean(exp(hh-cc)))-hh;
end

logp = logp - D*log(2*pi)/2 - D*sum(log(s))/P;            % normalize densities


% test for run length coding

% some signal with long cluster of 0/1
n = 1024*2;
options.alpha = 0.1;
x = load_signal('regular',n,options);
x = (x-mean(x))>0;

options.rle_coding_mode = 'shannon';
[tmp,nb_shannon] = perform_rle_coding(x, +1, options);
disp(sprintf('Shannon = %.2f', nb_shannon));

options.rle_coding_mode = 'arithmetic';
[tmp,nb_arith] = perform_rle_coding(x, +1, options);
disp(sprintf('Arithmetic = %.2f', nb_arith));

options.rle_coding_mode = 'arithfixed';
[tmp,nb_arithfixed] = perform_rle_coding(x, +1, options);
disp(sprintf('Arithmetic(laplacian) = %.2f', nb_arithfixed));

[tmp,nb_direct] = perform_arithmetic_coding(x, +1);
disp(sprintf('Direct(entropy) = %.2f', nb_direct));

options.rle_coding_mode = 'nocoding';
[tmp,nb_nocode] = perform_rle_coding(x, +1, options);
disp(sprintf('No code = %.2f', nb_nocode));

% test for bijectivity
options.rle_coding_mode = 'nocoding';
stream = perform_rle_coding(x, +1, options);
xx = perform_rle_coding(stream, -1, options);
disp( sprintf('Error (should be 0): %.2f', norme(x-xx)) );

options.rle_coding_mode = 'arithfixed';
stream = perform_rle_coding(x, +1, options);
xx = perform_rle_coding(stream, -1, options);
disp( sprintf('Error (should be 0): %.2f', norme(x-xx)) );


function out = trigcoeffs(f, N)
%TRIGCOEFFS   Trigonometric Fourier coefficients of a CLASSICFUN.
%   C = TRIGCOEFFS(F) returns the trigonometric Fourier coefficients of F
%   using complex-exponential form.  Specifically, for N = length(F)
%   If N is odd
%       F(x) = C(1)*z^(N-1)/2 + C(2)*z^((N-1)/2-1) + ... + C((N+1)/2) + ...
%                + C(N)*z^(-(N-1)/2)
%   If N is even
%       F(x) = C(1)*z^(N/2-1) + C(2)*z^(N/2-2) + ... + C(N/2) + ...
%                + C(N-1)*z^(-N/2-1) + 1/2*C(N)*(z^(N/2) + z^(-N/2))
%   where z = exp(1i*pi*x).
%
%   A = TRIGCOEFFS(F, N) truncates or pads the vector C so that N coefficients
%   of F are returned.
%
%   If F is array-valued with M columns, then C is an MxN matrix.
%
% See also LEGCOEFFS, CHEBCOEFFS.

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

if ( nargin == 1 )
    N = length(f);
end

% Call TRIGCOEFFS() of the .ONEFUN:
out = trigcoeffs(f.onefun, N);

end


%  Figure 3.4      Feedback Control of Dynamic Systems, 6e
%                        Franklin, Powell, Emami
% script to generate Fig. 3.4
%% fig3_04.m    Example 3.5
clf;
k=1;
num=1;                        % form numerator
den=[1 k];                    % form denominator
% sinusoidal input signal
deltaT = 0.001;
t=0:deltaT:10;                % form time vector
u=sin(10*(t));                % form input
sys=tf(num,den);              % form system
[y]=lsim(sys,u,t);            % linear simulation
% plot response
figure();
plot(t,y);
xlabel('Time (sec)');
ylabel('Output');
title('Fig. 3.4 (a): transient response');
pause;
hold on;
y1=(10/101)*exp(-t);
phi=atan(-10);
y2=(1/sqrt(101))*sin(10*t+phi);
plot(t,y1,t,y2,t,y1+y2);
% grid
nicegrid
hold off;
pause;
figure();
ii=[9001:10001];
plot(t(ii),y(ii),t(ii),u(ii));
xlabel('Time (sec)');
ylabel('Output, input');
title('Fig. 3.4 (b): Steady-state response');
text(9.4,0.65,'u(t)');
text(9.24,0.12,'y(t)');
% grid
nicegrid


classdef prtPreProcLda < prtPreProcClass
    % prtPreProcLda  Linear discriminant analysis processing
    %
    %   preProc = prtPreProcLda creates a linear discriminant pre
    %   processing object. A prtPreProcLda object projects the input data
    %   onto a linear space that best separates class labels
    %
    %   A prtPreProcLda object has the following properties:
    %
    %   nComponents - The number of dimensions to project the data onto.
    %                 This must less than or equal to the input data's
    %                 number of features, and less than or equal to the
    %                 input data sets number of classes.
    %
    %   A prtPreProcLda object also inherits all properties and functions from
    %   the prtAction class
    %
    %   More information about LDA can be found at the following URL:
    %   http://en.wikipedia.org/wiki/Linear_discriminant_analysis
    %
    %   Example:
    %
    %   dataSet = prtDataGenIris;               % Load a dataset
    %   dataSet = dataSet.retainFeatures(1:3);  % Retain the first 3 features
    %   lda = prtPreProcLda;                    % Create the pre-processor
    %
    %   lda = lda.train(dataSet);               % Train
    %   dataSetNew = lda.run(dataSet);          % Run
    %
    %   % Plot the results
    %   subplot(2,1,1); plot(dataSet);
    %   title('Original Data');
    %   subplot(2,1,2); plot(dataSetNew);
    %   title('LDA Projected Data');
    %
    %   See Also: prtPreProc, prtPreProcPca, prtPreProcPls,
    %   prtPreProcHistEq, prtPreProcZeroMeanColumns, prtPreProcLda,
    %   prtPreProcZeroMeanRows, prtPreProcLogDisc, prtPreProcZmuv,
    %   prtPreProcMinMaxRows

    properties (SetAccess=private)
        name = 'Linear discriminant analysis' % Linear discriminant analysis
        nameAbbreviation = 'LDA' % LDA
    end

    properties
        nComponents = 2;   % The number of LDA components
    end
    properties (SetAccess=private)
        projectionMatrix = []; % The projection matrix
        globalMean = [];       % The global mean
    end

    methods

        % Allow for string, value pairs
        function Obj = prtPreProcLda(varargin)
            Obj = prtUtilAssignStringValuePairs(Obj,varargin{:});
        end
	end

	methods (Hidden = true)
        function featureNameModificationFunction = getFeatureNameModificationFunction(obj) %#ok<MANU>
            featureNameModificationFunction = prtUtilFeatureNameModificationFunctionHandleCreator('LDA Score #index#');
        end
	end

    methods
        function Obj = set.nComponents(Obj,nComp)
            if ~prtUtilIsPositiveScalarInteger(nComp)
                error('prt:prtPreProcPca','nComponents must be a positive scalar integer');
            end
            Obj.nComponents = nComp;
        end
    end

    methods (Access=protected,Hidden=true)

        function Obj = trainAction(Obj,DataSet)
            if Obj.nComponents > DataSet.nClasses
                error('prt:prtPreProcLda','Attempt to train LDA pre-processor with more components (%d) than unique classes in data set (%d)',Obj.nComponents,DataSet.nClasses);
            end
            [Obj.projectionMatrix,Obj.globalMean] = prtUtilLinearDiscriminantAnalysis(DataSet,Obj.nComponents);
        end

        function DataSet = runAction(Obj,DataSet)

            X = DataSet.getObservations;
            X = bsxfun(@minus,X,Obj.globalMean);
            DataSet = DataSet.setObservations(X*Obj.projectionMatrix);
        end

    end

end


% Test spectrogram

function tPlotSpectrogram

addpath('..');

[x, Fs] = wavread('addf8.wav');

Options = {'BW', 'NB', 'FLim', [500 1500]};
PlotSpectrogram(x, Fs, Options{:});
colormap(SpecColorMap);
colorbar;

% Use alternate colour map
figure;

Options = {'NSlice', 450, 'preF', 0.97,  'BW', 'WB'};
TLen = (length(x)-1)/Fs;
TLim = [0.3*TLen, 0.4*TLen];
PlotSpectrogram(x, TLim, Fs, Options{:});
colorbar;

% Sine wave test (expect sine wave peak at -6 dBov)
% Changing fc to 0, gives 0 dBov at dc
Fs = 16000;
fc = Fs/8;
NSamp = 5000;
t = (0:NSamp-1)/Fs;
Amax = 32767;
x = Amax * cos(2*pi*t*fc);

PmaxdBSPL = 92;             % Max level in dB SPL
PoffsdB = PmaxdBSPL + 20*log10(2);
g = 10^(PoffsdB/20);
AmaxN = Amax/g;

figure;
Options = {'Amax', AmaxN, 'FLim', [0 4000]};
PlotSpectrogram(x, Fs, Options{:});
colormap(SpecColorMap);
colorbar;

return


function [reg_c,rho_c,eta_c] = l_corner(rho,eta,reg_param,U,s,b,method,M)
%L_CORNER Locate the "corner" of the L-curve.
%
% [reg_c,rho_c,eta_c] =
%        l_corner(rho,eta,reg_param)
%        l_corner(rho,eta,reg_param,U,s,b,method,M)
%        l_corner(rho,eta,reg_param,U,sm,b,method,M) ,  sm = [sigma,mu]
%
% Locates the "corner" of the L-curve in log-log scale.
%
% It is assumed that corresponding values of || A x - b ||, || L x ||,
% and the regularization parameter are stored in the arrays rho, eta,
% and reg_param, respectively (such as the output from routine l_curve).
%
% If nargin = 3, then no particular method is assumed, and if
% nargin = 2 then it is issumed that reg_param = 1:length(rho).
%
% If nargin >= 6, then the following methods are allowed:
%    method = 'Tikh'  : Tikhonov regularization
%    method = 'tsvd'  : truncated SVD or GSVD
%    method = 'dsvd'  : damped SVD or GSVD
%    method = 'mtsvd' : modified TSVD,
% and if no method is specified, 'Tikh' is default.  If the Spline Toolbox
% is not available, then only 'Tikh' and 'dsvd' can be used.
%
% An eighth argument M specifies an upper bound for eta, below which
% the corner should be found.

% Per Christian Hansen, IMM, July 26, 2007.

% Set default regularization method.
if (nargin <= 3)
  method = 'none';
  if (nargin==2), reg_param = (1:length(rho))'; end
else
  if (nargin==6), method = 'Tikh'; end
end

% Set this logical variable to 1 (true) if the corner algorithm
% should always be used, even if the Spline Toolbox is available.
alwayscorner = 0;

% Set threshold for skipping very small singular values in the
% analysis of a discrete L-curve.
s_thr = eps;  % Neglect singular values less than s_thr.

% Set default parameters for treatment of discrete L-curve.
deg   = 2;  % Degree of local smooting polynomial.
q     = 2;  % Half-width of local smoothing interval.
order = 4;  % Order of fitting 2-D spline curve.

% Initialization.
if (length(rho) < order)
  error('Too few data points for L-curve analysis')
end
if (nargin > 3)
  [p,ps] = size(s); [m,n] = size(U);
  beta = U'*b;
  if (m>n), b0 = b - U*beta; end
  if (ps==2)
    s = s(p:-1:1,1)./s(p:-1:1,2);
    beta = beta(p:-1:1);
  end
  xi = beta./s;
end

% Restrict the analysis of the L-curve according to M (if specified).
if (nargin==8)
  index = find(eta < M);
  rho = rho(index); eta = eta(index); reg_param = reg_param(index);
end

if (strncmp(method,'Tikh',4) | strncmp(method,'tikh',4))

  % The L-curve is differentiable; computation of curvature in
  % log-log scale is easy.

  % Compute g = - curvature of L-curve.
  g = lcfun(reg_param,s,beta,xi);

  % Locate the corner.  If the curvature is negative everywhere,
  % then define the leftmost point of the L-curve as the corner.
  [gmin,gi] = min(g);
  reg_c = fminbnd('lcfun',...
    reg_param(min(gi+1,length(g))),reg_param(max(gi-1,1)),...
    optimset('Display','off'),s,beta,xi); % Minimizer.
  kappa_max = - lcfun(reg_c,s,beta,xi); % Maximum curvature.

  if (kappa_max < 0)
    lr = length(rho);
    reg_c = reg_param(lr); rho_c = rho(lr); eta_c = eta(lr);
  else
    f = (s.^2)./(s.^2 + reg_c^2);
    eta_c = norm(f.*xi);
    rho_c = norm((1-f).*beta);
    if (m>n), rho_c = sqrt(rho_c^2 + norm(b0)^2); end
  end

elseif (strncmp(method,'tsvd',4) | strncmp(method,'tgsv',4) | ...
        strncmp(method,'mtsv',4) | strncmp(method,'none',4))

  % Use the adaptive pruning algorithm to find the corner, if the
  % Spline Toolbox is not available.
  if ~exist('splines','dir') | alwayscorner
    %error('The Spline Toolbox in not available so l_corner cannot be used')
    reg_c = corner(rho,eta);
    rho_c = rho(reg_c);
    eta_c = eta(reg_c);
    return
  end

  % Othersise use local smoothing followed by fitting a 2-D spline curve
  % to the smoothed discrete L-curve. Restrict the analysis of the L-curve
  % according to s_thr.
  if (nargin > 3)
    if (nargin==8)       % In case the bound M is in action.
      s = s(index,:);
    end
    index = find(s > s_thr);
    rho = rho(index); eta = eta(index); reg_param = reg_param(index);
  end

  % Convert to logarithms.
  lr = length(rho);
  lrho = log(rho); leta = log(eta); slrho = lrho; sleta = leta;

  % For all interior points k = q+1:length(rho)-q-1 on the discrete
  % L-curve, perform local smoothing with a polynomial of degree deg
  % to the points k-q:k+q.
  v = (-q:q)'; A = zeros(2*q+1,deg+1); A(:,1) = ones(length(v),1);
  for j = 2:deg+1, A(:,j) = A(:,j-1).*v; end
  for k = q+1:lr-q-1
    cr = A\lrho(k+v); slrho(k) = cr(1);
    ce = A\leta(k+v); sleta(k) = ce(1);
  end

  % Fit a 2-D spline curve to the smoothed discrete L-curve.
  sp = spmak((1:lr+order),[slrho';sleta']);
  pp = ppbrk(sp2pp(sp),[4,lr+1]);

  % Extract abscissa and ordinate splines and differentiate them.
  % Compute as many function values as default in spleval.
  P     = spleval(pp);  dpp   = fnder(pp);
  D     = spleval(dpp); ddpp  = fnder(pp,2);
  DD    = spleval(ddpp);
  ppx   = P(1,:);       ppy   = P(2,:);
  dppx  = D(1,:);       dppy  = D(2,:);
  ddppx = DD(1,:);      ddppy = DD(2,:);

  % Compute the corner of the discretized .spline curve via max. curvature.
  % No need to refine this corner, since the final regularization
  % parameter is discrete anyway.
  % Define curvature = 0 where both dppx and dppy are zero.
  k1    = dppx.*ddppy - ddppx.*dppy;
  k2    = (dppx.^2 + dppy.^2).^(1.5);
  I_nz  = find(k2 ~= 0);
  kappa = zeros(1,length(dppx));
  kappa(I_nz) = -k1(I_nz)./k2(I_nz);
  [kmax,ikmax] = max(kappa);
  x_corner = ppx(ikmax); y_corner = ppy(ikmax);

  % Locate the point on the discrete L-curve which is closest to the
  % corner of the spline curve.  Prefer a point below and to the
  % left of the corner.  If the curvature is negative everywhere,
  % then define the leftmost point of the L-curve as the corner.
  if (kmax < 0)
    reg_c = reg_param(lr); rho_c = rho(lr); eta_c = eta(lr);
  else
    index = find(lrho < x_corner & leta < y_corner);
    if ~isempty(index)
      [dummy,rpi] = min((lrho(index)-x_corner).^2 + (leta(index)-y_corner).^2);
      rpi = index(rpi);
    else
      [dummy,rpi] = min((lrho-x_corner).^2 + (leta-y_corner).^2);
    end
    reg_c = reg_param(rpi); rho_c = rho(rpi); eta_c = eta(rpi);
  end

elseif (strncmp(method,'dsvd',4) | strncmp(method,'dgsv',4))

  % The L-curve is differentiable; computation of curvature in
  % log-log scale is easy.

  % Compute g = - curvature of L-curve.
  g = lcfun(reg_param,s,beta,xi,1);

  % Locate the corner.  If the curvature is negative everywhere,
  % then define the leftmost point of the L-curve as the corner.
  [gmin,gi] = min(g);
  reg_c = fminbnd('lcfun',...
    reg_param(min(gi+1,length(g))),reg_param(max(gi-1,1)),...
    optimset('Display','off'),s,beta,xi,1); % Minimizer.
  kappa_max = - lcfun(reg_c,s,beta,xi,1); % Maximum curvature.

  if (kappa_max < 0)
    lr = length(rho);
    reg_c = reg_param(lr); rho_c = rho(lr); eta_c = eta(lr);
  else
    f = s./(s + reg_c);
    eta_c = norm(f.*xi);
    rho_c = norm((1-f).*beta);
    if (m>n), rho_c = sqrt(rho_c^2 + norm(b0)^2); end
  end

else
  error('Illegal method')
end


function dq = linevel2dq(v,r,vp,rp)

% LINEVEL2DQ     Transforms a line velocity expressed in vector notation
%                into its dual quaternion representation.
%
%      DQ = LINE2DQ(V,R,VP,RP) transforms the line position, specified by:
%          - the line orientation V
%          - the position of any point of the line, R.
%          - the line orientation rate of change, VP
%          - the velocity component (orthogonal to the line orientation V)
%          of point P, RP
%       V does not need to be unitary, but VP must be orthogonal to V. If
%       RP has a component in the V orientation, it does not matter, since
%       it does not change the expression of the resulting dual quaternion
%       DQ.
%       V,R,VP and RP must have the same size. The inputs (V,R,VP,RP) are
%       either a vector of size 3 or an array of size 3*N (column i
%       represents the input component of Line velocity i) where N is the
%       number of lines. DQ is either a vector of size 8, either an array
%       of size (8*N) depending on the input format. Each column of DQ
%       represents the dual quaternion representation of the corresponding
%       line position velocity.
%
% See also POS2DQ, VEL2DQ, LINE2DQ

sv = size(v);
sr = size(r);
svp = size(vp);
srp = size(rp);
if sv == [1 3],  v = v.'; sv = size(v); end
if sr == [1 3],  r = r.'; sr = size(r); end
if svp == [1 3],  vp = vp.'; svp = size(vp); end
if srp == [1 3],  rp = rp.'; srp = size(rp); end

% check that all inputs have the same size
tab_s = [sv; sr; svp; srp];
if max(tab_s) ~= min(tab_s)
      error('DualQuaternion:linevel2dquat:sizesDoNotMatch',...
        'Arrays v, r, vp and r should be the same size. Size of \n - v is [%d %d] \n - r is [%d %d] \n - vp is [%d %d] \n - rp is [%d %d]',...
           sv(1),sv(2),sr(1),sr(2),svp(1),svp(2),srp(1),srp(2));
end

% if the format is wrong
if sv(1) ~= 3
    error('DualQuaternion:linevel2dquat:wrongsize',...
        '%d rows in the V,R,VP and RP  arrays. It should be 3. ',sv(1));
end

% normalization of the axis vector (if necessary)
n = length(v(1,:));
n2 = sum(v.^2).^0.5;
n2 = repmat(n2,3,1);
v=v./n2;
vp=vp./n2;

% construction of the line velocity dual quaternion
dq = sym(zeros(8,n));
dq(2:4,:) = vp;
dq(6:8,:) = cross(r,vp)+cross(rp,v);


function cheby_u_poly_test ( )

%*****************************************************************************80
%
%% CHEBY_U_POLY_TEST tests CHEBY_U_POLY.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    10 January 2015
%
%  Author:
%
%    John Burkardt
%
  n_max = 12;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'CHEBY_U_POLY_TEST:\n' );
  fprintf ( 1, '  CHEBY_U_POLY evaluates the Chebyshev T polynomial.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '     N      X        Exact F       U(N)(X)\n' );
  fprintf ( 1, '\n' );

  n_data = 0;

  while ( 1 )

    [ n_data, n, x, fx ] = cheby_u_poly_values ( n_data );

    if ( n_data == 0 )
      break
    end

    fx2 = cheby_u_poly ( 1, n, x );

    fprintf ( 1, '  %6d  %8f  %12f  %12f\n', n, x, fx, fx2(n+1) );

  end

  return
end


clear;
clc;
close all;

A = [1 1 1 1; 2 5  7 8]';
B = [1 2 3 3]';

X = inv((A'*A))*A'*B

X = pinv(A)*B

[U,S,V] = svd(A);
PINV_A = V*pinv(S)*U';
X = PINV_A*B

X = U*U'*B


function [imgOut,SH] = DiffuseConvolutionSH(img, falloff)
%
%
%        [imgOut,SH]=DiffuseConvolutionSH(img,falloff)
%
%
%        Input:
%           -img: an environment map in the latitude-longitude mapping
%           -falloff: a flag. If it is set 1, it means that fall-off will
%                     be taken into account
%
%        Output:
%           -imgOut: a diffuse convolved version of img
%           -SH: a [3,9] vector where spherical harmonics for img are
%           encoded
%
%     Copyright (C) 2011  Francesco Banterle
%
%     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/>.
%

if(~exist('falloff', 'var'))
    falloff = 0;
end

%falloff compensation
if(falloff)
    img = FallOffEnvMap(img);
end

[r,c,col]=size(img);

SH = zeros(col, 9);

%projection constants
y00 = 0.282095;
y1x = 0.488603;
y2x = 1.092548;
y20 = 0.315392;
y22 = 0.546274;

%generation of directions

[X,Y] = meshgrid(1:c, 1:r);
phi   = pi * 2 * (X / c);
theta = pi * (Y / r);
sinTheta = sin(theta);

Dx = cos(phi) .* sinTheta;
Dy = cos(theta);
Dz = sin(phi) .* sinTheta;

for i=1:col
    img(:,:,i) = img(:,:,i) .* sinTheta;
end

%Environment projection on SH
for i=1:col
    %SH 0
    SH(i,1) = mean(mean(img(:,:,i) .* y00));
    %SH 1 -1 y
    SH(i,2) = mean(mean(img(:,:,i) .* Dy * y1x));
    %SH 1  0 z
    SH(i,3) = mean(mean(img(:,:,i) .* Dz * y1x));
    %SH 1  1 x
    SH(i,4) = mean(mean(img(:,:,i) .* Dx * y1x));
    %SH 2 -2 xy
    SH(i,5) = mean(mean(img(:,:,i) .* Dx .* Dy * y2x));
    %SH 2 -1 yz
    SH(i,6) = mean(mean(img(:,:,i) .* Dy .* Dz * y2x));
    %SH 2  1 xz
    SH(i,7) = mean(mean(img(:,:,i) .* Dx .* Dz * y2x));
    %SH 2  0 3z^2-1
    SH(i,8) = mean(mean(img(:,:,i) .* (3 * (Dz.^2) - 1) * y20));
    %SH 2  2 x^2-y^2
    SH(i,9) = mean(mean(img(:,:,i) .* (Dx.^2 - Dy.^2) * y22));
end

%scaling
SH = SH * pi * pi * 2;

%convolution
imgOut = EvaluationSH(SH, Dx, Dy, Dz);

end


function [psnr,ssim_val]=compute_psnr(im1,im2,shave_border)
if size(im1, 3) == 3,
    im1 = rgb2ycbcr(im1);
    im1 = im1(:, :, 1);
end

if size(im2, 3) == 3,
    im2 = rgb2ycbcr(im2);
    im2 = im2(:, :, 1);
end

imdff = double(im1) - double(im2);
if shave_border > 0
    imdff = shave(imdff,[shave_border,shave_border]);
end
imdff = imdff(:);
im1 = shave(im1,[shave_border,shave_border]);
im2 = shave(im2,[shave_border,shave_border]);
ssim_val = ssim_index(im1,im2);
rmse = sqrt(mean(imdff.^2));
psnr = 20*log10(255/rmse);


function [out] = naturallabel(n)
% Returns a natural label `idv` of `n` carbons.
% Assumes 1.1% C13
%
% USAGE:
%
%    [out] = naturallabel(n)
%
% INPUT:
%    n:      size of label
%
% OUTPUT:
%    out:    natural label idv of n carbons

if n <= 0
    out = 1;
    return;
end

out = zeros(2^n,1);
for i = 0:(2^n-1)
    t = dec2bin(i,n);
    c13 = sum(t-48); % subtract 48 for the '0' offset.
    c12 = n-c13;
    out(i+1) = .989^c12*.011^c13;
end


% This is material illustrating the methods from the book
% Financial Modelling  - Theory, Implementation and Practice with Matlab
% source
% Wiley Finance Series
% ISBN 978-0-470-74489-5
%
% Date: 02.05.2012
%
% Authors:  Joerg Kienitz
%           Daniel Wetterau
%
% Please send comments, suggestions, bugs, code etc. to
% kienitzwetterau_FinModelling@gmx.de
%
% (C) Joerg Kienitz, Daniel Wetterau
%
% Since this piece of code is distributed via the mathworks file-exchange
% it is covered by the BSD license
%
% This code is being provided solely for information and general
% illustrative purposes. The authors will not be responsible for the
% consequences of reliance upon using the code or for numbers produced
% from using the code.

function [pathS1, pathS2] = MC_B_path(S0,r,d,sigmaB, sigmaBS,T,Z)
%
% Simulate a path within the Bachelier model model
%
%   S0 spot price
%   K the strike price
%   r the riskless rate
%   d the dividend yield
%   sigma the volatility
%   T the maturity
%   NTime number of timesteps
%   NSim number of simulations

NSim = size(Z,1);
NTime = size(Z,2);
Delta = T/NTime;                          % The discretisation step

lnS1 = zeros(NSim,NTime+1);               % init the logspot price path
lnS1(:,1)=log(S0*exp(-d*T));              % adjust due to dividend yield
S1 = zeros(NSim,NTime+1);
S1(:,1) = S0;

%dW = randn(NSim,NTime);                   % precompute all randoms

for i=1:NTime
    lnS1(:,i+1) = lnS1(:,i) + (r-d) * Delta + sigmaBS* sqrt(Delta)*Z(:,i);
    S1(:,i+1) = S1(:,i) + (r-d) * Delta + sigmaB * sqrt(Delta) * Z(:,i);
end

pathS1 = exp(lnS1);
pathS2 = S1;
clear dW;
end


function ompspeedtest
%OMPSPEEDTEST Test the speed of the OMP functions.
%  OMPSPEEDTEST invokes the three operation modes of OMP and compares
%  their speeds. The function automatically selects the number of signals
%  for the test based on the speed of the system.
%
%  To run the test, type OMPSPEEDTEST from the Matlab prompt.
%
%  See also OMPDEMO.

%  Ron Rubinstein
%  Computer Science Department
%  Technion, Haifa 32000 Israel
%  ronrubin@cs
%
%  August 2009

% random dictionary %

n = 512;
L = 1000;
T = 8;

D = randn(n,L);
D = D*diag(1./sqrt(sum(D.*D)));    % normalize the dictionary

% select signal number according to computer speed %

x = randn(n,20);
tic; omp(D,x,[],T,'messages',-1); t=toc;
signum = ceil(20/(t/20));     % approximately 20 seconds of OMP-Cholesky

% generate random signals %

X = randn(n,signum);

% run OMP  %

printf('\nRunning OMP-Cholesky...');
tic; omp(D,X,[],T,'messages',4); t1=toc;

printf('\nRunning Batch-OMP...');
tic; omp(D,X,D'*D,T,'messages',1); t2=toc;

printf('\nRunning Batch-OMP with D''*X specified...');
tic; omp(D'*X,D'*D,T,'messages',1); t3=toc;

% display summary  %

printf('\n\nSpeed summary for %d signals, dictionary size %d x %d:\n', signum, n, L);
printf('Call syntax        Algorithm               Total time');
printf('--------------------------------------------------------');
printf('OMP(D,X,[],T)      OMP-Cholesky            %5.2f seconds', t1);
printf('OMP(D,X,G,T)       Batch-OMP               %5.2f seconds', t2);
printf('OMP(DtX,G,T)       Batch-OMP with D''*X     %5.2f seconds\n', t3);


function [CIJkcore,kn,peelorder,peellevel] = kcore_bu(CIJ,k)
%KCORE_BU       K-core
%
%   [CIJkcore,kn,peelorder,peellevel] = kcore_bu(CIJ,k);
%
%   The k-core is the largest subnetwork comprising nodes of degree at
%   least k. This function computes the k-core for a given binary
%   undirected connection matrix by recursively peeling off nodes with
%   degree lower than k, until no such nodes remain.
%
%   input:          CIJ,        connection/adjacency matrix (binary, undirected)
%                     k,        level of k-core
%
%   output:    CIJkcore,        connection matrix of the k-core.  This matrix
%                               only contains nodes of degree at least k.
%                    kn,        size of k-core
%                    peelorder, indices in the order in which they were
%                               peeled away during k-core decomposition
%                    peellevel, corresponding level - nodes at the same
%                               level were peeled away at the same time
%
%   'peelorder' and 'peellevel' are similar the the k-core sub-shells
%   described in Modha and Singh (2010).
%
%   References: e.g. Hagmann et al. (2008) PLoS Biology
%
%   Olaf Sporns, Indiana University, 2007/2008/2010/2012

%#ok<*AGROW>

peelorder = [];
peellevel = [];
iter = 0;

while 1

    % get degrees of matrix
    [deg] = degrees_und(CIJ);

    % find nodes with degree <k
    ff = find((deg<k)&(deg>0));

    % if none found -> stop
    if (isempty(ff)) break; end;            %#ok<SEPEX>

    % peel away found nodes
    iter = iter+1;
    CIJ(ff,:) = 0;
    CIJ(:,ff) = 0;

    peelorder = [peelorder; ff'];
    peellevel = [peellevel; iter.*ones(1,length(ff))'];

end;

CIJkcore = CIJ;
kn = sum(deg>0);