function Y = sym_sne(X, d, perplexity)
%SNE Implementation of symmetric Stochastic Neighbor Embedding
%
%   mappedX = sym_sne(X, no_dims, perplexity)
%
% Runs the symmetric Stochastic Neighbor Embedding algorithm. The
% high-dimensional datapoints are specified by X. The target dimensionality
% is specified in no_dims (default = 2), and the perplexity of the Gaussian
% kernel is specified in perplexity (default = 30).
% The function returns the embedded points in mappedX.
%

% This file is part of the Matlab Toolbox for Dimensionality Reduction.
% The toolbox can be obtained from http://homepage.tudelft.nl/19j49
% You are free to use, change, or redistribute this code in any way you
% want for non-commercial purposes. However, it is appreciated if you
% maintain the name of the original author.
%
% (C) Laurens van der Maaten, Delft University of Technology

    if ~exist('d', 'var') || isempty(d)
        d = 2;
    end
    if ~exist('perplexity', 'var') || isempty(perplexity)
        perplexity = 30;
    end

    % Initialize some variables
    n = size(X, 1);                 % number of instances
    eta = .05;                      % learning rate
    max_iter = 2000;                % maximum number of iterations
    jitter = 0.3;                   % initial jitter
    jitter_decay = 0.99;            % jitter decay
    momentum = 0.5;                 % initial momentum
    final_momentum = 0.8;           % final momentum
    mom_switch_iter = 750;          % iteration where momentum changes

    % Initialize embedding coordinates randomly (close to origin)
    Y = 0.0001 * rand(n, d);
    dC = zeros(n, d);
    y_incs = zeros(n, d);

    % Compute Gaussian kernel for high-dimensional data representation
    P = x2p(X, perplexity, 1e-5);                                        % use fixed perplexity
    P = P + P';
    P = P ./ sum(P(:));
    P = max(P, eps);

    % Iterating loop
    for iter=1:max_iter

        % Compute Gaussian kernel for low-dimensional data representation
        sum_Y = sum(Y .^ 2, 2);                                                     % precomputation for pairwise distances
        Q = exp(-bsxfun(@plus, sum_Y, bsxfun(@plus, sum_Y', -2 * Y * Y')) ./ 2);    % Gaussian probabilities
        Q = Q ./ repmat(sum(Q, 2), [1 n]);
        Q = max(Q, eps);

        % Compute cost function between P and Q
        if ~rem(iter, 20)
            costs = sum(P .* log((P + eps) ./ (Q + eps)), 2) ./ n;              % division by n corrects for # of datapoints
            cost = sum(costs);
            disp(['Iteration ' num2str(iter) ': error is ' num2str(cost)]);
        end

        % Compute gradient
        PQ = P - Q;
        for i=1:n
            dC(i,:) = sum(bsxfun(@times, bsxfun(@minus, Y(i,:), Y), PQ(i,:)'), 1);
        end

        % Perform the gradient search
        y_incs = momentum * y_incs - eta * dC;
        Y = Y + y_incs;
		Y = Y + jitter * randn(size(Y));
        Y = bsxfun(@minus, Y, mean(Y, 1));

        % Reduce jitter over time and change momentum
        jitter = jitter * jitter_decay;
        if iter == mom_switch_iter
            momentum = final_momentum;
        end
    end


function [ x, seed ] = quasigeometric_sample ( a, b, seed )

%*****************************************************************************80
%
%% QUASIGEOMETRIC_SAMPLE samples the Quasigeometric PDF.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    29 January 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real A, the probability of 0 successes.
%    0.0 <= A <= 1.0.
%
%    Input, real B, the depreciation constant.
%    0.0 <= B < 1.0.
%
%    Input, integer SEED, a seed for the random
%    number generator.
%
%    Output, integer X, a sample of the PDF.
%
%    Output, integer SEED, a seed for the random
%    number generator.
%
  [ cdf, seed ] = r8_uniform_01 ( seed );

  x = quasigeometric_cdf_inv ( cdf, a, b );

  return
end


function ref = physical_to_reference_tet4 ( t, n, phy )

%*****************************************************************************80
%
%% PHYSICAL_TO_REFERENCE_TET4 maps physical points to reference points.
%
%  Discussion:
%
%    Given the vertices of an order 4 physical tetrahedron and a point
%    (X,Y,Z) in the physical tetrahedron, the routine computes the value
%    of the corresponding point (R,S,T) in the reference tetrahedron.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    10 August 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real T(3,4), the coordinates of the vertices of the
%    physical tetrahedron.  The vertices are assumed to be the images of
%    (1,0,0), (0,1,0), (0,0,1) and (0,0,0) respectively.
%
%    Input, integer N, the number of points to transform.
%
%    Input, real PHY(3,N), the coordinates of physical points
%    to be transformed.
%
%    Output, real REF(3,N), the coordinates of the corresponding
%    points in the reference tetrahedron.
%
  a(1:3,1:3) = t(1:3,1:3);
  for i = 1 : 3
    a(i,1:3) = a(i,1:3) - t(i,4);
  end

  for i = 1 : 3
    ref(i,1:n) = phy(i,1:n) - t(i,4);
  end

  ref(1:3,1:n) = a(1:3,1:3) \ ref(1:3,1:n);

  return
end


function fea = NormalizeFea(fea,row)
% if row == 1, normalize each row of fea to have unit norm;
% if row == 0, normalize each column of fea to have unit norm;

if ~exist('row','var')
    row = 1;
end

% if row
%     nSmp = size(fea,1);
%     feaNorm = max(1e-14,full(sum(fea.^2,2)));
%     fea = spdiags(feaNorm.^-.5,0,nSmp,nSmp)*fea;
% else
%     nSmp = size(fea,2);
%     feaNorm = max(1e-14,full(sum(fea.^2,1))');
%     fea = fea*spdiags(feaNorm.^-.5,0,nSmp,nSmp);
% end
%
% return;

if row
    [nSmp, mFea] = size(fea);
    if issparse(fea)
        fea2 = fea';
        feaNorm = mynorm(fea2,1);
        for i = 1:nSmp
            fea2(:,i) = fea2(:,i) ./ max(1e-10,feaNorm(i));
        end
        fea = fea2';
    else
        feaNorm = sum(fea.^2,2).^.5;
        fea = fea./feaNorm(:,ones(1,mFea));
    end
else
    [mFea, nSmp] = size(fea);
    if issparse(fea)
        feaNorm = mynorm(fea,1);
        for i = 1:nSmp
            fea(:,i) = fea(:,i) ./ max(1e-10,feaNorm(i));
        end
    else
        feaNorm = sum(fea.^2,1).^.5;
        fea = fea./feaNorm(ones(1,mFea),:);
    end
end


function B=autocorr2d(H)

% Compute the 2D  autocorrelation of matrix ( Image )
% Algorithm based on Wiener - Khintchine Theorem*.
%
% * :http://mathworld.wolfram.com/Wiener-KhinchinTheorem.html
%
% Special Case :
% 2D zero mean Gaussian process with variance=1:
%           ==========================
%           | P=randn(400,600);      |
%           | CorrFunc=autocorr2d(H);|
%           ==========================
% CorrFunc is symmetric with Dirac impulsion in the center.
% with max(CorrFunc(:))=1
% July, 24, 2012
% KHMOU Youssef

[n m]=size(H);
% Divide by the size for normalization

B=abs(fftshift(ifft2(fft2(H).*conj(fft2(H)))))./(n*m);
figure, surf(B);
shading interp;


function [ w, x ] = line_o05 ( )

%*****************************************************************************80
%
%% LINE_O05 returns a 5 point quadrature rule for the unit line.
%
%  Discussion:
%
%    The integration region is:
%
%    - 1.0 <= X <= 1.0
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    16 April 2009
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Carlos Felippa,
%    A compendium of FEM integration formulas for symbolic work,
%    Engineering Computation,
%    Volume 21, Number 8, 2004, pages 867-890.
%
%  Parameters:
%
%    Output, real W(5), the weights.
%
%    Output, real X(5), the abscissas.
%
  w(1:5) = [ ...
    0.118463442528095, ...
    0.239314335249683, ...
    0.284444444444444, ...
    0.239314335249683, ...
    0.118463442528095 ];

  x(1:5) = [ ...
    -0.90617984593866399280, ...
    -0.53846931010568309104, ...
     0.00000000000000000000, ...
     0.53846931010568309104, ...
     0.90617984593866399280 ];

  return
end


function [x,tspan] = eulermaruyama(f,L,tspan,x0,Q)
%% EULERMARUYAMA - Numerical SDE solver: The Euler-Maruyama method
%
% Syntax:
%   [x,tspan] = eulermaruyama(f,L,tspan,x0,Q)
%
% In:
%   f      - Drift function, f(x,t)
%   L      - Diffusion function, L(x,t)
%   tspan  - Time steps to simulate, [t0,...,tend]
%   x0     - Initial condition
%   Q      - Spectral density (default: standard Brownian motion)
%
% Out:
%   x      - Solved values
%   tspan  - Time steps
%
% Description:
%   Integrates the system of stochatic differential equations
%     dx = f(x,t) dt + L(x,t) dbeta,  for x(0) = x0
%   over the time interval defined in tspan.
%
% Copyright:
%   2018 - Simo Särkkä and Arno Solin
%
% License:
%   This software is provided under the MIT License. See the accompanying
%   LICENSE file for details.

%%

  % Check if Q given
  if nargin<5 || isempty(Q), Q = eye(size(L(x0,tspan(1)),2)); end

  % Cholesky factor of Q
  cQ = chol(Q,'lower');

  % Number of steps
  steps = numel(tspan);

  % Allocate space
  x = zeros(size(x0,1),steps);

  % Initial state
  x(:,1) = x0;

  % Iterate
  for k=2:steps

    % Time discretization
    dt = tspan(k)-tspan(k-1);

    % Increment
    db = sqrt(dt)*cQ*randn(size(Q,1),1);

    % Step
    x(:,k) = x(:,k-1) + ...
        f(x(:,k-1),tspan(k-1))*dt + ...
        L(x(:,k-1),tspan(k-1))*db;

  end


%computes the lag of the average magnitude difference function
%> called by ::ComputePitch
%>
%> @param x: audio signal
%> @param iBlockLength: block length in samples
%> @param iHopLength: hop length in samples
%> @param f_s: sample rate of audio data
%>
%> @retval f_0 amdf lag (in Hz)
%> @retval t time stamp of f_0 estimate (in s)
% ======================================================================
function [f_0, t] = PitchTimeAmdf(x, iBlockLength, iHopLength, f_s)

    % blocking
    [x_b, t] = ToolBlockAudio(x, iBlockLength, iHopLength, f_s);
    iNumOfBlocks = size(x_b, 1);

    % allocate memory
    f_0 = zeros(1, iNumOfBlocks);

    % initialization
    f_max = 2000;
    f_min = 50;
    eta_min = round(f_s/f_max);
    eta_max = round(f_s/f_min);

    for n = 1:iNumOfBlocks

        if (sum(abs(x_b(n, :))) == 0)
            f_0(n) = 0;
            continue;
        end

        % calculate the amdf_I minimum
        afAMDF = amdf_I(x_b(n, :), eta_max);
        [fDummy, T_0(n)] = min(afAMDF(1+eta_min:end));

        % convert to Hz
        f_0(n) = f_s ./ (T_0(n) + eta_min);
    end
end

function [AMDF] = amdf_I(x, eta_max)
    K = length(x);

    AMDF = ones(1, K);

    for eta=0:min(K-1,eta_max-1)
        AMDF(eta+1) = sum(abs(x(1:K-1-eta) - x(eta+2:end))) / K;
    end
end


function n_errors = gsp_test_graph_learning

tol = 1e-5;

n_errors = test_graph_l2(tol) + test_graph_log(tol); %+ test_graph_LX(tol*100) ;
% n_errors = n_errors + test_graph_LX(tol*100);

end

function n_errors = test_graph_LX(tol)

n_errors = 0;

n = 20;
b = 1;

X = rand(20, 5);

params.verbosity = 0;
params.maxit = 10000;

W = gsp_learn_graph_LX_fro(X, b, params);

% zero diagonal
if not(all(diag(W) == 0))
    n_errors = n_errors + 1;
    warning('W has non zero diagonal');
end

% non-negative weights
if not(all(W(:) >= -tol))
    n_errors = n_errors + 1;
    warning('W has non-negative values');
end

% sum equal to n
if (norm(sum(W) - b) / n) > tol
    n_errors = n_errors + 1;
    warning('W has degrees smaller than the limit requested');
end

% W symmetric
if (norm(W - W', 'fro') / n) > tol
    n_errors = n_errors + 1;
    warning('W not symmetric');
end

end

function n_errors = test_graph_l2(tol)

n_errors = 0;

n = 20;

Z = gsp_distanz(randn(n)).^2;

params.maxit = 100000;
params.tol = 0.1 * tol;
W = gsp_learn_graph_l2_degrees(1*Z, 1, params);

% zero diagonal
if not(all(diag(W) == 0))
    n_errors = n_errors + 1;
end

% non-negative weights
if not(all(W(:) >= -tol))
    n_errors = n_errors + 1;
end

% sum equal to n
if abs(sum(W(:) - n) / n > tol)
    n_errors = n_errors + 1;
end

% % step-size correct
% params.step_size = .9;
% W2 = gsp_learn_graph_l2_degrees(10*Z, 10, params);
% if not(norm(W - W2, 'fro')/norm(W, 'fro') < 10*tol)
%     n_errors = n_errors + 1;
% end

end

function n_errors = test_graph_log(tol)

n_errors = 0;

n = 20;

Z = gsp_distanz(rand(n)).^2;

% We'll get a very sparse graph and check the degrees quality later
W = gsp_learn_graph_log_degrees(Z, 1, 1);

params.tol = tol * 1e-3;
params.maxit = 50000;
params.step_size = .9;
params.verbosity = 1;
W = gsp_learn_graph_log_degrees(Z, .031, .003, params);

% zero diagonal
if not(all(diag(W) == 0))
    n_errors = n_errors + 1;
end

% non-negative weights
if not(all(W(:) >= -tol))
    n_errors = n_errors + 1;
end

% positive degrees
if not(all(sum(W) >= tol * max(sum(W))))
    n_errors = n_errors + 1;
end

end


function julia(arg1,arg2)
%
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%
%               Julia Fractals Using Matlab
%               Written By Sridharan, Mithun Aiyswaryan
%               Christian Albrechts Universität zu Kiel, Germany
%               Mail Your Comments At: s.mithun@indiatimes.com
%
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%               Help :
%               This program takes two arguments and computes the
%               Julia sets using the provided values.
%               For the best viewing results, varhoose the arguments such that:
%
%               Argument 1 > 10     &             Argument 2 > 100
%
%               Note : The generation of fractals is  computationally
%                      very intensive and it may take you a while before
%                      you observe the results on the screen!
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

xaxis=0;
yaxis=0;
l=1.5;
x=linspace(xaxis-l,xaxis+l,arg2);
y=linspace(yaxis-l,yaxis+l,arg2);
[xtrans,ytrans]=meshgrid(x,y);
var= -.745429;
ztrans=xtrans+i*ytrans;
for k=1:arg1;
ztrans=ztrans.^2+var;
t=exp(-abs(ztrans));
end
colormap prism(256)
pcolor(t);
shading flat;
axis('square','equal','off');


% function qs = equantile(X, ps, dim)
%
% Calculates empirical (non-smoothed) quantiles of multidimensional
% arrays.  Ignores NaN entries.  Faster than, but similar to, the
% quantile() function in the MATLAB Statistics toolbox.
%
% Input:
%  X: multidimensional vector/matrix over which to calculate
%     empirical quantiles.
%  ps: vector of quantile values (between 0 and 1)
%  dim: (optional) dimension along which to calculate quantiles
%
% Output:
%  qs: vector/matrix of empirical quantiles
%
%---------------------------------------------------------------------------------
%    Author: Eugene Brevdo (http://www.math.princeton.edu/~ebrevdo/)
%---------------------------------------------------------------------------------
function qs = equantile(X,ps,dim)

ndX = ndims(X);
sX = size(X);
psn = length(ps);

assert(all(ps >= 0 & ps <= 1));

needsort = 0;
if nargin<3
  % Sort properly depending on data
  if isvector(X) && ~issorted(X)
    needsort = 1;
  elseif ndX <= 2 && ~issorted(X,'rows')
    needsort = 1;
  elseif ndX > 2
    needsort = 1;
  end

  % Which dimension are we calculating quantiles along?
  if isvector(X)
    [~,mdim] = max(sX);
    dim = mdim;
  else
    dim = 1;
  end
else
  needsort = 1;
end

% Reshape data to make ensuing steps easier (quantile-dim becomes first dim)
dperm = 1:ndX;
dperm([1 dim]) = dperm([dim 1]);
if (dim ~= 1)
  X = permute(X, dperm);
end
sXperm = sX(dperm);

% Reshape to 2D; we calculate quantiles along first dimension
X = reshape(X, sX(dim), prod(sX([1:dim-1, dim+1:ndX])));

if (needsort),
  X = sort(X,1);
end

% If we see NaNs, need to calculate quantiles row-by-row.
% Otherwise can do it in one fell swoop.
Xnan = isnan(X);
if any(any(Xnan,2))
  hasnan = 1;
else
  hasnan = 0;
end

if (~hasnan)
  ks = round(ps*(sX(dim)-1) + 1);
  assert(all(ks >= 1 & ks <= sX(dim)));
  qs = X(ks,:);
else % if (hasnan)
  ns = zeros(size(X,2), 1);
  qs = nan(psn, size(X,2));

  % Limit ourselves to non-NaN values
  for ci=1:size(X,2)
    ni = find(Xnan(:, ci), 1, 'first')-1;
    % If don't find any NaNs, use full dim
    if isempty(ni), ni = sX(dim); end

    ns(ci) = ni;
  end

  % Calculate quantiles in each case
  Xcol = 1:size(X,2);
  for pi=1:psn
    p = ps(pi);
    ks = round(p*(ns-1)+1);
    % Pull out the proper elements of sorted X
    qs(pi,ks>0) = X(sub2ind(size(X), ks(ks>0)', Xcol(ks>0)));
  end
end

% Convert back to ndim array
qs = reshape(qs, [psn, sX(1:dim-1), sX(dim+1:ndX)]);

% Move coordinates back to their proper places
if (dim ~= 1)
  qs = ipermute(qs, dperm);
end


function [x, infos] = alternating_onmf(V, rank, in_options)
% Orthogonal two-block coordinate descent (2-BCD) for non-negative matrix factorization (Alt-Orth-NMF).
%
% The problem of interest is defined as
%
%       min || V - WH ||_F^2,
%       where
%       {V, W, H} >= 0, and W or H is orthogonal, i.e., HH^T = I_r.
%
% Given a non-negative matrix V, factorized non-negative matrices {W, H} are calculated.
%
%
% Inputs:
%       matrix      V
%       rank        rank
%
% Output:
%       w           solution of w
%       infos       information
%
% References:
%       F. Pompili, N. Gillis, P.-A. Absil and F. Glineur,
%       "Two Algorithms for Orthogonal Nonnegative Matrix Factorization
%       with Application to Clustering,"
%       Neurocomputing 141, pp. 15-25, 2014.
%
%
% This file is part of NMFLibrary.
%
% This file has been ported from
% alternatingONMF.m at https://gitlab.com/ngillis/nmfbook/-/tree/master/algorithms
% by Nicolas Gillis (nicolas.gillis@umons.ac.be)
%
% Change log:
%
%       June 14, 2022 (Hiroyuki Kasai): Ported initial version
%

    % set dimensions and samples
    [m, n] = size(V);

    % set local options
    local_options = [];
    local_options.orth_h = true;
    local_options.delta = 0;
    local_options.special_stop_condition = @(epoch, infos, options, stop_options) alt_nmf_stop_func(epoch, infos, options, stop_options);

    % check input options
    if ~exist('in_options', 'var') || isempty(in_options)
        in_options = struct();
    end
    % merge options
    options = mergeOptions(get_nmf_default_options(), local_options);
    options = mergeOptions(options, in_options);

    % initialize factors
    init_options = options;
    [init_factors, ~] = generate_init_factors(V, rank, init_options);
    W = init_factors.W; % use only W

    % initialize
    method_name = 'ALT-ONMF';
    epoch = 0;
    grad_calc_count = 0;

    if options.verbose > 0
        fprintf('# %s: started ...\n', method_name);
    end

    % initialize for this algorithm
    % Xn: normalized version of X, ||Xn(:,j)||_2  1 for all j
    norm2x = sqrt(sum(V.^2,1));
    Vn = V .* repmat(1./(norm2x+1e-16), m, 1);
    normV2 = sum(V(:).^2);
    stop_options.normV2 = normV2;
    H = nnls_orth(V, W, Vn);

    % store initial info
    clear infos;
    [infos, f_val, optgap] = store_nmf_info(V, W, H, [], options, [], epoch, grad_calc_count, 0);
    orth_val = norm(H*H' - eye(rank), 'fro');
    [infos.orth] = orth_val;
    infos.prev_error =  Inf;

    if options.verbose > 1
        fprintf('%s: Epoch = 0000, cost = %.16e, optgap = %.4e\n', method_name, f_val, optgap);
    end

    % set start time
    start_time = tic();

    % main loop
    while true

        % check stop condition
        [stop_flag, reason, max_reached_flag, infos] = check_stop_condition(epoch, infos, options, stop_options);
        if stop_flag
            display_stop_reason(epoch, infos, options, method_name, reason, max_reached_flag);
            break;
        end

        % update H
        % H = argmin_H ||X-WH||_F, H >= 0, rows H orthogonal up to a scaling of the rows of H
        H = nnls_orth(V, W, Vn);

        % normalize rows of H
        norm2h = sqrt(sum(H'.^2, 1)) + 1e-16;
        H = repmat(1./norm2h', 1, n) .* H;

        % update W
        W = V * H';

        % measure gradient calc count
        grad_calc_count = grad_calc_count + m*n;

        % measure elapsed time
        elapsed_time = toc(start_time);

        % update epoch
        epoch = epoch + 1;

        % store info
        infos = store_nmf_info(V, W, H, [], options, infos, epoch, grad_calc_count, elapsed_time);
        orth_val = norm(H*H' - eye(rank), 'fro');
        [infos.orth] = [infos.orth orth_val];

        % display info
        display_info(method_name, epoch, infos, options);

        % check convergence (by original code)
        e = sqrt( (normV2-sum(sum(W.^2)))/normV2 );
        if (epoch > 2) && (abs(e_prev-e) < options.delta)
            %break;
        else
            e_prev = e;
        end
    end

    x.W = W;
    x.H = H;

end

function [stop_flag, reason, infos] = alt_nmf_stop_func(epoch, infos, options, stop_options)

    stop_flag = false;
    reason = [];

    normV2 = stop_options.normV2;
    W = infos.final_W;

    error = sqrt( (normV2-sum(sum(W.^2)))/normV2 );
    if (epoch > 2) && (abs(infos.prev_error - error) < options.delta)
        stop_flag = true;
        reason = sprintf('Relative solution change tolerance reached: %.4e < %.4e\n', abs(infos.prev_error - error), options.delta);
    else
        infos.prev_error = error;
    end

end


% Copyright (C) 2000 Paul Kienzle  <pkienzle@users.sf.net>
% Copyright (C) 2007 Peter L. Soendergaard
%
% 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/>.

% -*- texinfo -*-
% @deftypefn {Function File} {@var{h} =} hilbert (@var{f}, @var{N}, @var{dim})
% Analytic extension of real valued signal.
%
% @code{@var{h} = hilbert (@var{f})} computes the extension of the real
% valued signal @var{f} to an analytic signal. If @var{f} is a matrix,
% the transformation is applied to each column. For N-D arrays,
% the transformation is applied to the first non-singleton dimension.
%
% @code{real (@var{h})} contains the original signal @var{f}.
% @code{imag (@var{h})} contains the Hilbert transform of @var{f}.
%
% @code{hilbert (@var{f}, @var{N})} does the same using a length @var{N}
% Hilbert transform. The result will also have length @var{N}.
%
% @code{hilbert (@var{f}, [], @var{dim})} or
% @code{hilbert (@var{f}, @var{N}, @var{dim})} does the same along
% dimension @var{dim}.
% @end deftypefn

function f = oc_hilbert(f, N, dim)

% ------ PRE: initialization and dimension shifting ---------

if (nargin<1 || nargin>3)
    error('Invalid call');
end
if (nargin < 3)
    dim = [];
end
if (nargin < 2)
    N = [];
end

if ~isreal(f)
    warning ('HILBERT: ignoring imaginary part of signal');
    f = real (f);
end

D=ndims(f);

% Dummy assignment.
order=1;

if isempty(dim)
    dim=1;

    if sum(size(f)>1)==1
        % We have a vector, find the dimension where it lives.
        dim=find(size(f)>1);
    end

else
    if (numel(dim)~=1 || ~isnumeric(dim))
        error('HILBERT: dim must be a scalar.');
    end
    if rem(dim,1)~=0
        error('HILBERT: dim must be an integer.');
    end
    if (dim<1) || (dim>D)
        error('HILBERT: dim must be in the range from 1 to %d.',D);
    end

end

if (numel(N)>1 || ~isnumeric(N))
    error('N must be a scalar.');
elseif (~isempty(N) && rem(N,1)~=0)
    error('N must be an integer.');
end

if dim>1
    order=[dim, 1:dim-1,dim+1:D];

    % Put the desired dimension first.
    f=permute(f,order);

end

Ls=size(f,1);

% If N is empty it is set to be the length of the transform.
if isempty(N)
    N=Ls;
end

% Remember the exact size for later and modify it for the new length
permutedsize=size(f);
permutedsize(1)=N;

% Reshape f to a matrix.
f=reshape(f,size(f,1),numel(f)/size(f,1));
W=size(f,2);

if ~isempty(N)
    f = oc_postpad(f,N);
end

% ------- actual computation -----------------
if N>2
    f=fft(f);

    if rem(N,2)==0
        f=[f(1,:);
            2*f(2:N/2,:);
            f(N/2+1,:);
            zeros(N/2-1,W)];
    else
        f=[f(1,:);
            2*f(2:(N+1)/2,:);
            zeros((N-1)/2,W)];
    end

    f=ifft(f);
end

% ------- POST: Restoration of dimensions ------------

% Restore the original, permuted shape.
f=reshape(f,permutedsize);

if dim>1
    % Undo the permutation.
    f=ipermute(f,order);
end

end

%!demo
%! % notice that the imaginary signal is phase-shifted 90 degrees
%! t=linspace(0,10,256);
%! z = hilbert(sin(2*pi*0.5*t));
%! grid on; plot(t,real(z),';real;',t,imag(z),';imag;');

%!demo
%! % the magnitude of the hilbert transform eliminates the carrier
%! t=linspace(0,10,1024);
%! x=5*cos(0.2*t).*sin(100*t);
%! grid on; plot(t,x,'g;z;',t,abs(hilbert(x)),'b;|hilbert(z)|;');


function r = tenRank( A, tol )
%TENRANK Calculates the multilinear rank.
%   R = TENRANK( A, TOL ) calculates the multilinear rank R of the
%   given tensor A. All singular values below the specified tolerance
%   TOL are considered to be zero.
%
%   R = TENRANK( A ) calculates the multilinear rank R of the given
%   tensor A. The default tolerance 1e-5 is chosen for the cutoff.
%

%   GeomCG Tensor Completion. Copyright 2013 by
%   Michael Steinlechner
%   Questions and contact: michael.steinlechner@epfl.ch
%   BSD 2-clause license, see LICENSE.txt

    if ~exist('tol','var')
        tol = 1e-5;
    end

    r = zeros( 1, ndims( A ) );

    for i = 1:ndims( A )
        r(i) = rank( double( tenmat( A, i ) ), tol);
    end
end


function moment = truncated_normal_ab_moment ( order, mu, s, a, b )

%*****************************************************************************80
%
%% TRUNCATED_NORMAL_AB_MOMENT returns a moment of the truncated Normal PDF.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    11 September 2013
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Phoebus Dhrymes,
%    Moments of Truncated Normal Distributions,
%    May 2005.
%
%  Parameters:
%
%    Input, integer ORDER, the order of the moment.
%    0 <= ORDER.
%
%    Input, real MU, S, the mean and standard deviation of the
%    parent Normal distribution.
%    0 < S.
%
%    Input, real A, B, the lower and upper truncation limits.
%    A < B.
%
%    Output, real MOMENT, the moment of the PDF.
%
  if ( order < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'TRUNCATED_NORMAL_AB_MOMENT - Fatal error!\n' );
    fprintf ( 1, '  ORDER < 0.\n' );
    error ( 'TRUNCATED_NORMAL_AB_MOMENT - Fatal error!\n' );
  end

  if ( s <= 0.0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'TRUNCATED_NORMAL_AB_MOMENT - Fatal error!\n' );
    fprintf ( 1, '  S <= 0.0.\n' );
    error ( 'TRUNCATED_NORMAL_AB_MOMENT - Fatal error!\n' );
  end

  if ( b <= a )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'TRUNCATED_NORMAL_AB_MOMENT - Fatal error!\n' );
    fprintf ( 1, '  B <= A.\n' );
    error ( 'TRUNCATED_NORMAL_AB_MOMENT - Fatal error!\n' );
  end

  a_h = ( a - mu ) / s;
  a_pdf = normal_01_pdf ( a_h );
  a_cdf = normal_01_cdf ( a_h );

  if ( a_cdf == 0.0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'TRUNCATED_NORMAL_AB_MOMENT - Fatal error!\n' );
    fprintf ( 1, '  PDF/CDF ratio fails, because A_CDF is too small.\n' );
    fprintf ( 1, '  A_PDF = %g\n', a_pdf );
    fprintf ( 1, '  A_CDF = %g\n', a_cdf );
    error ( 'TRUNCATED_NORMAL_AB_MOMENT - Fatal error!\n' );
  end

  b_h = ( b - mu ) / s;
  b_pdf = normal_01_pdf ( b_h );
  b_cdf = normal_01_cdf ( b_h );

  if ( b_cdf == 0.0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'TRUNCATED_NORMAL_AB_MOMENT - Fatal error!\n' );
    fprintf ( 1, '  PDF/CDF ratio fails, because B_CDF too small.\n' );
    fprintf ( 1, '  B_PDF = %g\n', b_pdf );
    fprintf ( 1, '  B_CDF = %g\n', b_cdf );
    error ( 'TRUNCATED_NORMAL_AB_MOMENT - Fatal error!\n' );
  end

  moment = 0.0;
  irm2 = 0.0;
  irm1 = 0.0;

  for r = 0 : order

    if ( r == 0 )
      ir = 1.0;
    elseif ( r == 1 )
      ir = - ( b_pdf - a_pdf ) / ( b_cdf - a_cdf );
    else
      ir = ( r - 1 ) * irm2 ...
        - ( b_h ^ ( r - 1 ) * b_pdf - a_h ^ ( r - 1 ) * a_pdf ) ...
        / ( b_cdf - a_cdf );
    end

    moment = moment + r8_choose ( order, r ) ...
      * mu ^ ( order - r ) ...
      * s ^ r * ir;

    irm2 = irm1;
    irm1 = ir;

  end

  return
end


function a = kahan_inverse ( alpha, n )

%*****************************************************************************80
%
%% KAHAN_INVERSE returns the inverse of the KAHAN matrix.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    13 October 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real ALPHA, the scalar that defines A.  A typical
%    value is 1.2.  The "interesting" range of ALPHA is 0 < ALPHA < PI.
%
%    Input, integer N, the order of A.
%
%    Output, real A(N,N), the matrix.
%
  a = zeros ( n, n );

  ci = cos ( alpha );

  for i = 1 : n
    for j = 1 : n

      if ( i == j )
        a(i,j) = 1.0;
      elseif ( i == j - 1 )
        a(i,j) = ci;
      elseif ( i < j )
        a(i,j) = ci * ( 1.0 + ci )^(j-i-1);
      else
        a(i,j) = 0.0;
      end

    end
  end
%
%  Scale the columns.
%
  for j = 1 : n
    si = sin ( alpha )^j;
    a(1:n,j) = a(1:n,j) / si;
  end

  return
end


function test_int_test04 ( )

%*****************************************************************************80
%
%% TEST04 applies a composite Gauss-Legendre rule to finite interval 1D problems.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    12 November 2009
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST04\n' );
  fprintf ( 1, '  Use a composite 4 point Gauss-Legendre rule,\n' );
  fprintf ( 1, '  for 1D finite interval problems.\n' );

  prob_num = p00_prob_num ( );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Problem       Exact\n' );
  fprintf ( 1, '         Ints   Approx	   Error\n' );
%
%  Pick a problem.
%
  for prob = 1 : prob_num

    exact = p00_exact ( prob );

    fprintf ( 1, '\n' );
    fprintf ( 1, '  %4d        %14f\n', prob, exact );
%
%  Pick a number of subintervals.
%
    for int_log = 0 : 7

      int_num = 2^int_log;

      result = p00_gauss_legendre ( prob, int_num );

      error = abs ( exact - result );

      fprintf ( 1, '        %4d  %14f  %14e\n', int_num, result, error );

    end

  end

  return
end


function r=rot4x(theta)
    % r = rot4x(theta)
    %
    % rotx produces a 4x4 rotation matrix representing
    % a rotation by theta radians about the x axis.
    %
    %	Argument definitions:
    %
    %	theta = rotation angle in radians
    c = cos(theta);
    s = sin(theta);
    r = [1  0  0 0;
        0  c -s 0;
        0  s  c 0;
        0  0  0 1];


function[teps]=maternedge(varargin)
%MATERNEDGE  Long-time cutoff edge for the Matern impulse response function.
%
%   TE=MATERNEDGE(ALPHA,H,EPSILON) determines a long-time cutoff for the
%   Green's function of a Matern process characterized by slope parameter
%   ALPHA and range parameter H.
%
%   TE is the (approximately) the first time at which the ratio of the
%   time-integrated magnitude of the Green's function, to the value it
%   obtains at infinity, has risen to within EPSILON of unity.
%
%   TE is approximate because of discretization of time.  It will always be
%   greater than the actual time at which the EPSILON level is reached.
%
%   See Lilly et al. (2017) for details.
%
%   MATERNEDGE is a low-level function that is called by MATERNOISE.
%
%   See also MATERNSPEC, MATERNCOV, MATERNIMP, MATERNOISE.
%
%   'maternedge --t' runs some tests.
%
%   Usage: te=maternedge(alpha,h,epsilon);
%   __________________________________________________________________
%   This is part of JLAB --- type 'help jlab' for more information
%   (C) 2013--2017 J.M. Lilly --- type 'help jlab_license' for details

if strcmpi(varargin{1}, '--t')
    maternedge_test,return
end

alpha=varargin{1};
h=varargin{2};
epsilon=varargin{3};

arrayify(alpha,h,epsilon);
teps=zeros(size(alpha));

tnorm=[0:0.001:20]';
%tnorm=[0:0.01:20]';
for i=1:length(alpha)

    gint=gammainc(tnorm,alpha(i));  %This is integral divided by its total
    %Note Matlab defines the incomplete gamma function as a ratio to gamma
    ii=find(gint>1-epsilon(i),1,'first');
    %plot(tnorm,gint),hlines(1),hold on
    if ~isempty(ii)
        teps(i)=tnorm(ii)./h(i);
    else
        %disp('The Green''s function does not cross this threshold within 20 e-folding times.')
        teps(i)=inf;
    end
end

if aresame(size(varargin{1}),size(varargin{2}))
    teps=reshape(teps,size(varargin{1},1),size(varargin{1},2));
end

function[]=maternedge_test

alpha=[1 1.5 2 3 4];
%alpha=[3/4 1 1.5 2 3 4];
h=[.01 .02 .05 .2 1];
[alpha,h]=meshgrid(alpha,h);
h=h.*alpha;
epsilon=1e-2;

vcolon(alpha,h);
te=maternedge(alpha,h,epsilon);

t=[1e-6:0.0001:20]';
tnorm=oprod(t,1./h);
g=zeros(size(tnorm));
gint=zeros(size(tnorm));
for i=1:length(alpha)
    d=sqrt(frac(h(i).^(2*alpha(i)-1),materncfun(alpha(i))));
    g(:,i)=frac(1,d)*maternimp(tnorm(:,i),alpha(i),h(i));
    gint(:,i)=cumsum(g(:,i)).*(tnorm(2,i)-tnorm(1,i));
    gint(:,i)=gint(:,i).*h(i).^alpha(i);
end

te2=zeros(size(te));
for i=1:length(alpha)
     ii=find(gint(:,i)>1-epsilon,1,'first');
     if ~isempty(ii)
         te2(i)=tnorm(ii,i);
     else
         te2(i)=nan;
     end
end

%abs(te2-te)./te

reporttest('MATERNEDGE matches explicit calculation to within one percent',allall(abs(te2-te)./te<.01))


function value = pyramid_unit_volume_3d ( )

%*****************************************************************************80
%
%% PYRAMID_UNIT_VOLUME_3D returns the volume of a unit pyramid in 3D.
%
%  Integration region:
%
%    - ( 1 - Z ) <= X <= 1 - Z
%    - ( 1 - Z ) <= Y <= 1 - Z
%              0 <= Z <= 1.
%
%  Discussion:
%
%    A pyramid with square base can be regarded as the upper half of a
%    3D octahedron.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    31 March 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, real VALUE, the volume of the pyramid.
%
  value = 4.0 / 3.0;

  return
end


function a = bab ( n, alpha, beta )

%*****************************************************************************80
%
%% BAB returns the BAB matrix.
%
%  Example:
%
%    N = 5
%    ALPHA = 5, BETA = 2
%
%    5  2  .  .  .
%    2  5  2  .  .
%    .  2  5  2  .
%    .  .  2  5  2
%    .  .  .  2  5
%
%  Properties:
%
%    A is banded, with bandwidth 3.
%
%    A is tridiagonal.
%
%    Because A is tridiagonal, it has property A (bipartite).
%
%    A is Toeplitz: constant along diagonals.
%
%    A is symmetric: A' = A.
%
%    Because A is symmetric, it is normal.
%
%    Because A is normal, it is diagonalizable.
%
%    A is persymmetric: A(I,J) = A(N+1-J,N+1-I).
%
%    The family of matrices is nested as a function of N.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    05 November 2007
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    CM da Fonseca, J Petronilho,
%    Explicit Inverses of Some Tridiagonal Matrices,
%    Linear Algebra and Its Applications,
%    Volume 325, 2001, pages 7-21.
%
%  Parameters:
%
%    Input, integer N, the order of the matrix.
%
%    Input, real ALPHA, BETA, the parameters.
%
%    Output, real A(N,N), the matrix.
%
  a = zeros ( n, n );

  for i = 1 : n
    a(i,i) = alpha;
  end

  for i = 1 : n - 1
    a(i,i+1) = beta;
    a(i+1,i) = beta;
  end

  return
end


function [cm, cSq] = DiscreteFrechetDist(P,Q,dfcn)
% Calculates the discrete Frechet distance between curves P and Q
%
% [cm, cSq] = DiscreteFrechetDist(P,Q)
% [cm, cSq] = DiscreteFrechetDist(...,dfcn)
%
% P and Q are two sets of points that define polygonal curves with rows of
% vertices (data points) and columns of dimensionality. The points along
% the curves are taken to be in the order as they appear in P and Q.
%
% Returned in cm is the discrete Frechet distance, aka the coupling
% measure, which is zero when P equals Q and grows positively as the curves
% become more dissimilar.
%
% The optional dfcn argument allows the user to specify a function with
% which to calculate distance between points in P and Q. If not provided,
% the L2 norm is used.
%
% The secondary output, cSq, is the coupling sequence, that is, the
% sequence of steps along each curve that must be followed to achieve the
% minimum coupling distance, cm. The output is returned in the form of a
% matrix with column 1 being the index of each point in P and column 2
% being the index of each point in Q. (NOTE: the coupling sequence is not
% unique in general)
%
% Explanation:
% The Frechet distance is a measure of similarity between to curves, P and
% Q. It is defined as the minimum cord-length sufficient to join a point
% traveling forward along P and one traveling forward along Q, although the
% rate of travel for either point may not necessarily be uniform.
%
% The Frechet distance, FD, is not in general computable for any given
% continuous P and Q. However, the discrete Frechet Distance, also called
% the coupling measure, cm, is a metric that acts on the endpoints of
% curves represented as polygonal chains. The magnitude of the coupling
% measure is bounded by FD plus the length of the longest segment in either
% P or Q,  and approaches FD in the limit of sampling P and Q.
%
% This function implements the algorithm to calculate discrete Frechet
% distance outlined in:
% T. Eiter and H. Mannila. Computing discrete Frechet distance. Technical
% Report 94/64, Christian Doppler Laboratory, Vienna University of
% Technology, 1994.
%
%
%
% EXAMPLE:
% % create data
% t = 0:pi/8:2*pi;
% y = linspace(1,3,6);
% P = [(2:7)' y']+0.3.*randn(6,2);
% Q = [t' sin(t')]+2+0.3.*randn(length(t),2);
% [cm, cSq] = DiscreteFrechetDist(P,Q);
% % plot result
% figure
% plot(Q(:,1),Q(:,2),'o-r','linewidth',3,'markerfacecolor','r')
% hold on
% plot(P(:,1),P(:,2),'o-b','linewidth',3,'markerfacecolor','b')
% title(['Discrete Frechet Distance of curves P and Q: ' num2str(cm)])
% legend('Q','P','location','best')
% line([2 cm+2],[0.5 0.5],'color','m','linewidth',2)
% text(2,0.4,'dFD length')
% for i=1:length(cSq)
%   line([P(cSq(i,1),1) Q(cSq(i,2),1)],...
%        [P(cSq(i,1),2) Q(cSq(i,2),2)],...
%        'color',[0 0 0]+(i/length(cSq)/1.35));
% end
% axis equal
% % display the coupling sequence along with each distance between points
% disp([cSq sqrt(sum((P(cSq(:,1),:) - Q(cSq(:,2),:)).^2,2))])
%
%
%
% %%% ZCD June 2011 %%%
% %%% edits ZCD May 2013: 1) remove excess arguments to internal functions
% and persistence for speed, 2) added example, 3) allowed for user defined
% distance function, 4) added aditional output option for coupling sequence
%

% size of the data curves
sP = size(P);
sQ = size(Q);

% check validity of inputs
if sP(2)~=sQ(2)
    error('Curves P and Q must be of the same dimension')
elseif sP(1)==0
    cm = 0;
    return;
end

% initialize CA to a matrix of -1s
CA = ones(sP(1),sQ(1)).*-1;

% distance function
if nargin==2
    dfcn = @(u,v) sqrt(sum( (u-v).^2 ));
end

% final coupling measure value
cm = c(sP(1),sQ(1));

% obtain coupling measure via backtracking procedure
if nargout==2
    cSq = zeros(sQ(1)+sP(1)+1,2);    % coupling sequence
    CApad = [ones(1,sQ(1)+1)*inf; [ones(sP(1),1)*inf CA]];  % pad CA
    Pi=sP(1)+1; Qi=sQ(1)+1; count=1;  % counting variables
    while Pi~=2 || Qi~=2
        % step down CA gradient
        [v,ix] = min([CApad(Pi-1,Qi) CApad(Pi-1,Qi-1) CApad(Pi,Qi-1)]);
        if ix==1
            cSq(count,:) = [Pi-1 Qi];
            Pi=Pi-1;
        elseif ix==2
            cSq(count,:) = [Pi-1 Qi-1];
            Pi=Pi-1; Qi=Qi-1;
        elseif ix==3
            cSq(count,:) = [Pi Qi-1];
            Qi=Qi-1;
        end
        count=count+1;
    end
    % format output: remove extra zeroes, reverse order, subtract off
    % padding value, and add in the last point
    cSq = [flipud(cSq(1:find(cSq(:,1)==0,1,'first')-1,:))-1; sP(1) sQ(1)];
end

% debug
% assignin('base','CAw',CA)

function CAij = c(i,j)
    % coupling search function
    if CA(i,j)>-1
        % don't update CA in this case
        CAij = CA(i,j);
    elseif i==1 && j==1
        CA(i,j) = dfcn(P(1,:),Q(1,:));     % update the CA permanent
        CAij = CA(i,j);                    % set the current relevant value
    elseif i>1 && j==1
        CA(i,j) = max( c(i-1,1), dfcn(P(i,:),Q(1,:)) );
        CAij = CA(i,j);
    elseif i==1 && j>1
        CA(i,j) = max( c(1,j-1), dfcn(P(1,:),Q(j,:)) );
        CAij = CA(i,j);
    elseif i>1 && j>1
        CA(i,j) = max( min([c(i-1,j), c(i-1,j-1), c(i,j-1)]),...
            dfcn(P(i,:),Q(j,:)) );
        CAij = CA(i,j);
    else
        CA(i,j) = inf;
    end
end     % end function, c

end     % end main function


% Chapter 17 - Neural Networks.
% Programs_17e - Bifurcation Diagram for a Simple Bistable Neuromodule.
% Copyright Birkhauser 2013. Stephen Lynch.

% Bifurcation diagram for a two-neuron module. (See Figure 17.15).
% Vary bias b1.
clear all
format long;
halfN=1000;N=2*halfN+1;N1=1+halfN;Max=10;a=1;alpha=0.3;
x=zeros(1,N);y=zeros(1,N);
b2=3;w11=7;w12=-4;w21=5;start=-5;
x(1)=-10;y(1)=-3;

% Ramp the power up
for n=1:halfN
    b1=(start+n*Max/halfN);
    x(n+1)=b1+w11*(exp(a*x(n))-exp(-a*x(n)))/(exp(a*x(n))+exp(-a*x(n)))+w12*(exp(alpha*y(n))-exp(-alpha*y(n)))/(exp(alpha*y(n))+exp(-alpha*y(n)));
    y(n+1)=b2+w21*(exp(a*x(n))-exp(-a*x(n)))/(exp(a*x(n))+exp(-a*x(n)));
end

% Ramp the power down
for n=N1:N
    b1=(start+2*Max-n*Max/halfN);
    x(n+1)=b1+w11*(exp(a*x(n))-exp(-a*x(n)))/(exp(a*x(n))+exp(-a*x(n)))+w12*(exp(alpha*y(n))-exp(-alpha*y(n)))/(exp(alpha*y(n))+exp(-alpha*y(n)));
    y(n+1)=b2+w21*(exp(a*x(n))-exp(-a*x(n)))/(exp(a*x(n))+exp(-a*x(n)));
end

% Plot the bifurcation diagrams
fsize=14;
subplot(2,1,1)
hold on
set(gca,'XTick',0:halfN/2:N,'FontSize',fsize);
set(gca,'YTick',-Max:5:Max,'FontSize',fsize);
plot(x(1:N),'-','MarkerSize',1,'color','k')
xlabel('Number of Iterations','FontSize',fsize);
ylabel('x_n','FontSize',fsize);
hold off
x1=zeros(1,N);w=zeros(1,N);

for n=1:halfN
    x1(n)=x(N+1-n);
    w(n)=start+n*Max/halfN;
end

subplot(2,1,2)
hold on
set(gca,'XTick',start:5:start+Max,'FontSize',fsize);
set(gca,'YTick',-Max:5:Max,'FontSize',fsize);
plot(w(1:halfN),x(1:halfN),'-','MarkerSize',1,'color','k');
plot(w(1:halfN),x1(1:halfN),'-','MarkerSize',1,'color','k');
xlabel('b_1','FontSize',fsize);
ylabel('x_n','FontSize',fsize);
hold off

% End of Programs_17e.


% EASY12   Detailed explanations of a Matlab implementation
%          of the Lambda method. The notation follows the one
%          introduced in Strang and Borre, pages 495--499

%Kai Borre 30-06-2008
%Copyright (c) by Kai Borre
%$Revision: 1.0 $  $Date: 2008/06/30  $

fprintf('\n')
echo on
% Test example
hat_I = [5.45;3.1;2.97];
%hat_I =[0; 1];
n = size(hat_I,1);
Q_hat_I = [6.29 5.978 .544; 5.978 6.292 2.34; .544 2.34 6.288];
%Q_hat_I = [53.40 38.40;38.40 28.00];
echo off

% Given float ambiguities
fprintf('\nFloat ambiguities hat_I')
for i = 1:n
    fprintf('\n%12.3f', hat_I(i,1))
end

% Original covariance matrix for hat_I
fprintf('\n\nCovariance matrix for hat_I')
for i = 1:n
    fprintf('\n')
    for j = 1:n
        fprintf('%12.3f', Q_hat_I(i,j))
    end
end

fprintf('\n\n')
echo on
% Shift of hat_I in order to secure that -1 < hat_I <= +1
echo off

shifts = hat_I-rem(hat_I,1);
fprintf('\n\nInteger shifts of hat_I')
for i = 1:n
    fprintf('\n%12.0f', shifts(i,1))
end

% Remainders of hat_I
hat_I_r = rem(hat_I,1);
fprintf('\n\nRemainders of hat_I')
for i = 1:n
    fprintf('\n%12.3f', hat_I_r(i,1))
end

% L^T*D*L factorization of Q_hat_I
% For consistency we do not use the Matlab ldl function
[L,D] = ldldecom(Q_hat_I);
fprintf('\n\nQ_hat_I is factorized into L^T*D*L')
fprintf('\n\nThe lower triangular L')
for i = 1:n
    fprintf('\n')
    for j = 1:n
        fprintf('%12.3f',L(i,j))
    end
end
fprintf('\n\nThe diagonal matrix D\n')
for i = 1:n
    fprintf('%12.3f',D(i))
end

% Computing the size of the search volume
chi2 = chistart(D,L,hat_I_r,1);
fprintf('\n\nchi^2 = %5.3f\n',chi2)

% Doing the decorrelation
[Q_bar_I,Z,L_t,D_t] = decorrel(Q_hat_I,hat_I_r);
fprintf('\nInteger transformation matrix Z')
for i = 1:n
    fprintf('\n')
    for j = 1:n
        fprintf('%12.0f',Z(i,j))
    end
end

% hat_I transformed: I_s = Z'*hat_I_r
fprintf('\n\nTransformed, shifted ambiguities I_s = Z^T*hat_I_r')
I_s = Z'*hat_I_r;
for i = 1:n
    fprintf('\n%12.3f',I_s(i))
end

% The transformed, decorrelated covariance matrix: Q_bar_I = Z^T*Q_hat_I*Z
fprintf('\n\nThe transformed, decorrelated covariance matrix Q_bar_I = Z^T*Q_hat_I*Z.')
fprintf('\n\nQ_bar_I = Z^T*Q_hat_I*Z')
for i = 1:n
    fprintf('\n')
    for j = 1:n
        fprintf('%12.3f',Q_bar_I(i,j))
    end
end
fprintf('\nNote the deminished off-diagonal terms!')
fprintf('\n\nThe lower triangular L_t used in the search')
for i = 1:n
    fprintf('\n')
    for j = 1:n
        fprintf('%12.3f',L_t(i,j))
    end
end
fprintf('\n\nThe diagonal matrix D_t used in the seach\n')
for i = 1:n
    fprintf('%12.3f',D_t(i))
end

fprintf('\n\n')
echo on
% Determining the size of the search volume for the transformed L_t and D_t
echo off

chi2 = chistart(D_t,L_t,I_s,1);
fprintf('\n\nchi^2 for the transformed problem  =  %5.3f\n',chi2)

fprintf('\nThe search domain is defined as')
fprintf('\n(I-hat_I_r)^T*(Z^T*Q_hat_I*Z)*(I-hat_I_r) < chi^2,  for I integer')

[bar_I,sqnorm,ierr] = lsearch(I_s,L_t,D_t,chi2,1);
%bar_I = (bar_I' * inv(Z))'+shifts;
bar_I = (bar_I'/Z)' + shifts;
fprintf('\n\nFixed ambiguities bar_I')
for i = 1:n
    fprintf('\n%12.0f', bar_I(i,1))
end
fprintf('\n\n')
%%%%%%%%%%%%%%%%%%%%%%%%%%% end easy12.m  %%%%%%%%%%%%


u0 = double(imread('58468899e2951a4b87b00897.png'));
u0 = mean(u0,3);

[M N] = size(u0);
MN = M*N;
I=reshape([1:M*N],M,N);
east=[I(:,2:end), I(:,end)];
north=[I(2:end,:); I(end,:)];
D1 = sparse(I,east,1,MN,MN) -speye(MN,MN);
D2 = sparse(I,north,1,MN,MN) -speye(MN,MN);
D = [D1 ; D2];

h0 = [ 1 2 1 ];
h = h0
for i=1:5 %% level of blur
    h = conv(h0,h);
end
size(h)
h = h'*h;
h = h/sum(sum(h));

stddev=5;
g = filter2(h,u0,'valid');
[Ms Ns]=size(g);
g = g + stddev*randn(Ms,Ns);

figure(1);
imagesc(u0); colormap(gray); %drawnow();
figure(2);
imagesc(g); colormap(gray); drawnow();

u=zeros(size(u0));
L2 = 8;
tau = 1; %% max value for tau = 1;
sig = 1/tau/L2;
lambda = .2;

p = zeros(2*MN,1);
%% primal-dual
for i=1:1000
    um = u;
    u = u-tau*(conv2(h,filter2(h,u,'valid')-g,'full') + reshape(D'*p,M,N));
    um = 2*u-um;
    p = p + sig*D*um(:);
    no= max(1,hypot(p(1:MN),p(MN+1:end))/lambda);
    p = p./[no;no];
    if mod(i,20)==0
        i
        figure(3);
        imagesc(u);
        colormap(gray); drawnow();
    end
end


function [M, H, noiseFractions] = hyperNacp(M, h, w)
% HYPERMNF Performs the noise adjusted principal component transform (NACP)
%  hyperMnf performs the noise adjust principal component transform on the
% data and uses spatial (row) offsets of the data to estimate the
% covariance matrix of the data.
%
% Usage
%   M = hyperNacp(M, h, w)
% Inputs
%   M - 2D matrix (p x N)
%   h - height of image in pixels
%   w - width of image in pixels
% Outputs
%   M - 2D transformed data
%   H - 2D transformation matrix
%   noiseFractions - Estimates of the noise fraction for each band
%
% References
%   C-I Change and Q Du, "Interference and Noise-Adjusted Principal
% Components Analysis," IEEE TGRS, Vol 36, No 5, September 1999.

[p, N] = size(M);

% Remove mean from data
u = mean(M.').';
for k=1:N
    M(:,k) = M(:,k) - u;
end

% Compute to rotation of the signal+noise
sigmaZ = hyperCov(M);
M = hyperConvert3d(M, h, w, p);

% Estimate the covariance of the noise.
dX = zeros(h-1, w, p);
for i=1:(h-1)
    dX(i, :, :) = M(i, :, :) - M(i+1, :, :);
end
dX = hyperConvert2d(dX);

% Compute the covariance of the noise signal estimate.
sigmaN = hyperCov(dX);

% Orthonormalize the noise subspace.
[U,deltaN,E] = svd(sigmaN);
F = E*inv(sqrt(deltaN));  % Rotation components of noise orthonormalized
% F now whitens the noise.

% Rotates the signal+noise cov so that the noise is whitened (all noise
% powers are equal)
sigmaAdj = F'*sigmaZ*F;

[U,gammaAdj,G] = svd(sigmaAdj);
H = G*F;

% Compute noise fractions
noiseFractions = diag(gammaAdj);

% Perform transform
M = H*hyperConvert2d(M);


function glscf = CO_glscf(y,alpha,beta,tau)
% CO_glscf  The generalized linear self-correlation function of a time series.
%
% This function was introduced in Queiros and Moyano in Physica A, Vol. 383, pp.
% 10--15 (2007) in the paper "Yet on statistical properties of traded volume:
% Correlation and mutual information at different value magnitudes"
% https://www.sciencedirect.com/science/article/pii/S0378437107004645
%
% The function considers magnitude correlations.
%
%---INPUTS:
% y, the input time series
% alpha and beta are real and nonzero parameters
% tau is the time-delay (can also be 'tau' to set to first zero-crossing of the ACF)
%
% When alpha = beta estimates how values of the same order of magnitude are
% related in time
% When alpha ~= beta, estimates correlations between different magnitudes of the
% time series.

% ------------------------------------------------------------------------------
% Copyright (C) 2020, Ben D. Fulcher <ben.d.fulcher@gmail.com>,
% <http://www.benfulcher.com>
%
% If you use this code for your research, please cite the following two papers:
%
% (1) B.D. Fulcher and N.S. Jones, "hctsa: A Computational Framework for Automated
% Time-Series Phenotyping Using Massive Feature Extraction, Cell Systems 5: 527 (2017).
% DOI: 10.1016/j.cels.2017.10.001
%
% (2) B.D. Fulcher, M.A. Little, N.S. Jones, "Highly comparative time-series
% analysis: the empirical structure of time series and their methods",
% J. Roy. Soc. Interface 10(83) 20130048 (2013).
% DOI: 10.1098/rsif.2013.0048
%
% This function 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/>.
% ------------------------------------------------------------------------------

% ------------------------------------------------------------------------------
%% Check inputs and set defaults
% ------------------------------------------------------------------------------
if nargin < 4 || isempty(tau)
    tau = 'tau';
end

% Set tau to first zero-crossing of the autocorrelation function with the input 'tau'
if strcmp(tau,'tau')
    tau = CO_FirstCrossing(y,'ac',0,'discrete');
end

% Take magnitudes of time-delayed versions of the time series:
y1 = abs(y(1:end-tau));
y2 = abs(y(1+tau:end));

glscf = (mean((y1.^alpha).*(y2.^beta)) - mean(y1.^alpha)*mean(y2.^beta)) / ...
     		    (sqrt(mean(y1.^(2*alpha)) - mean(y1.^alpha)^2) ...
     		          * sqrt(mean(y2.^(2*beta)) - mean(y2.^beta)^2));

end


function [H_o_j, A_j, H_x_j] = calcHoj(p_f_G, msckfState, camStateIndices)
%CALCHOJ Calculates H_o_j according to Mourikis 2007
% Inputs: p_f_G: feature location in the Global frame
%         msckfState: the current window of states
%         camStateIndex: i, with camState being the ith camera pose in the window
% Outputs: H_o_j, A

N = length(msckfState.camStates);
M = length(camStateIndices);
H_f_j = zeros(2*M, 3);
H_x_j = zeros(2*M, 12 + 6*N);

c_i = 1;
for camStateIndex = camStateIndices
    camState = msckfState.camStates{camStateIndex};

    C_CG = quatToRotMat(camState.q_CG);
    %The feature position in the camera frame
    p_f_C = C_CG*(p_f_G - camState.p_C_G);

    X = p_f_C(1);
    Y = p_f_C(2);
    Z = p_f_C(3);

    J_i = (1/Z)*[1 0 -X/Z; 0 1 -Y/Z];

    H_f_j((2*c_i - 1):2*c_i, :) = J_i*C_CG;

    H_x_j((2*c_i - 1):2*c_i,12+6*(camStateIndex-1) + 1:12+6*(camStateIndex-1) + 3) = J_i*crossMat(p_f_C);
    H_x_j((2*c_i - 1):2*c_i,(12+6*(camStateIndex-1) + 4):(12+6*(camStateIndex-1) + 6)) = -J_i*C_CG;

    c_i = c_i + 1;
end

A_j = null(H_f_j');
H_o_j = A_j'*H_x_j;

end


function [H]=hessianScalar(varargin)

% function [H]=hessianScalar(U,v,cellOpt)
% ------------------------------------------------------------------------
%
% This function computes the Hessian matrix of the scalar function U for
% each point in U. U may be a vector, a 2D matrix or a 3D matrix. The
% vector v denotes the points spacing between the data entries in U. If v
% is not supplied the spacing is assumed to be homogeneous and unity. If
% the input is n dimensional array consisting of m entries then the output
% is a matrix (if cellOpt==0) the size of mx(n^2) (whereby the colum
% entries define the entries in a Hessian matrix and row entries relate to
% elements in the input array). If cellOpt==1 then the output is reformed
% into a cell array that matches the size of the input aray. Each cell
% entry then contains the nxn Hessian matrix.
%
% See also: |gradient|,|hessian|,|jacobian|,|cellEig|
%
% Kevin Mattheus Moerman
% gibbon.toolbox@gmail.com
%
% 2014/10/10 Updated
%------------------------------------------------------------------------

%% Parse input

switch nargin
    case 1
        U=varargin{1};
        v=[];
        cellOpt=0;
    case 2
        U=varargin{1};
        v=varargin{2};
        cellOpt=0;
    case 3
        U=varargin{1};
        v=varargin{2};
        cellOpt=varargin{3};
end
%%

nDims=ndims(U);
if isvector(U)
    nDims=1;
end

if isempty(v)
    v=ones(1,nDims); %Use default
end

if nDims<=3
    switch nDims
        case 1
            %Compute first order derivative
            [dUdx] = gradient(U,v);

            %Compute second order derivatives
            [dUdxdx] = gradient(dUdx,v);

            H_mat=dUdxdx(:);
        case 2
            %Compute first order derivative
            [dUdx,dUdy] = gradient(U,v(1),v(2));

            %Compute second order derivatives
            [dUdxdx,dUdxdy] = gradient(dUdx,v(1),v(2));
            [dUdydx,dUdydy] = gradient(dUdy,v(1),v(2));

            H_mat=[dUdxdx(:) dUdxdy(:)...
                dUdydx(:) dUdydy(:)];
        case 3
            %Compute first order derivative
            [dUdx,dUdy,dUdz] = gradient(U,v(1),v(2),v(3));

            %Compute second order derivatives
            [dUdxdx,dUdxdy,dUdxdz] = gradient(dUdx,v(1),v(2),v(3));
            [dUdydx,dUdydy,dUdydz] = gradient(dUdy,v(1),v(2),v(3));
            [dUdzdx,dUdzdy,dUdzdz] = gradient(dUdz,v(1),v(2),v(3));

            H_mat=[dUdxdx(:) dUdxdy(:) dUdxdz(:)...
                   dUdydx(:) dUdydy(:) dUdydz(:)...
                   dUdzdx(:) dUdzdy(:) dUdzdz(:)];
    end

    if cellOpt==1
        H_mat=reshape(H_mat',nDims,nDims,size(H_mat,1));

        %Cell array of Hessian matrices
        H=reshape(mat2cell(H_mat,nDims,nDims,ones(size(H_mat,3),1)),size(U));
    else
        H=H_mat;
    end
else
    warning('Function only defined for 1D, 2D or 3D scalar valued arrays');
end

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


% Test script for solving the 2D advection
Globals2D;

% Set polynomial order to use
N = 7;

% Read and initiate circular mesh
filename = 'circA01.neu';
[Nv, VX, VY, K, EToV, BCType] = MeshReaderGambitBC2D(filename);

StartUp2D;
BuildBCMaps2D;

% Push all boundary faces to unit cylinder
[k,f] = find(BCType);
curved = sort(unique(k));
MakeCylinder2D([k,f], 1, 0, 0);

% Set initial conditions
% First 6 modes of eigenmodes with 6 azimuthal periods
alpha = [9.936109524217684,13.589290170541217,17.003819667816014,...
         20.320789213566506,23.586084435581391,26.820151983411403];

% choose radial mode
alpha0 = alpha(2);
theta = atan2(y,x);
rad   = sqrt(x.^2+y.^2);

Ez = besselj(6, alpha0*rad).*cos(6*theta);
Hx = zeros(Np, K); Hy = zeros(Np, K);

% Solve Problem for exactly one period
FinalTime = .5;
[Hx,Hy,Ez,time] = MaxwellCurved2D(Hx,Hy,Ez,FinalTime);

exactEz = besselj(6, alpha0*rad).*cos(6*theta)*cos(alpha0*time(end));
maxabserror = max(max(abs(Ez-exactEz)))


% demonstrate usage of mean functions
%
% See also meanFunctions.m.
%
% Copyright (c) by Carl Edward Rasmussen and Hannes Nickisch, 2014-12-08.
%                                      File automatically generated using noweb.
clear all, close all
n = 5; D = 2; x = randn(n,D);            % create a random data set

% set up simple mean functions
m0 = {'meanZero'};  hyp0 = [];      % no hyperparameters are needed
m1 = {'meanOne'};   hyp1 = [];      % no hyperparameters are needed
mc = {@meanConst};  hypc = 2;  % also function handles are possible
ml = {@meanLinear}; hypl = [2;3];              % m(x) = 2*x1 + 3*x2
mp = {@meanPoly,2}; hypp = [1;1;2;3];  % m(x) = x1+x2+2*x1^2+3*x2^2
mn = {@meanNN,[1,0; 0,1],[0.9,0.5]}; hypn = [];  % nearest neighbor
s = 12; hypd = randn(s,1);           % discrete mean with 12 hypers
md = {'meanDiscrete',s};
hyp.cov = [0;0]; hypg = [];                    % GP predictive mean
xt = randn(2*n,D); yt = sign(xt(:,1)-xt(:,2));      % training data
mg = {@meanGP,hyp,@infEP,@meanZero,@covSEiso,@likErf,xt,yt};
hype = [0;0; log(0.1)];             % regression GP predictive mean
xt = randn(2*n,D); yt = xt(:,1).*xt(:,2);           % training data
me = {@meanGPexact,@meanZero,@covSEiso,xt,yt};

% set up composite mean functions
msc = {'meanScale',{m1}};      hypsc = [3; hyp1];      % scale by 3
msu = {'meanSum',{m0,mc,ml}};  hypsu = [hyp0; hypc; hypl];    % sum
mpr = {@meanProd,{mc,ml}};     hyppr = [hypc; hypl];      % product
mpo = {'meanPow',3,msu};       hyppo = hypsu;         % third power
mask = [false,true];     % mask excluding all but the 2nd component
mma = {'meanMask',mask,ml};    hypma = hypl(mask);
mpf = {@meanPref,ml};          hyppf = 2;  % linear pref with slope

% 0) specify mean function
% mean = md; hyp = hypd; x = randi([1,s],n,1);
% mean = mn; hyp = hypn;
% mean = mg; hyp = hypg;
mean = me; hyp = hype;
% mean = m0;  hyp = hyp0;
% mean = msu; hyp = hypsu;
% mean = mpr; hyp = hyppr;
% mean = mpo; hyp = hyppo;
% mean = mpf; hyp = hyppf;

% 1) query the number of parameters
feval(mean{:})

% 2) evaluate the function on x
feval(mean{:},hyp,x)

% 3) compute the derivatives w.r.t. to hyperparameter i
i = 2; feval(mean{:},hyp,x,i)


function K = exponential_correlation ( s, t )

%*****************************************************************************80
%
%% EXPONENTIAL_CORRELATION evaluates the exponential correlation function.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    23 June 2014
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real S(*), T(*), pairs of argument values.
%
%    Output, real K(*), the correlation function values
%
  K = exp ( - abs ( s - t ) );

  return
end


function test06 ( dim_num, level_max )

%*****************************************************************************80
%
%% SPARSE_GRID_GL_TEST06 creates a sparse Gauss-Legendre grid and writes it to a file.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    26 September 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer DIM_NUM, the spatial dimension.
%
%    Input, integer LEVEL_MAX, the level.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST06:\n' );
  fprintf ( 1, '  SPARSE_GRID_GL makes a sparse Gauss-Legendre grid.\n' );
  fprintf ( 1, '  Write the data to a set of quadrature files.\n' );

  level_min = max ( 0, level_max + 1 - dim_num );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  LEVEL_MIN = %d\n', level_min );
  fprintf ( 1, '  LEVEL_MAX = %d\n', level_max );
  fprintf ( 1, '  Spatial dimension DIM_NUM = %d\n', dim_num );
%
%  Determine the number of points.
%
  point_num = sparse_grid_gl_size ( dim_num, level_max );

  r(1:dim_num,1) = -1.0;
  r(1:dim_num,2) = +1.0;
%
%  Compute the weights and points.
%
  [ w, x ] = sparse_grid_gl ( dim_num, level_max, point_num );
%
%  Write the data out.
%
  r_filename = sprintf ( 'gl_d%d_level%d_r.txt', dim_num, level_max );
  w_filename = sprintf ( 'gl_d%d_level%d_w.txt', dim_num, level_max );
  x_filename = sprintf ( 'gl_d%d_level%d_x.txt', dim_num, level_max );

  r8mat_write ( r_filename, dim_num, 2,         r );
  r8mat_write ( w_filename, 1,       point_num, w );
  r8mat_write ( x_filename, dim_num, point_num, x );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  R data written to "%s".\n', r_filename );
  fprintf ( 1, '  W data written to "%s".\n', w_filename );
  fprintf ( 1, '  X data written to "%s",\n', x_filename );

  return
end


function I = intersectionHull(varargin)
%intersectionHull - computes a bounded convex polyhedron resulting from the
%intersection of other convex polyhedra. The other polyhedra need not individually
%be bounded. Only the final intersection resulting from them must be bounded.
%Any number of polyhedra can be input to the intersection operation. They can
%be expressed using either vertices or linear in/equalities, according to
%the input scheme,
%
%
%   I = intersectionHull('vert', V1, 'lcon', A2,b2, 'lcon', A3,b3,Aeq3,,beq3,...)
%
%The arguments specifying different polyhedra are separated using labels
%'vert' and 'lcon'. The label 'vert' signifies that an input polyhedron will
%be expressed using vertices and is to be followed by any string of input arguments
%accepted by vert2lcon(). The label 'lcon' signifies that an input polyhedron will
%be expressed using linear constraints and is to be followed by any string of
%input arguments accepted by lcon2vert().
%
%The output, I, is a struct containing fields
%
%   I.vert: A matrix whose rows are the vertices of the polyhedron formed from
%           the intersection.
%   I.lcon: The quadruplet of linear constraint data {A,b,Aeq,beq}
%           describing the polyhedral intersection.
%
%EXAMPLE 1: This example computes the intersection of a unit square and an
%oblique 2D line segment, both expressed in terms of their vertices.
%
%     V1=dec2bin(0:2^2-1,2)-'0';   %vertices of unit square
%
%     V2=[1,1;0,-1];               %vertices of 2D line segment
%
%     I=intersectionHull('vert',V1,'vert',V2);  %compute intersection
%
%The intersection is another line segment with vertices
%
%        >> I.vert
%
%         ans =
%
%             0.5000         0
%             1.0000    1.0000
%
%EXAMPLE 2: This example computes the intersection of a unit cube, expressed in
%terms of its vertices, and an infinite oblique 3D line, expressed in terms of linear equalities.
%Note that the line is an unbounded polyhedron. This is okay, since we know in advance
%that the final polyhedron formed from the intersection is bounded.
%
%     V=dec2bin(0:2^3-1,3)-'0';    %vertices of unit cube
%
%     Aeq=[1 -1 0; 0 1 -1]; beq=[0;0]; %oblique line in 3D
%
%     I=intersectionHull('vert',V,'lcon',[],[],Aeq,beq);  %compute intersection
%
%Once again, the intersection is a line segment. Its vertices are
%
%      >> I.vert   %vertices of line segment of intersection
%
%         ans =
%
%             0.0000    0.0000    0.0000
%             1.0000    1.0000    1.0000

%%%%begin parsing

if isnumeric(varargin{1})
   TOL=varargin{1};
   varargin(1)=[];
else
    TOL=[];
end

N=length(varargin);
idxType = [find(cellfun(@ischar,varargin)),N+1];

L=length(idxType)-1;
S(L).type=[];
S(L).args={};
S(L).A=[];
S(L).b=[];
S(L).Aeq=[];
S(L).beq=[];

for i=1:L

    j=idxType(i);
    k=idxType(i+1);
    S(i).type=varargin{j};
    S(i).args=varargin(j+1:k-1);

    if isempty(S(i).args)
     error 'Syntax error - arguments missing'
    end

    lcon=cell(1,4);

      switch S(i).type

          case 'vert'

              [lcon{1:4}] = vert2lcon(S(i).args{:});

          case 'lcon'

               lcon(1:k-j-1) = S(i).args;

          case 'qlcon' %deliberately undocumented - no point in using this

               lcon(1:k-j-1) = S(i).args(2:end);

          otherwise

            error(['Unrecognized representation label of polyhedron ' num2str(i)]);

      end

    [S(i).A, S(i).b, S(i).Aeq, S(i).beq] = deal(lcon{:});

end

%%%%end parsing

   A=vertcat(S.A);
   b=vertcat(S.b);
   Aeq=vertcat(S.Aeq);
   beq=vertcat(S.beq);

   [V,nr,nre]=lcon2vert(A,b,Aeq,beq,TOL);

   I.vert=V;
   I.lcon={A(nr,:),b(nr,:), Aeq(nre,:),beq(nre,:)};


%VL_NNBNORM CNN batch normalisation.
%   Y = VL_NNBNORM(X,G,B) applies batch normalization to the input
%   X. Batch normalization is defined as:
%
%      Y(i,j,k,t) = G(k) * (X(i,j,k,t) - mu(k)) / sigma(k) + B(k)
%
%   where:
%
%      mu(k) = mean_ijt X(i,j,k,t),
%      sigma2(k) = mean_ijt (X(i,j,k,t) - mu(k))^2,
%      sigma(k) = sqrt(sigma2(k) + EPSILON)
%
%   are respectively the per-channel mean, variance, and standard
%   deviation of each feature channel in the data X. The parameters
%   G(k) and B(k) are multiplicative and additive constants use to
%   scale each data channel.
%
%   Means and variances are accumulated across all the data items
%   (images) stored in the 4D tensor X (from which the name batch
%   normalization is derived). The constant EPSILON is used to
%   regularize the computation of sigma(k) and to avoid division by
%   zero.
%
%   [DZDX,DZDG,DZDB] = VL_NNBNORM(X,G,B,DZDY) computes the derviatives
%   of the block projected onto DZDY. DZDX, DZDG, DZDB and DZDY have
%   the same dimensions as X, G, B, and Y respectivey.
%
%   Optionally, [Y,MOMENTS] = VL_NNBNORM(...) and
%   [DZDX,DZDG,DZDB,MOMENTS] = VL_NNBNORM(...,DZDY) return the values
%   of the vectors mu and sigma in the formulas above. Here, MOMENTS
%   is a DEPTH x 2 array [MU, SIGMA].
%
%   VL_NNBNROM(..., 'Option', value) takes the following options:
%
%   `Epsilon`:: 1e-4
%       Specifies the constant EPSILON in the formuals above.
%
%   `Moments`:: unspecified
%       Specifies an array MOMENTS with the values of mu and sigma to
%       use instead of computing them according to the equations
%       above. This is useful to disable batch normalization during
%       testing.
%
%   `CuDNN`:: specified
%       If specified, turns on CuDNN. CuDNN is on by default. This
%       option can be useful to undo the effect of a previous
%       `NoCuDNN` option in the argument list.
%
%   `NoCuDNN`:: not specified
%       If specified, turns off CuDNN.
%
%   See also: VL_NNNORMALIZE().

% Copyright (C) 2015 Sébastien Ehrhardt, Karel Lenc and Andrea Vedaldi.
% All rights reserved.
%
% This file is part of the VLFeat library and is made available under
% the terms of the BSD license (see the COPYING file).


function x = exponential_01_cdf_inv ( cdf )

%*****************************************************************************80
%
%% EXPONENTIAL_01_CDF_INV inverts the Exponential 01 CDF.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    09 September 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real CDF, the value of the CDF.
%    0.0 <= CDF <= 1.0.
%
%    Output, real X, the corresponding argument.
%
  if ( cdf < 0.0 | 1.0 < cdf )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'EXPONENTIAL_01_CDF_INV - Fatal error!\n' );
    fprintf ( 1, '  CDF < 0 or 1 < CDF.\n' );
    error ( 'EXPONENTIAL_01_CDF_INV - Fatal error!' );
  end

  x = - log ( 1.0 - cdf );

  return
end


function bestFits = ellipseDetection(img, params)
% ellipseDetection: Ellipse detection
%
% Overview:
% --------
% Fits an ellipse by examining all possible major axes (all pairs of points) and
% getting the minor axis using Hough transform. The algorithm complexity depends on
% the number of valid non-zero points, therefore it is beneficial to provide as many
% restrictions in the "params" input arguments as possible if there is any prior
% knowledge about the problem.
%
% The code is reasonably fast due to (optional) randomization and full code vectorization.
% However, as the algorithm needs to compute pairwise point distances, it can be quite memory
% intensive. If you get out of memory errors, either downsample the input image or somehow
% decrease the number of non-zero points in it.
% It can deal with big amount of noise but can have severe problem with occlusions (major axis
% end points need to be visible)
%
% Input arguments:
% --------
% img
%   - One-channel input image (greyscale or binary).
% params
%   - Parameters of the algorithm:
%       minMajorAxis: Minimal length of major axis accepted.
%       maxMajorAxis: Maximal length of major axis accepted.
%        rotation, rotationSpan: Specification of restriction on the angle of the major axis in degrees.
%                                If rotationSpan is in (0,90), only angles within [rotation-rotationSpan,
%                               rotation+rotationSpan] are accepted.
%       minAspectRatio: Minimal aspect ratio of an ellipse (in (0,1))
%       randomize: Subsampling of all possible point pairs. Instead of examining all N*N pairs, runs
%                  only on N*randomize pairs. If 0, randomization is turned off.
%       numBest: Top numBest to return
%       uniformWeights: Used to prefer some points over others. If false, accumulator points are weighted
%                       by their grey intensity in the image. If true, the input image is regarded as binary.
%       smoothStddev: In order to provide more stability of the solution, the accumulator is convolved with
%                     a gaussian kernel. This parameter specifies its standard deviation in pixels.
%
% Return value:
% --------
% Returns a matrix of best fits. Each row (there are params.numBest of them) contains six elements:
% [x0 y0 a b alpha score] being the center of the ellipse, its major and minor axis, its angle in degrees and score.
%
% Based on:
% --------
% - "A New Efficient Ellipse Detection Method" (Yonghong Xie Qiang , Qiang Ji / 2002)
% - random subsampling inspired by "Randomized Hough Transform for Ellipse Detection with Result Clustering"
%   (CA Basca, M Talos, R Brad / 2005)
%
% Update log:
% --------
% 1.1: More memory efficient code, better documentation, more parameters, more solutions possible, example code.
% 1.0: Initial version
%
%
% Author: Martin Simonovsky
% e-mail: <mys007@seznam.cz>
% Release: 1.1
% Release date: 25.7.2013
%
%
% --------
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are
% met:
%
%     * Redistributions of source code must retain the above copyright
%       notice, this list of conditions and the following disclaimer.
%     * 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 OWNER 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.

    % default values
    if nargin==1; params=[]; end
    % - parameters to contrain the search
    if ~isfield(params,'minMajorAxis');     params.minMajorAxis = 10; end
    if ~isfield(params,'maxMajorAxis');     params.maxMajorAxis = 200; end
    if ~isfield(params,'rotation');            params.rotation = 0; end
    if ~isfield(params,'rotationSpan');        params.rotationSpan = 0; end
    if ~isfield(params,'minAspectRatio');    params.minAspectRatio = 0.1; end
    if ~isfield(params,'randomize');        params.randomize = 2; end
    % - others
    if ~isfield(params,'numBest');            params.numBest = 3; end
    if ~isfield(params,'uniformWeights');   params.uniformWeights = true; end
    if ~isfield(params,'smoothStddev');        params.smoothStddev = 1; end

    eps = 0.0001;
    bestFits = zeros(params.numBest,6);
    params.rotationSpan = min(params.rotationSpan, 90);
    H = fspecial('gaussian', [params.smoothStddev*6 1], params.smoothStddev);

    [Y,X]=find(img);
    Y = single(Y); X = single(X);
    N = length(Y);

    fprintf('Possible major axes: %d * %d = %d\n', N, N, N*N);

    % compute pairwise distances between points (memory intensive!) and filter
    % TODO: do this block-wise, just appending the filtered results (I,J)
    distsSq = bsxfun(@minus,X,X').^2 + bsxfun(@minus,Y,Y').^2;
    [I,J] = find(distsSq>=params.minMajorAxis^2 & distsSq<=params.maxMajorAxis^2);
    idx = I<J;
    I = uint32(I(idx)); J = uint32(J(idx));

    fprintf('..after distance constraint: %d\n', length(I));

    % compute pairwise angles and filter
    if params.rotationSpan>0
        tangents = (Y(I)-Y(J)) ./ (X(I)-X(J));
        tanLo = tand(params.rotation-params.rotationSpan);
        tanHi = tand(params.rotation+params.rotationSpan);
        if tanLo<tanHi
            idx = tangents > tanLo & tangents < tanHi;
        else
            idx = tangents > tanLo | tangents < tanHi;
        end
        I = I(idx); J = J(idx);
        fprintf('..after angular constraint: %d\n', length(I));
    else
        fprintf('..angular constraint not used\n');
    end

    npairs = length(I);

    % compute random choice and filter
    if params.randomize>0
        perm = randperm(npairs);
        pairSubset = perm(1:min(npairs,N*params.randomize));
        clear perm;
        fprintf('..after randomization: %d\n', length(pairSubset));
    else
        pairSubset = 1:npairs;
    end

    % check out all hypotheses
    for p=pairSubset
        x1=X(I(p)); y1=Y(I(p));
        x2=X(J(p)); y2=Y(J(p));

        %compute center & major axis
        x0=(x1+x2)/2; y0=(y1+y2)/2;
        aSq = distsSq(I(p),J(p))/4;
        thirdPtDistsSq = (X-x0).^2 + (Y-y0).^2;
        K = thirdPtDistsSq <= aSq; % (otherwise the formulae in paper do not work)

        %get minor ax propositions for all other points
        fSq = (X(K)-x2).^2 + (Y(K)-y2).^2;
        cosTau = (aSq + thirdPtDistsSq(K) - fSq) ./ (2*sqrt(aSq*thirdPtDistsSq(K)));
        cosTau = min(1,max(-1,cosTau)); %inexact float arithmetic?!
        sinTauSq = 1 - cosTau.^2;
        b = sqrt( (aSq * thirdPtDistsSq(K) .* sinTauSq) ./ (aSq - thirdPtDistsSq(K) .* cosTau.^2 + eps) );

        %proper bins for b
        idxs = ceil(b+eps);

        if params.uniformWeights
            weights = 1;
        else
            weights = img(sub2ind(size(img),Y(K),X(K)));
        end
        accumulator = accumarray(idxs, weights, [params.maxMajorAxis 1]);

        %a bit of smoothing and finding the most busy bin
        accumulator = conv(accumulator,H,'same');
        accumulator(1:ceil(sqrt(aSq)*params.minAspectRatio)) = 0;
        [score, idx] = max(accumulator);

        %keeping only the params.numBest best hypothesis (no non-maxima suppresion)
        if (bestFits(end,end) < score)
            bestFits(end,:) = [x0 y0 sqrt(aSq) idx atand((y1-y2)/(x1-x2)) score];
            if params.numBest>1
                [~,si]=sort(bestFits(:,end),'descend');
                bestFits = bestFits(si,:);
            end
        end
    end
end


function circular_arc ( xcenter, ycenter, radius, angmin, angmax )

%*****************************************************************************80
%
%% CIRCULAR_ARC draws a circular arc of a given angular size and radius.
%
%  Discussion:
%
%    It is assumed that a plot has already been begun.
%
%  Example:
%
%    r = rand ( 100, 1 );
%    t = pi * rand ( 100, 1 );
%    plot ( r .* cos ( t ), r .* sin ( t ), 'b*' );
%    axis equal
%    axis square
%    circular_arc ( 0.0, 0.0, 1.0, 0, 180 );
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    30 July 2010
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real XCENTER, YCENTER, the X and Y coordinates of
%    the center of the circle on which the arc lies.
%
%    Input, real RADIUS, the radius of the circle on which the arc lies.
%
%    Input, real ANGMIN, ANGMAX, the minimum and maximum
%    angles of the circle.  ANGMIN and ANGMAX are both
%    measured in degrees.  ANGMIN and ANGMAX determine the
%    portion of the circle to be drawn.  If ANGMIN=0.0 and
%    ANGMAX=90.0, for instance, an arc of 90 degrees will be drawn.
%
  color = [ 0.75, 0.75, 0.75 ];

  nval = 65;

  if ( radius == 0.0 )
    return
  end
%
%  Set up the data defining the circular arc, using NVAL equally
%  spaced points along the circumference.
%
  if ( nval == 1 )
    angle(1) = 0.5 * ( angmax + angmin );
  else
    angle(1:nval) = linspace ( angmin, angmax, nval );
  end

  xval(1:nval) = xcenter + radius * cos ( angle * pi / 180 );
  yval(1:nval) = ycenter + radius * sin ( angle * pi / 180 );

  line ( xval, yval, 'Color', color );

  return
end


% ir_denoise_test_sep1
% Examine denoising with ordinary vs separable finite differences
% i.e. |Ch X|_1 + |Cv X|_1 vs |Ch X Cv|_1
% Uses ADMM algorithm to optimize denoising cost function.

if ~isvar('yi'), printm 'generate noisy image'
	xt = ellipse_im(2^7);
	xt = zeros(2^6); xt(20:60,20:48) = 9;
	sig = 2^0; clim = [0 9];

	snr = @(x) -20*log(norm(x(:)-xt(:)) / norm(xt(:)));

	rng(7)
	yi = xt + sig * randn(size(xt));

	im plc 2 4
	im(1, xt, clim, 'True')
	im(2, yi, clim, 'Noisy')
	xlabelf('SNR = %4.1f dB', snr(yi))
end

if ~isvar('Cs'), printm 'C2 and Cs'
	arg.Ch = Cdiffs(size(xt,1), 'type_diff', 'circshift', 'offsets', 1);
	arg.Cv = Cdiffs(size(xt,2), 'type_diff', 'circshift', 'offsets', 1);
	Cs = fatrix2('arg', arg, 'idim', size(xt), 'odim', size(xt), ...
		'forw', @(arg, x) arg.Ch * x * arg.Cv, ... % separable!
		'back', @(arg, y) arg.Ch' * y * arg.Cv');
	C2 = Cdiffs(size(xt), 'type_diff', 'circshift', 'offsets', '2d:hv');

	im(3, 'col', 1, C2 * xt, 'Usual'), cbar
	im(4, Cs * xt, 'Separable'), cbar
	drawnow
end

if ~isvar('x2'), printm 'run admm with usual 2d finite differences'
	[x2s snr2] = ir_denoise_admm1(yi, 'beta', 2^+1, ...
		'stop_diff_tol', 1e-4, 'chat', 0, ...
		'isave', 'all', ...
		'userfun', @(x, iter) snr(x), ...
		'niter', 2^5, 'shrink', [], 'rho', 1);
	x2 = x2s(:,:,end);
end

if ~isvar('x1'), printm 'run admm with separable finite differences'
	[x1s snr1] = ir_denoise_admm1(yi, 'beta', 2^+1, ...
		'stop_diff_tol', 1e-4, 'chat', 0, ...
		'C', 'sep1', ...
		'isave', 'all', ...
		'userfun', @(x, iter) snr(x), ...
		'niter', 2^5, 'shrink', [], 'rho', 1);
	x1 = x1s(:,:,end);
end

if 1 % figures
	im(7, x2, clim, 'Denoised usual')
	xlabelf('SNR = %4.1f dB', snr(x2))
	im(8, x1, clim, 'Denoised separ.')
	xlabelf('SNR = %4.1f dB', snr(x1))

%	im subplot 5
	subplot(223)
	iters = 0:numel(snr1)-1;
	plot(iters, snr2, '-o', iters, snr1, '-x')
	snr_lim = [floor(min([snr1; snr2])) ceil(max([snr1; snr2]))];
	axis([0 numel(iters) snr_lim])
	ytick(snr_lim)
	xlabelf 'ADMM iteration'
	ylabelf 'SNR (dB)'
	legend('usual', 'separable', 'location', 'southeast')
end


function [R, singular_values, determinants] = round_solution(Yopt, problem_data)
%function [R, singular_values, determinants] = round_solution(Yopt, problem_data)
%
% Given an element Yopt in St(d, r)^n, this function rounds Yopt to an
% element of SO(d)^n

% Copyright (C) 2016 by David M. Rosen

r = size(Yopt, 1);

[U, Xi, V] = svd(Yopt, 'econ');
singular_values = diag(Xi)';

Xi_d = Xi(1:problem_data.d, 1:problem_data.d);  %Xi_d is the upper-left dxd submatrix of Xi
V_d = V(:, 1:problem_data.d);  %V_d contains the first d columns of V

R = Xi_d*V_d';

determinants = zeros(1, problem_data.n);

for k = 1:problem_data.n
    determinants(k) = det(R(:, problem_data.d*(k-1) + 1 : problem_data.d*(k-1) + problem_data.d));
end
ng0 = sum(determinants > 0);

reflector = diag([ones(1, problem_data.d - 1), -1]);  % Orthogonal matrix that we can use for reversing the orientations of the orthogonal matrix subblocks of R

if ng0 == 0
    % This solution converged to a reflection of the correct solution
    R = reflector*R;
    determinants = -determinants;
elseif ng0 < problem_data.n
    disp('WARNING: SOLUTION HAS INCONSISTENT ORIENTATIONS!');

    % If more than half of the determinants have negative sign, reverse
    % them
    if ng0 < problem_data.n / 2
        determinants = -determinants;
        R = reflector * R;
    end
end

% Finally, project each element of R to SO(d)
for i = 1:problem_data.n
    R(:, problem_data.d * (i-1) + 1 : problem_data.d *i) = project_to_SOd( R(:, problem_data.d * (i-1) + 1 : problem_data.d *i) );
end

end


% laplac2d() - generate a 2 dimensional gaussian matrice
%
% Usage :
%    >> [ gaussmatrix ] = laplac2d( rows, columns, sigma, ...
%                                       meanR, meanC, cut)
%
% Example :
%   >> laplac2d( 5, 5)
%
% Inputs:
%   rows    - number of rows
%   columns - number of columns
%   sigma   - standart deviation (default: rows/5)
%   meanR   - mean for rows (default: center of the row)
%   meanC   - mean for columns (default: center of the column)
%   cut	    - percentage (0->1) of the maximum value for removing
%             values in the matrix (default: 0)
%
% Note: this function implements a simple laplacian for exploratory
%       research. For a more rigorous validated approach use the freely
%       available Current Source Density Matlab toolbox.
%
% See also: eeg_laplac()
%
% Author: Arnaud Delorme, CNL, Salk Institute, 2001

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

function mat = laplac2d( sizeX, sizeY, sigma, meanX, meanY, cut);

if nargin < 2
	help laplac2d
	return;
end;
if nargin < 3
	sigma = sizeX/5;
end;
if nargin < 4
	meanX = (sizeX+1)/2;
end;
if nargin < 5
	meanY = (sizeY+1)/2;
end;
if nargin < 6
	cut = 0;
end;

X = linspace(1, sizeX, sizeX)'* ones(1,sizeY);
Y = ones(1,sizeX)'   		  * linspace(1, sizeY, sizeY);
%[-sizeX/2:sizeX/2]'*ones(1,sizeX+1);
%Y = ones(1,sizeY+1)'   *[-sizeY/2:sizeY/2];

r2 = (X-meanX).*(X-meanX) + (Y-meanY).*(Y-meanY);
sigma2 = sigma*sigma;

mat = - exp(-0.5*r2/sigma2) .* ((r2 - sigma2)/(sigma2*sigma2));
% zeros crossing at r = -/+ sigma;
% mat = r2;
if cut > 0
	maximun = max(max(mat))*cut;
	I = find(mat < maximun);
	mat(I) = 0;
end;

return;


% Program_3c - The Mandelbrot Set in Color.
% Program supplied by Steve Lord from The MathWorks.
% Copyright Birkhauser 2013.

% Define parameters
Nmax = 50;   scale = 0.005;
xmin = -2.4; xmax  = 1.2;
ymin = -1.5;  ymax  = 1.5;

% Generate X and Y coordinates and Z complex values
[x,y]=meshgrid(xmin:scale:xmax, ymin:scale:ymax);
z = x+1i*y;

% Generate w accumulation matrix and k counting matrix
w = zeros(size(z));
k = zeros(size(z));

% Start off with the first step ...
N = 0;

% While N is less than Nmax and any k's are left as 0
while N<Nmax && ~all(k(:))
    % Square w, add z
    w = w.^2+z;
    % Increment iteration count
    N = N+1;
    % Any k locations for which abs(w)>4 at this iteration and no
    % previous iteration get assigned the value of N
    k(~k & abs(w)>4) = N;
end

% If any k's are equal to 0 (i.e. the corresponding w's never blew up) set
% them to the final iteration number
k(k==0) = Nmax;

% Open a new figure
figure

% Display the matrix as a surface
s=pcolor(x,y,k);

% If you truly want the Mandelbrot curve in B&W, comment the above line and
% uncomment these two
% s = pcolor(x, y, mod(k, 2));
% colormap([0 0 0;1 1 1])

% Turn off the edges of the surface (because the cells are so small, the
% edges would drown out any useful information if we left them black)
set(s,'edgecolor','none')

% Adjust axis limits, ticks, and tick labels
axis([xmin xmax -ymax ymax])
fontsize=15;
set(gca,'XTick',xmin:0.4:xmax,'FontSize',fontsize)
set(gca,'YTick',-ymax:0.5:ymax,'FontSize',fontsize)
xlabel('Re z','FontSize',fontsize)
ylabel('Im z','FontSize',fontsize)

keyboard
figure

% End of Probgram_3c.


function sim = ImageSimilarity (im1, im2)
% This function computes the "similarity score" between two images. You
% should use the value for the similarity factor value when the two images
% are assigned the same character.
%
% Input:
%   im1, im2: Two images from the provided dataset (they should be 16x8
%     matrices of 0s and 1s).
%
% Output:
%   sim: The similarity score of those images.
%
% Copyright (C) Daphne Koller, Stanford University, 2012

a = im1(:);
b = im2(:);

meanSim = 0.283; % Avg sim score computed over held-out data.

cosDist = (a' * b) / (norm(a) * norm(b));

diff = (cosDist - meanSim) ^ 2;

if (cosDist > meanSim)
    sim = 1 + 5*diff;
else
    sim = 1 / (1 + 5*diff);
end

end