function x = fibonacci_lattice_q_nodes ( k )

%*****************************************************************************80
%
%% FIBONACCI_LATTICE_Q_NODES returns Fibonacci lattice nodes in 2D.
%
%  Discussion:
%
%    Because this is a standard lattice rule, it is really only suited
%    for functions which are periodic, of period 1, in both X and Y.
%
%    The number of nodes returned is
%
%      M = fibonacci ( k ).
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    19 November 2008
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Ian Sloan, Stephen Joe,
%    Lattice Methods for Multiple Integration,
%    Oxford, 1994,
%    ISBN: 0198534728,
%    LC: QA311.S56
%
%  Parameters:
%
%    Input, integer K, the index of the Fibonacci number to be used.
%    K must be at least 3.
%
%    Output, real X(2,M), the nodes.
%
  dim_num = 2;

  m = fibonacci ( k );

  z(1) = 1;
  z(2) = fibonacci ( k - 1 );

  for j = 0 : m - 1
    x(1:dim_num,j+1) = mod ( j * z(1:dim_num) / m, 1.0 );
  end

  return
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% KNOCK-OUT BARRIER OPTION PRICE COMPARISON (RUN SCRIPT)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Descritpion: Script to Compare Methods For Barrier Options Under Black Scholes Model
%              This script compares accuracy/CPU of the following methods,
%                   Monte Carlo
%                   PROJ
%
% Author:      Justin Kirkby
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

[folder, name, ext] = fileparts(which( mfilename('fullpath')));
cd(folder);
addpath('../../PROJ/LEVY/RN_CHF')
addpath('../../PROJ/LEVY/Helper_Functions')

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%  Step 1) CHOOSE CONTRACT/GENERAL PARAMETERS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
S_0    = 100;   %Initial price
W      = 100;   %Strike            %NOTE: no error handling in place for extreme values of W (increase grid if strike falls outside)
r      = 0.05;  %Interest rate
q      = 0.02;  %dividend yield
T      = 1;     %Time (in years)
call   = 1;     %For call use 1 (else, its a put)
down   = 1;     %down-out or up-out (down=1 => down-and-out)
H      = 90;    %barrier (Knock-Out)
M      = 52;    %number of discrete monitoring points
rebate = 0;     % rebate paid immediately upon passing the barrier (knocking-out)

sigma = 0.15;  % volatility of diffusion

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
model = 1; params = {}; params.sigmaBSM = sigma;
modelInput = getModelInput(model, T/M, r, q, params);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%  Reference Price (Using PROJ)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
addpath('../../PROJ/LEVY/Barrier_Options')
L1_ref = 20; N_ref = 2^17;
alpha_ref = getTruncationAlpha(T, L1_ref, modelInput, model);
price_ref = PROJ_Barrier(N_ref, alpha_ref, call, down, S_0, W, H, M, r, q, modelInput.rnCHF, T, rebate);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%  PROJ Method
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
N = 2^12;    % grid roughly centered on [c1 - alph, c1 + alph]
L1 = 10;
alpha = getTruncationAlpha(T, L1, modelInput, model);

tic
price_PROJ = PROJ_Barrier(N, alpha, call, down, S_0, W, H, M, r, q, modelInput.rnCHF, T, rebate);
time_PROJ = toc;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%  Monte Carlo Pricer (Exact Sim, Multi-Step)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% NOTE: Variance reduction techniques should be used in practice
addpath('../../Monte_Carlo/')
addpath('../../Monte_Carlo/Barrier')
N_sim = 5*10^5;  % number of paths
mult = 3;   % multiplier for simulation (see below) to reduce bias

tic
M_mult = M*mult;  %time partitioning to reduce bias
Spath = Simulate_Jump_Diffusion_func( N_sim, M_mult + 1, T, S_0, r, q, sigma);

[price_MC, stdErr] = Price_MC_Barrier_Strikes_func(Spath, call, down, H, W, M, mult, rebate, r, T);

price_MC_L = price_MC - 2*stdErr; price_MC_U = price_MC + 2*stdErr;
time_MC = toc;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% COMPARE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fprintf('\n---------------------------------------------\n')
fprintf('Method      |    Price    |    Err   |  CPU \n')
fprintf('---------------------------------------------\n')
fprintf('Reference   | %.8f  |          |       \n', price_ref)
fprintf('---------------------------------------------\n')
fprintf('PROJ        | %.8f  | %.2e | %.4f \n', price_PROJ, abs(price_ref-price_PROJ), time_PROJ)
fprintf('---------------------------------------------\n')
fprintf('MC-Exact    |[%.3f,%.3f]| %.2e | %.4f \n', price_MC_L, price_MC_U, abs(price_ref-price_MC), time_MC)
fprintf('---------------------------------------------\n')


function sample = SampleGaussian(mu, sigma)

% sample from the Gaussian distribution specifed by mean value mu and standard deviation sigma
%
% Copyright (C) Daphne Koller, Stanford Univerity, 2012

 sample = mu + sigma*randn(1,1);


function X = fast_pca(in_X, K)

in_X = in_X - repmat(mean(in_X),size(in_X,1),1);
[U, S, ~] = rsvd(in_X, K);
K = min(size(S,2),K);
X = U(:,1:K)*diag(sqrt(diag(S(1:K,1:K))));
X = X./repmat(sqrt(sum(X.*X,2)),1,K);
end

function [U,S,V] = rsvd(A,K)
%-------------------------------------------------------------------------------------
% random SVD
% Extremely fast computation of the truncated Singular Value Decomposition, using
% randomized algorithms as described in Halko et al. 'finding structure with randomness
%
% usage :
%
%  input:
%  * A : matrix whose SVD we want
%  * K : number of components to keep
%
%  output:
%  * U,S,V : classical output as the builtin svd matlab function
%-------------------------------------------------------------------------------------
% Antoine Liutkus  (c) Inria 2014

[M,N] = size(A);
P = min(2*K,N);
X = randn(N,P);
Y = A*X;
W1 = orth(Y);
B = W1'*A;
[W2,S,V] = svd(B,'econ');
U = W1*W2;
K=min(K,size(U,2));
U = U(:,1:K);
S = S(1:K,1:K);
V=V(:,1:K);
end


function M = euclideancomplexfactory(m, n)
% Returns a manifold struct to optimize over complex m-by-n matrices.
%
% function M = euclideancomplexfactory(m, n)
%
% Returns M, a structure describing the vector space of complex m-by-n
% matrices, as a manifold for Manopt.
%
% The complex plane is here viewed as R^2. The inner product between two
% m-by-n matrices A and B is given by: real(trace(A'*B)). This choice
% guides the proper definition of gradient and Hessian for this geometry.
% This is not the classical Euclidean inner product for complex matrices;
% it is a real inner product.
%
% See also: euclideanfactory

% This file is part of Manopt: www.manopt.org.
% Original author: Nicolas Boumal, April 7, 2015.
% Contributors:
% Change log:

    if ~exist('n', 'var') || isempty(n)
        n = 1;
    end

    M.name = @() sprintf('Vector space C^(%dx%d)', m, n);

    M.dim = @() 2*m*n;

    M.inner = @(x, d1, d2) real(d1(:)'*d2(:));

    M.norm = @(x, d) norm(d, 'fro');

    M.dist = @(x, y) norm(x-y, 'fro');

    M.typicaldist = @() sqrt(m*n);

    M.proj = @(x, d) d;

    M.egrad2rgrad = @(x, g) g;

    M.ehess2rhess = @(x, eg, eh, d) eh;

    M.tangent = M.proj;

    M.exp = @exp;
    function y = exp(x, d, t)
        if nargin == 3
            y = x + t*d;
        else
            y = x + d;
        end
    end

    M.retr = M.exp;

	M.log = @(x, y) y-x;

    M.hash = @(x) ['z' hashmd5([real(x(:)) ; imag(x(:))])];

    M.rand = @() (randn(m, n) + 1i*randn(m, n))/sqrt(2);

    M.randvec = @randvec;
    function u = randvec(x) %#ok<INUSD>
        u = randn(m, n) + 1i*randn(m, n);
        u = u / norm(u, 'fro');
    end

    M.lincomb = @matrixlincomb;

    M.zerovec = @(x) zeros(m, n);

    M.transp = @(x1, x2, d) d;

    M.pairmean = @(x1, x2) .5*(x1+x2);

    mn = m*n;
    M.vec = @(x, u_mat) [real(u_mat(:)) ; imag(u_mat(:))];
    M.mat = @(x, u_vec) reshape(u_vec(1:mn), [m, n]) + 1i*reshape(u_vec((mn+1):end), [m, n]);
    M.vecmatareisometries = @() true;

end


function signal = logCompression(signal, a, normalise)
%LOGCOMPRESSION   Log compress an input signal.
%
% DESCRIPTION:
%       logCompression compresses the input signal using the expression
%       signal = log10(1 + a*signal)./log10(1 + a)
%
% USAGE:
%       signal = logCompression(signal, a)
%       signal = logCompression(signal, a, normalise)
%
% INPUTS:
%       signal      - input signal
%       a           - compression factor
%
% OPTIONAL INPUTS
%       normalise   - Boolean controlling whether the maximum of the input
%                     signal is normalised to unity before compression
%                     (default = false). If set to true, the original
%                     magnitude is restored after compression.
%
% OUTPUTS:
%       signal      - log compressed signal
%
% ABOUT:
%       author      - Bradley Treeby
%       date        - 24th February 2011
%       last update - 24th February 2011
%
% This function is part of the k-Wave Toolbox (http://www.k-wave.org)
% Copyright (C) 2009-2014 Bradley Treeby and Ben Cox

% This file is part of k-Wave. k-Wave is free software: you can
% redistribute it and/or modify it under the terms of the GNU Lesser
% General Public License as published by the Free Software Foundation,
% either version 3 of the License, or (at your option) any later version.
%
% k-Wave 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 Lesser General Public License for
% more details.
%
% You should have received a copy of the GNU Lesser General Public License
% along with k-Wave. If not, see <http://www.gnu.org/licenses/>.

% check for optional normalise input
if nargin == 2
    normalise = false;
end

% compress signal
if normalise
    mx = max(signal(:));
    signal = mx*(log10(1 + a*signal./mx)./log10(1 + a));
else
    signal = log10(1 + a*signal)./log10(1 + a);
end


function varargout = alldist2(varargin)
% VL_ALLDIST2  Pairwise distances
%  D = VL_ALLDIST2(X,Y) returns the pairwise distance matrix D of the
%  columns of S1 and S2, yielding
%
%    D(i,j) = sum (X(:,i) - Y(:,j)).^2
%
%  VL_ALLDIST2(X) returns the pairwise distance matrix fo the columns of
%  S, yielding
%
%    D(i,j) = sum (X(:,i) - X(:,j)).^2
%
%  VL_ALLDIST2(...,'METRIC') changes the computed distance. Supported
%  values for METRIC are
%
%   METRIC  D(i,j)
%   --------------------------------------------------------
%    LINF   max |X  - Y|
%    L2     sum (X  - Y).^2
%    L1     sum |X  - Y|
%    L0     sum (X ~= Y)
%    CHI2   sum (X  - Y).^2 ./ (X + Y)
%    HELL   sum (X^.5 - Y^.5) .^ 2
%
%  (Notice that the standard definition of chi2 is half of what is
%  computed here).
%
%  VL_ALLDIST2(...,'KERNEL') computes the following 'kernels' K:
%
%   KERNEL  K(i,j)
%   ---------------------------------------------------------
%    KL2    sum X .* Y
%    KL1    sum min (X, Y)
%    KCHI2  2 * sum (X .* Y) ./ (X + Y)
%    KHELL  (X .* Y) .^ 0.5
%
%  The constant are chosen so that D(i,j) = K(i,i) + K(j,j) - 2 K(i,j)
%  where D is the metric corresponding to the kenrel (if the arguments
%  are non-negative vectors). Each kernel can be interpreted as the
%  inner product inducing the corresponding metric in an embedding of
%  the real space into an approrpiate reproducing Kenrel Hilbert
%  space.
%
%  VL_ALLDIST2() supports several storage classes. X and Y must have the
%  same storage class. The sotrage class of D is promoted to reduce
%  the chance of overvlow, but this is not checked.
%
%    X & Y class      D class
%   ---------------------------
%    UINT8            UINT32
%     INT8             INT32
%    UINT16           UINT32
%     INT16            INT32
%    UINT32           UINT32
%     INT32            INT32
%    SINGLE           SINGLE
%    DOUBLE           DOUBLE
%
%  Warning: Both chi2 and kchi2 use integer math when presented with
%  integer data types. This can easily result in zeros where you did
%  not expect them.
%
%  See also: VL_HELP().
[varargout{1:nargout}] = vl_alldist2(varargin{:});


function a = daub10 ( n )

%*****************************************************************************80
%
%% DAUB10 returns the DAUB10 matrix.
%
%  Discussion:
%
%    The DAUB10 matrix is the Daubechies wavelet transformation matrix
%    with 10 coefficients.
%
%    Note that in the reference, the coefficient 0.0775714938400459
%    is given incorrectly, with the "8" misrepresented as a "0".
%
%  Properties:
%
%    The family of matrices is nested as a function of N.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 July 2011
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Gilbert Strang, Truong Nguyen,
%    Wavelets and Filter Banks,
%    Wellesley-Cambridge Press, 1997,
%    ISBN: 0-9614088-7-1,
%    LC: TK7872.F5S79 / QA403.3.S87
%
%  Parameters:
%
%    Input, integer N, the order of the matrix.
%    N must be at least 10, and a multiple of 2.
%
%    Output, real A(N,N), the matrix.
%
  c = [ ...
    0.1601023979741929, ...
    0.6038292697971895, ...
    0.7243085284377726, ...
    0.1384281459013203, ...
   -0.2422948870663823, ...
   -0.0322448695846381, ...
    0.0775714938400459, ...
   -0.0062414902127983, ...
   -0.0125807519990820, ...
    0.0033357252854738 ];

  if ( n < 10 || mod ( n, 2 ) ~= 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'DAUB10 - Fatal error!\n' );
    fprintf ( 1, '  N must be at least 10 and a multiple of 2.\n' );
    error ( 'DAUB10 - Fatal error!' );
  end

  a = zeros ( n, n );

  for i = 1 : 2 : n - 1

    a(i,i)                  =    c(1);
    a(i,i+1)                =    c(2);
    a(i,i4_wrap(i+2,1,n))   =    c(3);
    a(i,i4_wrap(i+3,1,n))   =    c(4);
    a(i,i4_wrap(i+4,1,n))   =    c(5);
    a(i,i4_wrap(i+5,1,n))   =    c(6);
    a(i,i4_wrap(i+6,1,n))   =    c(7);
    a(i,i4_wrap(i+7,1,n))   =    c(8);
    a(i,i4_wrap(i+8,1,n))   =    c(9);
    a(i,i4_wrap(i+9,1,n))   =   c(10);

    a(i+1,i)                =   c(10);
    a(i+1,i+1)              =  - c(9);
    a(i+1,i4_wrap(i+2,1,n)) =    c(8);
    a(i+1,i4_wrap(i+3,1,n)) =  - c(7);
    a(i+1,i4_wrap(i+4,1,n)) =    c(6);
    a(i+1,i4_wrap(i+5,1,n)) =  - c(5);
    a(i+1,i4_wrap(i+6,1,n)) =    c(4);
    a(i+1,i4_wrap(i+7,1,n)) =  - c(3);
    a(i+1,i4_wrap(i+8,1,n)) =    c(2);
    a(i+1,i4_wrap(i+9,1,n)) =  - c(1);

  end

  return
end


function order = level_to_order_open ( dim_num, level )

%*****************************************************************************80
%
%% LEVEL_TO_ORDER converts a level to an order for open rules.
%
%  Discussion:
%
%    Sparse grids can naturally be nested.  A natural scheme is to use
%    a series of one-dimensional rules arranged in a series of "levels"
%    whose order roughly doubles with each step.
%
%    The arrangement described here works naturally for the Fejer Type 1,
%    Fejer Type 2, Newton Cotes Open, Newton Cotes Half Open,
%    and Gauss-Patterson rules.  It also can be used, partially, to describe
%    the growth of Gauss-Legendre rules.
%
%    The idea is that we start with LEVEL = 0, ORDER = 1 indicating the single
%    point at the center, and for all values afterwards, we use the relationship
%
%      ORDER = 2**(LEVEL+1) - 1.
%
%    The following table shows how the growth will occur:
%
%    Level    Order
%
%    0          1
%    1          3 =  4 - 1
%    2          7 =  8 - 1
%    3         15 = 16 - 1
%    4         31 = 32 - 1
%    5         63 = 64 - 1
%
%    For the Fejer Type 1, Fejer Type 2, Newton Cotes Open,
%    Newton Cotes Open Half, and Gauss-Patterson rules, the point growth is
%    nested.  If we have ORDER points on a particular LEVEL, the next level
%    includes all these old points, plus ORDER+1 new points, formed in the
%    gaps between successive pairs of old points plus an extra point at each
%    end.
%
%    Level    Order = New + Old
%
%    0          1   =  1  +  0
%    1          3   =  2  +  1
%    2          7   =  4  +  3
%    3         15   =  8  +  7
%    4         31   = 16  + 15
%    5         63   = 32  + 31
%
%    If we use a series of Gauss-Legendre rules, then there is almost no
%    nesting, except that the central point is shared.  If we insist on
%    producing a comparable series of such points, then the "nesting" behavior
%    is as follows:
%
%    Level    Order = New + Old
%
%    0          1   =  1  +  0
%    1          3   =  2  +  1
%    2          7   =  6  +  1
%    3         15   = 14  +  1
%    4         31   = 30  +  1
%    5         63   = 62  +  1
%
%    Moreover, if we consider ALL the points used in such a set of "nested"
%    Gauss-Legendre rules, then we must sum the "NEW" column, and we see that
%    we get roughly twice as many points as for the truly nested rules.
%
%    In this routine, we assume that a vector of levels is given,
%    and the corresponding orders are desired.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 April 2007
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Fabio Nobile, Raul Tempone, Clayton Webster,
%    A Sparse Grid Stochastic Collocation Method for Partial Differential
%    Equations with Random Input Data,
%    SIAM Journal on Numerical Analysis,
%    Volume 46, Number 5, 2008, pages 2309-2345.
%
%  Parameters:
%
%    Input, integer DIM_NUM, the spatial dimension.
%
%    Input, integer LEVEL(DIM_NUM), the nesting level.
%
%    Output, integer ORDER(DIM_NUM,1), the order (number of points) of the rule.
%
  order = zeros ( dim_num, 1 );

  for dim = 1 : dim_num

    if ( level(dim) < 0 )
      order(dim,1) = -1;
    elseif ( level(dim) == 0 )
      order(dim,1) = 1;
    else
      order(dim,1) = 2^( level(dim) + 1 ) - 1;
    end

  end

  return
end


function cx = laguerre_poly ( n, x )

%*****************************************************************************80
%
%% LAGUERRE_POLY evaluates the Laguerre polynomials at X.
%
%  Differential equation:
%
%    X * Y'' + (1-X) * Y' + N * Y = 0
%
%  First terms:
%
%      1
%     -X    +  1
%   (  X^2 -  4 X     +  2 ) / 2
%   ( -X^3 +  9 X^2 -  18 X    +    6 ) / 6
%   (  X^4 - 16 X^3 +  72 X^2 -   96 X +      24 ) / 24
%   ( -X^5 + 25 X^4 - 200 X^3 +  600 X^2 -  600 x    +  120 ) / 120
%   (  X^6 - 36 X^5 + 450 X^4 - 2400 X^3 + 5400 X^2 - 4320 X + 720 ) / 720
%   ( -X^7 + 49 X^6 - 882 X^5 + 7350 X^4 - 29400 X^3
%      + 52920 X^2 - 35280 X + 5040 ) / 5040
%
%  Recursion:
%
%    L(0)(X) = 1,
%    L(1)(X) = 1-X,
%    N * L(N)(X) = (2*N-1-X) * L(N-1)(X) - (N-1) * L(N-2)(X)
%
%  Orthogonality:
%
%    Integral ( 0 <= X < Infinity ) exp ( - X ) * L(N)(X) * L(M)(X) dX
%    = 0 if N /= M
%    = 1 if N == M
%
%  Special values:
%
%    L(N)(0) = 1.
%
%  Relations:
%
%    L(N)(X) = (-1)^N / N! * exp ( x ) * (d/dx)^n ( exp ( - x ) * X^n )
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    26 July 2004
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Milton Abramowitz and Irene Stegun,
%    Handbook of Mathematical Functions,
%    US Department of Commerce, 1964.
%
%  Parameters:
%
%    Input, integer N, the highest order polynomial to compute.
%    Note that polynomials 0 through N will be computed.
%
%    Input, real X, the point at which the polynomials are to be evaluated.
%
%    Output, real CX(1:N+1), the Laguerre polynomials of degree 0 through
%    N evaluated at the point X.
%
  if ( n < 0 )
    cx = [];
    return
  end

  cx(1) = 1.0;

  if ( n == 0 )
    return
  end

  cx(2) = 1.0 - x;

  for i = 2 : n

    cx(i+1) = ( ( ( 2 * i - 1 ) - x ) * cx(i  )   ...
                - (     i - 1 )       * cx(i-1) ) ...
                / (     i );

  end

  return
end


%% EXAMPLE 8: Band-pass filtering.
%
%   Reference:
%     [1] A. Nekkanti, O. T. Schmidt, Frequency–time analysis, low-rank reconstruction and denoising of turbulent flows using SPOD,
%         Journal of Fluid Mechanics 926, A26, 2021
%
% O. T. Schmidt (oschmidt@ucsd.edu)
% Last revision: 5-Sep-2022

clc, clear variables
addpath('utils')
disp('Loading the entire test database might take a second...')
load(fullfile('jet_data','jetLES.mat'),'p','p_mean','x','r','dt');

%   trapezoidal quadrature weights for cylindrical coordinates
intWeights      = trapzWeightsPolar(r(:,1),x(1,:));

%% SPOD
%   We will use standard parameters: a Hann window of length 256 and 50%
%   overlap.
nDFT            = 256;
nOvlp           = nDFT/2;
[L,P,f,~,A]     = spod(p,nDFT,intWeights,nOvlp,dt);

figure
loglog(f,L)
title('SPOD of full data')
xlabel('frequency'), ylabel('SPOD mode energy')
ylims           = ylim;

%% Filtering
%   An band-pass filter that focusses on the 'low-rank' portion of the
%   spectrum is implemented by setting to zero the SPOD expansion
%   coefficients in the range f<=0.08 and f>=1.0.
f_lowpass       = 1;
f_highpass      = 0.08;
A(f>=f_lowpass|f<=f_highpass,:,:) ...
                = 0;

%   The inverse SPOD using the modified SPOD expansion coefficients yields
%   the band-pass filtered data.
nt              = size(p,1);
p_rec           = invspod(P,A,nDFT,nOvlp);

%% Animate
%   Animate the original, filtered, and removed data.
figure
for t_i=1:1:30
    subplot(3,1,1)
    pcolor(x,r,squeeze(p(t_i,:,:))-p_mean); shading interp, axis equal tight
    title('Original data')
    if t_i==1; pmax = max(abs(caxis)); end, caxis(0.5*pmax*[-1 1]), colorbar
    subplot(3,1,2)
    pcolor(x,r,squeeze(p_rec(t_i,:,:))); shading interp, axis equal tight
    title('Reconstructed data')
    caxis(0.5*pmax*[-1 1]), colorbar
    subplot(3,1,3)
    pcolor(x,r,(squeeze(p(t_i,:,:))-p_mean)-squeeze(p_rec(t_i,:,:))); shading interp, axis equal tight
    title('Filtered/removed component')
    caxis(0.5*pmax*[-1 1]), colorbar
    drawnow
end

%% SPOD of filtered data
%   The effect of the band-pass filter should to a large degree remove
%   high-frequency components above the filter cut-on frequency.
[L,P,f,~,A]     = spod(p_rec,nDFT,intWeights,nOvlp,dt);

figure
loglog([f_lowpass f_lowpass],ylims,'k--'); hold on
loglog([f_highpass f_highpass],ylims,'k:');
loglog(f,L)
title('SPOD of filtered data')
xlabel('frequency'), ylabel('SPOD mode energy')
ylim(ylims);
legend('f_{low-pass}','f_{high-pass}')


%% Coarsening for Algebraic Multigrid
%
% Given a SPD matrix A, we describe an algebraic coarsening of a graph of A
% based on the concept of strong connectness. The measure of strong
% connectness is slightly different with the standard definition. The
% parameter theta is used to define strong connectness and the default
% value is 0.025.

%% Usage of the function
clear all
help coarsenAMGc

%% Generate a test matrix
[node,elem] = squaremesh([0,1,0,1],1/8);
% [node,elem] = uniformrefine(node,elem);
% load lakemesh
[A,M] = assemblematrix(node,elem);
% A = M;  % test mass matrix. No coarsening is needed.

%% Parameters
theta = 0.025;
N = size(A,1);
N0 = min(sqrt(N),50);       % number of the coarest nodes

%% Generate strong connectness matrix
D = spdiags(1./sqrt(diag(A)),0,N,N);
Am = D*A*D;  % normalize diagonal of A
[im,jm,sm] = find(Am);
idx = (-sm > theta);   % delete weakly connect off-diagonal and diagonal
As = sparse(im(idx),jm(idx),sm(idx),N,N); % matrix for strong connectness
% The diagonal of Am is 1. The negative off-diagonal measures the
% diffusivity. The positive off-diagonal is filtered.

%% Compute degree of vertex
deg = sum(spones(As)); % number of strongly connected neighbors
deg = full(deg');
% deg = deg + rand(N,1); % break the equal degree case but deteriorate performance
if sum(deg>0) < 0.1*sqrt(N)   % too few connected nodes e.g. A is mass matrix
    isC(round(rand(N0,1)*N)) = true; % randomly chose N0 nodes
    return                    % smoother is a good preconditioner
end
idx = (deg>0);
deg(idx) = deg(idx) + 0.1*rand(sum(idx),1); % break the equal degree case

%% Find an approximate maximal independent set and put to C set
isC = false(N,1);       % C: coarse node
isF = false(N,1);       % F: fine node
isU = true(N,1);        % S: selected set
isF(deg == 0) = true;   % isolated nodes are added into F set
% debug
close all;
%%
% * magneta dots: indepedent nodes in U
% * yellow dots: F (fine) nodes
% * red dots: C (coarse) nodes
% * black dots: U (undecided) nodes
set(gcf,'Units','normal');
set(gcf,'Position',[0.5,0.5,0.5,0.5]);
showmesh(node,elem);
findnode(node,isU,'noindex','Color','k','MarkerSize',32)
m = 1;
while sum(isC) < N/2 && sum(isU) >N0
    % Mark all undecided nodes
    isS = false(N,1);  % S: selected set, changing in the coarsening
    isS(deg>0) = true;
    S = find(isS);
    % debug
    fprintf('Coarsening ... \n');

    % Find marked nodes with local maximum degree
    [i,j] = find(triu(As(S,S),1));    % i,j and i<j: edges of subgraph S
    idx = deg(S(i)) >= deg(S(j));     % compare degree of vertices
    isS(S(j(idx))) = false;  % remove vertices with smaller degree
    isS(S(i(~idx))) = false;
    isC(isS) = true;
    findnode(node,isS,'noindex','Color','m');
    fprintf('Number of chosen points: %6.0u\n',sum(isS));
    snapnow

    % Remove coarse nodes and neighboring nodes from undecided set
    [i,j] = find(As(:,isC)); %#ok<*NASGU>
    isF(i) = true;        % neighbor of C nodes are F nodes
    isU = ~(isF | isC);   % U: undecided set
    deg(~isU) = 0;        % remove current C and F from the graph
    % -- No improvement by adding weight to nodes connected to F nodes --
%     degFin = sum(spones(As(isF,isU)));
%     degFin = full(degFin'); % degrer of strong connected with F points
%     deg(isU) = deg(isU) + degFin; % add weight to nodes connected to F

    if sum(isU) <= N0   % add small undecided nodes into C nodes
        isC(isU) = true;
        isU = [];       % to exit the while loop;
    end
    % debug
    showmesh(node,elem);
    findnode(node,isU,'noindex','Color','k','MarkerSize',32)
    findnode(node,isF,'noindex','Color','y','MarkerSize',32)
    findnode(node,isC,'noindex','Color','r','MarkerSize',36);
    snapnow
    m = m + 1;
end
fprintf('Apply %2.0u times and Number of Coarse Nodes: %6.0u\n',m,sum(isC));

%%
% Note that the red nodes are connected in the grid but not connected in
% the graph of the 5-point stencil.


function spquad_test02 ( )

%*****************************************************************************80
%
%% SPQUAD_TEST02 reports the size of various sparse grids.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    06 January 2012
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'SPQUAD_TEST02:\n' );
  fprintf ( 1, '  Print out the order (number of points) used\n' );
  fprintf ( 1, '  for sparse grids of various levels and spatial dimensions.\n' );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Dimension / Level size table for Sparse Grid Rule\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, ' Dim:  ' )
  for d = 1 : 10
    fprintf ( 1, '  %6d', d );
  end
  fprintf ( 1, '\n' );
  fprintf ( 1, 'Level:\n' );
  for k = 0 : 5
    fprintf ( 1, '  %2d:  ', k );
    for d = 1 : 10
      [ x, w ] = spquad ( d, k );
      n = length ( w );
      fprintf ( 1, '  %6d', n );
    end
    fprintf ( 1, '\n' );
  end

  return
end


function [ err ] = baselines( Xtrain, Ytrain, Xtest, Ytest, lambda, opts)
% Inputs
% Xtrain: input training data
% Ytrain: output training data
% Xtest: input test data
% Ytest: output test data
% lambda: regularization parameter (for global and local models)
% opts:
%   opts.avg: whether to compute avg or total error
%   opts.obj: 'R' for regression, 'C' for classification
%   opts.type:
%       consant - for each task, the model is the average (R) or mode (C) of the labels
%       global - concatenate data from all tasks, fit one global model
%       local - fit m separate models

% Output
% Average or total RMSE (R) or classification error (C) across tasks

%% set variables
m = length(Xtrain); % # of tasks
d = size(Xtrain{1}, 2); % # of features

%% compute baselines
switch opts.type
    case 'constant'
        % predict the mean output (R) or mode class (C) from training
        if(opts.obj == 'R') % regression
            if(opts.avg)
                errs = zeros(m, 1);
                for t=1:m
                    pred = mean(Ytrain{t});
                    errs(t) = sqrt(mean((Ytest{t} - pred).^2));
                end
                err = mean(errs);
            else
                Y_hat = cell(m,1);
                for t=1:m
                    Y_hat{t} = repmat(mean(Ytrain{t}), length(Ytest{t}), 1);
                end
                Y = cell2mat(Ytest(:));
                Y_hat = cell2mat(Y_hat);
                err = sqrt(mean((Y - Y_hat).^2));
            end
        else % classification
            if(opts.avg)
                errs = zeros(m, 1);
                for t=1:m
                    pred = mode(Ytrain{t});
                    errs(t) = mean(pred ~= Ytest{t});
                end
                err = mean(errs);
            else
                pred = mode(opts.Ytrainactual);
                err = sum(pred ~= opts.Yactual) / length(opts.Yactual);
            end
        end

    case 'global'
        % compute one global model for the data
        allX = cat(1, Xtrain{:});
        allY = cat(1, Ytrain{:});
        allXtest = cat(1, Xtest{:});
        allYtest = cat(1, Ytest{:});
        if(opts.obj == 'R') % regression
            w = inv(allX' * allX + lambda * eye(d)) * allX' * allY;
            err = sqrt(mean((allYtest - allXtest * w).^2));
        else % classification
            w = simple_svm(allX, allY, lambda, opts);
            if(opts.avg)
                errs = zeros(m, 1);
                for t=1:m
                    predvals = sign(Xtest{t} * w);
                    errs(t) = mean(predvals ~= Ytest{t});
                end
                err = mean(errs);
            else
                predvals = sign(allXtest * w);
                err = mean(allYtest ~= predvals);
            end
        end

    case 'local'
        % compute m completely separate local models
        if(opts.obj == 'R') % regression
            if(opts.avg)
                errs = zeros(m,1);
                for t=1:m
                    wt = inv(Xtrain{t}' * Xtrain{t} + lambda * eye(d)) * Xtrain{t}' * Ytrain{t};
                    errs(t) = sqrt(mean((Ytest{t} - Xtest{t} * wt).^2));
                end
                % compute average rmse
                err = mean(errs);
            else
                Y_hat = cell(m,1);
                for t=1:m
                    wt = inv(Xtrain{t}' * Xtrain{t} + lambda * eye(d)) * Xtrain{t}' * Ytrain{t};
                    Y_hat{t} = Xtest{t} * wt;
                end
                % compute total rmse
                Y = cell2mat(Ytest(:));
                Y_hat = cell2mat(Y_hat);
                size(Y_hat)
                size(Y)
                err = sqrt(mean((Y - Y_hat).^2));
            end
        else % classification
            Y_hat = cell(m,1);
            for t=1:m
                wt = simple_svm(Xtrain{t}, Ytrain{t}, lambda, opts);
                Y_hat{t} = sign(Xtest{t} * wt);
            end
            if(opts.avg)
                errs = zeros(m,1);
                for t=1:m
                    errs(t) = mean(Ytest{t} ~= Y_hat{t});
                end
                err = mean(errs);
            else
                Y = cell2mat(Ytest);
                Y_hat = cell2mat(Y_hat);
                err = mean(Y ~= Y_hat);
            end
        end
end

end


% Equalizer design example
% "Filter design" lecture notes (EE364) by S. Boyd
% (figures are generated)
%
% Designs a frequency-domain and time-domain FIR equalizer for
% a single-input single-output (SISO) channel.
%
% Frequency-domain equalization uses a Chebychev criteria and
% is specified in terms of frequency response functions.
% It is a convex problem (which can be formulated as an SOCP):
%
%   minimize   max |G(w)H(w) - G_des(w)|     for w in [0,pi]
%
% where H is the frequency response function and our variable
% is the filter impulse response h. Function G is the unequalized
% frequency response and G_des is the desired freq response.
%
% Time-domain equalization immediately designs the impulse
% response function by specifying the problem in time (it's an LP):
%
%   minimize   max_{t neq D} |g_tilde(t)|
%       s.t.   g_tilde(D) = 1
%
% where g_tilde is the impulse response of equalized system,
% and D is the delay of the system.
%
% Written for CVX by Almir Mutapcic 02/02/06

%********************************************************************
% problem specs
%********************************************************************
% sample channel with impulse response g
g =.5*[ 0.6526;  0.2157; -0.2639;  1.8024; -0.6430; ...
        0.1096; -0.7190;  0.4206; -0.0193;  0.6603;];

% problem parameters
n  = 30;              % filter order
D  = 10;              % overall delay

%********************************************************************
% frequency domain equalization
%********************************************************************
% number of freq samples (rule-of-thumb)
m  = 15*(length(g) + n);

w = linspace(0,pi,m)';
G = exp( -j*kron(w,[0:length(g)-1]) )*g;
A = exp( -j*kron(w,[0:n-1]) );

% desired frequency response is a pure delay (equalized channel)
Gdes = exp(-j*D*w);

% formulate and solve the Chebyshev design problem
cvx_begin
  variable hf(n,1)
  minimize( max( abs( G.*(A*hf) - Gdes ) ) )
cvx_end

% check if problem was successfully solved
disp(['Frequency equalization problem is ' cvx_status])
if ~strfind(cvx_status,'Solved')
  return
end

%********************************************************************
% time-domain equalization
%********************************************************************
% define the convolution matrix
Tconv = toeplitz([g; zeros(n-1,1)],[g(1) zeros(1,n-1)]);

% create array of all times without t=D
times_not_D = [1:D D+2:size(Tconv,1)];

% formulate and solve the time equalization problem
cvx_begin
  variable t
  variable ht(n,1)

  minimize( max( abs( Tconv(times_not_D,:)*ht ) ) )
  subject to
    Tconv(D+1,:)*ht == 1;
cvx_end

% check if problem was successfully solved
if ~strfind(cvx_status,'Solved')
  disp(['Frequency equalization problem is ' cvx_status])
  return
end

%********************************************************************
% equalizer plots
%********************************************************************
% plot g
figure(1)
plot([0:length(g)-1],g,'o',[0:length(g)-1],g,'b:')
xlabel('t')
ylabel('g(t)')

figure(2)
H = exp(-j*kron(w,[0:length(g)-1]))*g;
% magnitude
subplot(2,1,1);
plot(w,20*log10(abs(H)))
axis([0,pi,-20,20])
xlabel('w')
ylabel('mag G(w) in dB')
% phase
subplot(2,1,2)
plot(w,angle(H))
axis([0,pi,-pi,pi])
xlabel('w')
ylabel('phase G(w)')

% freq equalizer
figure(3)
plot([0:n-1],hf,'o',[0:n-1],hf,'b:')
xlabel('t')
ylabel('h(t)')

% plot g_tilde
figure(4)
gt=conv(g,hf);
plot([1:length(gt)]-1,gt,'o',[1:length(gt)]-1,gt,'b:')
xlabel('t')
ylabel('g tilde(t)')
axis([0,length(gt)-1,-.2 1.2])

figure(5)
H = exp(-j*kron(w,[0:length(gt)-1]))*gt;
% amplitude
subplot(2,1,1)
plot(w,20*log10(abs(H)))
axis([0,pi,-20,20])
xlabel('w')
ylabel('mag G tilde(w) in dB')
% phase
subplot(2,1,2)
plot(w,angle(H))
axis([0,pi,-pi,pi])
xlabel('w')
ylabel('phase G tilde(w)')

% time equalizer
figure(6)
plot([0:n-1],ht,'o',[0:n-1],ht,'b:')
xlabel('t')
ylabel('h(t)')

% plot g_tilde
figure(7)
gt=conv(g,ht);
plot([1:length(gt)]-1,gt,'o',[1:length(gt)]-1,gt,'b:')
xlabel('t')
ylabel('g tilde(t)')

figure(8)
H = exp(-j*kron(w,[0:length(gt)-1]))*gt;
% magnitude
subplot(2,1,1)
plot(w,20*log10(abs(H)))
axis([0,pi,-20,20])
xlabel('w')
ylabel('mag G tilde(w) in dB')
% phase
subplot(2,1,2)
plot(w,angle(H))
axis([0,pi,-pi,pi])
xlabel('w')
ylabel('phase G tilde(w)')


function [ n_data, x, fx ] = gud_values ( n_data )

%*****************************************************************************80
%
%% GUD_VALUES returns some values of the Gudermannian function.
%
%  Discussion:
%
%    The Gudermannian function relates the hyperbolic and trigonomentric
%    functions.  For any argument X, there is a corresponding value
%    GD so that
%
%      SINH(X) = TAN(GD).
%
%    This value GD is called the Gudermannian of X and symbolized
%    GD(X).  The inverse Gudermannian function is given as input a value
%    GD and computes the corresponding value X.
%
%    GD(X) = 2 * arctan ( exp ( X ) ) - PI / 2
%
%    In Mathematica, the function can be evaluated by:
%
%      2 * Atan[Exp[x]] - Pi/2
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    16 September 2004
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Stephen Wolfram,
%    The Mathematica Book,
%    Fourth Edition,
%    Wolfram Media / Cambridge University Press, 1999.
%
%    Daniel Zwillinger, editor,
%    CRC Standard Mathematical Tables and Formulae,
%    30th Edition,
%    CRC Press, 1996.
%
%  Parameters:
%
%    Input/output, integer N_DATA.  The user sets N_DATA to 0 before the
%    first call.  On each call, the routine increments N_DATA by 1, and
%    returns the corresponding data; when there is no more data, the
%    output value of N_DATA will be 0 again.
%
%    Output, real X, the argument of the function.
%
%    Output, real FX, the value of the function.
%
  n_max = 13;

  fx_vec = [ ...
     -0.1301760336046015E+01, ...
     -0.8657694832396586E+00, ...
      0.0000000000000000E+00, ...
      0.9983374879348662E-01, ...
      0.1986798470079397E+00, ...
      0.4803810791337294E+00, ...
      0.8657694832396586E+00, ...
      0.1131728345250509E+01, ...
      0.1301760336046015E+01, ...
      0.1406993568936154E+01, ...
      0.1471304341117193E+01, ...
      0.1510419907545700E+01, ...
      0.1534169144334733E+01 ];

  x_vec = [ ...
     -2.0E+00, ...
     -1.0E+00, ...
      0.0E+00, ...
      0.1E+00, ...
      0.2E+00, ...
      0.5E+00, ...
      1.0E+00, ...
      1.5E+00, ...
      2.0E+00, ...
      2.5E+00, ...
      3.0E+00, ...
      3.5E+00, ...
      4.0E+00 ];

  if ( n_data < 0 )
    n_data = 0;
  end

  n_data = n_data + 1;

  if ( n_max < n_data )
    n_data = 0;
    x = 0.0;
    fx = 0.0;
  else
    x = x_vec(n_data);
    fx = fx_vec(n_data);
  end

  return
end


function x = simplex_grid_index_to_point ( m, n, ng, g, v )

%*****************************************************************************80
%
%% SIMPLEX_GRID_INDEX_TO_POINT returns  points corresponding to simplex indices.
%
%  Discussion:
%
%    The M-dimensional simplex is defined by M+1 vertices.
%
%    Given a regular grid that uses N subintervals along the edge between
%    each pair of vertices, a simplex grid index G is a set of M+1 values
%    each between 0 and N, and summing to N.
%
%    This function determines the coordinates X of the point corresponding
%    to the index G.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    31 July 2014
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer M, the spatial dimension.
%
%    Input, integer N, the number of subintervals.
%
%    Input, integer NG, the number of grid indices to be converted.
%
%    Input, integer G(M+1,NG), the grid indices of 1 or more points.
%
%    Input, real V(M,M+1), the coordinates of the vertices of the simplex.
%
%    Output, real X(M,NG), the coordinates of one or more points.
%
  x = v(1:m,1:m+1) * g(1:m+1,1:ng) / n;

  return
end


function z = round2(x,y)
%ROUND2 rounds number to nearest multiple of arbitrary precision.
%   Z = ROUND2(X,Y) rounds X to nearest multiple of Y.
%
%Example 1: round PI to 2 decimal places
%   >> round2(pi,0.01)
%   ans =
%         3.14
%
%Example 2: round PI to 4 decimal places
%   >> round2(pi,1e-4)
%   ans =
%         3.1416
%
%Example 3: round PI to 8-bit fraction
%   >> round2(pi,2^-8)
%   ans =
%         3.1406
%
%Examples 4-6: round PI to other multiples
%   >> round2(pi,0.05)
%   ans =
%         3.15
%   >> round2(pi,2)
%   ans =
%         4
%   >> round2(pi,5)
%   ans =
%         5
%
% See also ROUND.

%% defensive programming
error(nargchk(2,2,nargin))
error(nargoutchk(0,1,nargout))
if numel(y)>1
  error('Y must be scalar')
end

%%
z = round(x/y)*y;


function featureVector = gaborFeatures(img,gaborArray,d1,d2)

% GABORFEATURES extracts the Gabor features of an input image.
% It creates a column vector, consisting of the Gabor features of the input
% image. The feature vectors are normalized to zero mean and unit variance.
%
%
% Inputs:
%       img         :	Matrix of the input image
%       gaborArray	:	Gabor filters bank created by the function gaborFilterBank
%       d1          :	The factor of downsampling along rows.
%       d2          :	The factor of downsampling along columns.
%
% Output:
%       featureVector	:   A column vector with length (m*n*u*v)/(d1*d2).
%                           This vector is the Gabor feature vector of an
%                           m by n image. u is the number of scales and
%                           v is the number of orientations in 'gaborArray'.
%
%
% Sample use:
%
% img = imread('cameraman.tif');
% gaborArray = gaborFilterBank(5,8,39,39);  % Generates the Gabor filter bank
% featureVector = gaborFeatures(img,gaborArray,4,4);   % Extracts Gabor feature vector, 'featureVector', from the image, 'img'.
%
%
%
%   Details can be found in:
%
%   M. Haghighat, S. Zonouz, M. Abdel-Mottaleb, "CloudID: Trustworthy
%   cloud-based and cross-enterprise biometric identification,"
%   Expert Systems with Applications, vol. 42, no. 21, pp. 7905-7916, 2015.
%
%
%
% (C)	Mohammad Haghighat, University of Miami
%       haghighat@ieee.org
%       PLEASE CITE THE ABOVE PAPER IF YOU USE THIS CODE.

if (nargin ~= 4)        % Check correct number of arguments
    error('Please use the correct number of input arguments!')
end

if size(img,3) == 3     % Check if the input image is grayscale
    warning('The input RGB image is converted to grayscale!')
    img = rgb2gray(img);
end

img = double(img);

%% Filter the image using the Gabor filter bank

% Filter input image by each Gabor filter
[u,v] = size(gaborArray);
gaborResult = cell(u,v);
for i = 1:u
    for j = 1:v
        gaborResult{i,j} = imfilter(img, gaborArray{i,j});
    end
end

%% Create feature vector

% Extract feature vector from input image
featureVector = [];
for i = 1:u
    for j = 1:v

        gaborAbs = abs(gaborResult{i,j});
        gaborAbs = downsample(gaborAbs,d1);
        gaborAbs = downsample(gaborAbs.',d2);
        gaborAbs = gaborAbs(:);

        % Normalized to zero mean and unit variance. (if not applicable, please comment this line)
        gaborAbs = (gaborAbs-mean(gaborAbs))/std(gaborAbs,1);

        featureVector =  [featureVector; gaborAbs];

    end
end

%% Show filtered images (Please comment this section if not needed!)

% % Show real parts of Gabor-filtered images
% figure('NumberTitle','Off','Name','Real parts of Gabor filters');
% for i = 1:u
%     for j = 1:v
%         subplot(u,v,(i-1)*v+j)
%         imshow(real(gaborResult{i,j}),[]);
%     end
% end
%
% % Show magnitudes of Gabor-filtered images
% figure('NumberTitle','Off','Name','Magnitudes of Gabor filters');
% for i = 1:u
%     for j = 1:v
%         subplot(u,v,(i-1)*v+j)
%         imshow(abs(gaborResult{i,j}),[]);
%     end
% end


function area = disk01_area ( )

%*****************************************************************************80
%
%% DISK01_AREA returns the area of the unit disk.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    03 January 2014
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, real AREA, the area of the unit disk.
%
  r = 1.0;
  area = pi * r * r;

  return
end


function mc1 = moc1 ( a, b, n, f )

%*****************************************************************************80
%
%% MOC1 estimates a function related to the modulus of continuity.
%
%  Discussion;
%
%    The modulus of continuity function MC(T) for a function F(X) over an
%    interval [A,B] is defined as
%
%      MC(T) = max | F(X+DX) - F(X) | for 0 <= DX <= T, and X and X+DX in [A,B].
%
%    If we define the simpler function
%
%      MC1(DX) = max | F(X+DX) - F(X) | for 0 <= DX, and X and X+DX in [A,B],
%
%    then we can evaluate MC(T) as
%
%      MC(T) = max ( MC1(DX) ), for DX <= T.
%
%    This function estimates the MC1 function based on a discrete
%    set of data at N equally spaced points in the interval [A,B].
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 October 2010
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real A, B, the left and right endpoints of the interval.
%
%    Input, integer N, the number of equally spaced sample points.
%
%    Input, function F(x), a handle to the function.
%
%    Output, real MC1(N), the maximum difference |F(X+DX)-F(X)| estimated at
%    DX = 0 exactly, H exactly, 2*H exactly, ..., (N-1)*H exactly.
%
  if ( nargin < 1 )
    a = 0.0;
  end

  if ( nargin < 2 )
    b = a + 1.0;
  end

  if ( nargin < 3 )
    n = 501;
  end
%
%  Set the evaluation points, and evaluate the function.
%
  x = linspace ( a, b, n );
  fx = f ( x );
%
%  Compute the maximum difference with a separation of 0*H, 1*H, 2*H,
%  ..., (N-1)*H.
%
  mc1 = zeros ( n, 1 );
  for i = 0 : n - 1
    mc1(i+1) = max ( abs ( fx(1+i:n) - fx(1:n-i) ) );
  end

  return
end


function solution = optimalConservationVectors(S, lambda, delta)
% DC programming for solving the cardinality optimization problem
%
% .. math::
%
%    min  ~& \lambda ||x||_0 - \delta ||y||_0 \\
%    s.t. ~& x + S^T y = 0 \\
%         ~& 0 \leq y \leq 1e4
%
% USAGE:
%
%    solution = optimalConservationVectors(S, lambda, delta)
%
% INPUT:
%    S:           `m` x `n` stoichiometric matrix
%
% OPTIONAL INPUTS:
%    lambda:      default = 1
%    delta:       default = 1
%
% OUTPUT:
%    solution:    result of the solved cardinality optimization problem

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

[mlt,nlt]=size(S');
prob.p=mlt;
prob.q=nlt;
prob.r=0;
prob.c=zeros(nlt+mlt,1);
prob.A=[speye(mlt,mlt),S'];
prob.b=zeros(mlt,1);
prob.lb=[-inf*ones(mlt,1);zeros(nlt,1)];
prob.ub=[inf*ones(nlt,1);1e4*ones(mlt,1)];
prob.csense(1:mlt,1)='E';
params.lamda=lambda;
params.delta=delta;
solution = optimizeCardinality(prob,params);
% DC programming for solving the cardinality optimization problem
% The l0 norm is approximated by capped-l1 function.
% min       c'(x,y,z) + lambda*||x||_0 - delta*||y||_0
% s.t.      A*(x,y,z) <= b
%           l <= (x,y,z) <=u
%           x in R^p, y in R^q, z in R^r
%
% solution = optimizeCardinality(problem,params)
%
%  problem                  Structure containing the following fields describing the problem
%       p                   size of vector x
%       q                   size of vector y
%       r                   size of vector z
%       c                   (p+q+r) x 1 linear objective function vector
%       lambda              trade-off parameter of ||x||_0
%       delta               trade-off parameter of ||y||_0
%       A                   s x (p+q+r) LHS matrix
%       b                   s x 1 RHS vector
%       csense              s x 1 Constraint senses, a string containting the constraint sense for
%                           each row in A ('E', equality, 'G' greater than, 'L' less than).
%       lb                  (p+q+r) x 1 Lower bound vector
%       ub                  (p+q+r) x 1 Upper bound vector
%
% OPTIONAL INPUTS
% params                    parameters structure
%       nbMaxIteration      stopping criteria - number maximal of iteration (Defaut value = 1000)
%       epsilon             stopping criteria - (Defaut value = 10e-6)
%       theta               parameter of the approximation (Defaut value = 2)
%
% OUTPUT
% solution                  Structure containing the following fields
%       x                   p x 1 solution vector
%       y                   q x 1 solution vector
%       z                   r x 1 solution vector
%       stat                status
%                           1 =  Solution found
%                           2 =  Unbounded
%                           0 =  Infeasible
%                           -1=  Invalid input


function y = geo_lpdf(x,p)
%GEO_LPDF     Geometric log probability density function (lpdf).
%   Y = GEO_LPDF(X,P) returns the log of geometric pdf with probability, P,
%   at the values in X.
%
%   The size of Y is the common size of X and P. A scalar input
%   functions as a constant matrix of the same size as the other input.
%
% Copyright (c) 1999-2000 Aki Vehtari

% This software is distributed under the GNU General Public
% License (version 3 or later); please refer to the file
% License.txt, included with the software, for details.

y = log(p) + log(1-p) * x;


function [pp, mse] = fitSpline(tData, xData, tKnot)
% pp = fitSpline(tData, xData, tGrid)
%
% Fits a piece-wise cubic spline to {tData, xData} using the
% knot-points in tKnot.
%
% INPUTS:
%     tData = [1,nData] = time stamps for data (uniform spacing, monotonic!)
%     xData = [nFunc,nData] = function value at each time
%     tKnot = [1,nKnot] = time for each knot point (monotonic!)
%
%   OUTPUTS:
%     pp = struct to be evaluated by Matlab's ppval command
%
%   NOTES:   (strongly suggested)
%
%     tData([1,end]) == tKnot([1,end])
%

nFunc = size(xData,1);
nKnot = length(tKnot);

xGuess = interp1(tData',xData',tKnot')';

%Numerically estimate the local slope
vData = zeros(size(xData));
for i=1:nFunc
vData(i,:) = diffCenter(xData(i,:),mean(diff(tData)));
end

vGuess = interp1(tData',vData',tKnot')';
zGuess = reshape([xGuess;vGuess],2*nFunc*nKnot,1);
options = optimoptions('fminunc',...
    'MaxFunEvals',200*length(zGuess),...
    'Display','off',...
    'Algorithm','quasi-newton');

objFun = @(z)checkFit(z,tData,xData,tKnot,nFunc,nKnot);
zSoln = fminunc(objFun,zGuess,options);

% Check the solution and return the answer:
[mse, pp] = checkFit(zSoln,tData,xData,tKnot,nFunc,nKnot);

end

function [mse, pp] = checkFit(z,tData,xData,tKnot,nFunc,nKnot)

zKnot = reshape(z,2*nFunc,nKnot);
xKnot = zKnot(1:nFunc,:);
vKnot = zKnot((nFunc+1):end,:);

pp = pwch(tKnot,xKnot,vKnot);
xFit = ppval(pp,tData);
mse = sum(mean((xFit-xData).^2));

end

function dx = diffCenter(x,dt)
% dx = diffCenter(x,dt)
%
%   Computes the second-order finite difference approximation of x with
%   respect to t. A one-sided second order difference is used at the end
%   points, so size(dx) == size(x).
%
%   INPUTS:
%       x = [1 x n] vector of function values
%       dt = sampling period of x   (default = 1)
%
%   OUTPUTS:
%       d = dx/dt = first derivative of x wrt t
%
% See also: cumInt, diff

if nargin == 1
    dt = 1;
end

if length(dt) ~= 1
    error('Time-step (dt) must be a scalar');
end

n = length(x);
if n < 2
    error('length(x) must be at least 2');
elseif n == 2
    dx = diff(x)/dt;
else %Then enough points for second-order finite difference
    dx = zeros(size(x));
    Dx = diff(x);   %Matlab first-order finite difference
    dx(1) = (-3*x(1) + 4*x(2) - x(3))/(2*dt);
    dx(2:(end-1)) = (Dx(1:(end-1)) + Dx(2:end))/(2*dt);  %Mid-points are easy
    dx(end) = (x(end-2) - 4*x(end-1) + 3*x(end))/(2*dt);
end

end


% Fast computation of the vector q defined by
% q_k = \sum_{l = 1}^{N_y} G(X_k - Y_l) f_l, k = 1 .. Nx
% Using the "Efficient Bessel Decomposition"
% Code developped by Martin Averseng
% See also SCSD method by François Alouges and Matthieu Aussal.

addpath(genpath(pwd)); % Add folders of the toolbox to the path.
clear all;%#ok
close all;
clc;

Nx = 10^4;
Ny = 10^4;
fprintf('10^%s x 10^%s cloud of points \n \n',num2str(round(log(Nx)/log(10))),num2str(round(log(Ny)/log(10))))
% Data points
X = uniformCircle([0,0],1,Nx);
Y = X; %uniformCircle([0,0],1,Ny)+0.5; %uniformDisk([0.2,0],1,Ny);
f = rand(size(Y,1),1); % Vector f

% Parameter for rescaling
rMax = rMaxCalc(X,Y);

% Kernel choice:

% G = LogKernel; % G(x) = log(x)

G = Y0Kernel(0.3); % G(x) = Y0(0.3*x) => Bessel decomposition with Robin
% conditions.

% G = 3*Y0Kernel(4); % G(x) = Y0(2*x) => Method of rescaling to a root of Y0

% G = H0Kernel(1000); % G(x) = Y0(1000*x) => Selects frequencies near 0 and 1000

% G = Kernel(@(r)(exp(-r.^2)),@(r)(-2*r.*exp(-r.^2))); % Arbitrary (smooth)
% kernel

% G = Kernel(@(r)(1./r.^2 ),@(r)(-2./r.^3)); % Arbitrary (singular) kernel

% Choice of the cutoff parameter.
lambda = 3;
a = lambda/sqrt(sqrt(Nx*Ny)); %this value is of the order of the optimal
% value for data uniformly distributed in a disk. Choose lambda by trial
% and error to minimize the online time.

tol = 1e-3; % input tolerance

% Offline computations.
gradOpt = true;
timeOff = tic;
[dxGxy,dyGxy,rq,loc] = offline_dEBD(G,X,Y,a,tol);
timeOff = toc(timeOff);
fprintf('Offline computations performed in \n %s seconds \n',num2str(timeOff))
% show the radial quadrature :
% rq.showDer;

% Online procedure.
timeOn = tic;
qx = dxGxy(f);
qy = dyGxy(f);
timeOn = toc(timeOn);
fprintf('Online products computed in \n %s seconds \n',num2str(timeOn))

% Error on first entry of q
dist = sqrt((X(1,1) - Y(:,1)).^2 + (X(1,2) - Y(:,2)).^2);
distInv = 1./dist;
distInv(dist<1e-12) = 0;
Y_X_x = (Y(:,1) - X(1,1));
Y_X_y = (Y(:,2) - X(1,2));
qvalx = sum((G.evalDer(dist).*Y_X_x.*distInv).*f);
qvaly = sum((G.evalDer(dist).*Y_X_y.*distInv).*f);
disp('error on first entry');
disp(abs(qvalx - qx(1))/(norm(qx,1)));
disp(abs(qvaly - qy(1))/(norm(qy,1)));

% Error when f = [1 0 0 ... 0]
dist = sqrt((Y(1,1) - X(:,1)).^2 + (Y(1,2) - X(:,2)).^2);
distInv = 1./dist;
distInv(dist < 1e-12) = 0;
Y_X_x = (Y(1,1) - X(:,1));
Y_X_y = (Y(1,2) - X(:,2));
qvalx = (G.evalDer(dist).*Y_X_x.*distInv);
qvaly = (G.evalDer(dist).*Y_X_y.*distInv);
f = [1; zeros(size(Y,1)-1,1)];

qx = dxGxy(f);
qy = dyGxy(f);

fprintf('Linf error for f = [1 0 0 ... 0] \n (effective error / target accuracy) \n');
fprintf('%s / %s \n\n',num2str(max(abs(qvalx - qx))),num2str(tol))
fprintf('%s / %s \n\n',num2str(max(abs(qvaly - qy))),num2str(tol))

disp('Done');


function determ = minij_determinant ( n )

%*****************************************************************************80
%
%% MINIJ_DETERMINANT returns the determinant of the MINIJ matrix.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    16 October 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the order of the matrix.
%
%    Output, real DETERM, the determinant.
%
  determ = 1.0;

  for i = 1 : n
    angle = ( 2 * i - 1 ) * pi / ( 2 * n + 1 );
    determ = determ * 0.5 / ( 1.0 - cos ( angle ) );
  end

  return
end


function dms=rad2dms(rad)
% RAD2DMS  Converts radians to degrees-minutes-seconds. Vectorized.
% Version: 12 Mar 00
% Useage:  dms=rad2dms(rad)
% Input:   rad - vector of angles in radians
% Output:  dms - [d m s] array of angles in deg-min-sec, where
%                d = vector of degrees
%                m = vector of minutes
%                s = vector of seconds

% Copyright (c) 2011, Michael R. Craymer
% All rights reserved.
% Email: mike@craymer.com

d=abs(rad).*180/pi;
id=floor(d);
rm=(d-id).*60;
im=floor(rm);
s=(rm-im).*60;

%if rad<0
%  if id==0
%    if im==0
%      s = -s;
%    else
%      im = -im;
%    end
%  else
%    id = -id;
%  end
%end

ind=(rad<0 & id~=0);
id(ind)=-id(ind);

ind=(rad<0 & id==0 & im~=0);
im(ind)=-im(ind);

ind=(rad<0 & id==0 & im==0);
s(ind)=-s(ind);

dms=[id im s];


% Detecting a small subset of infeasible linear inequalities
% Section 5.8, Boyd & Vandenberghe "Convex Optimization"
% Written for CVX by Almir Mutapcic - 02/18/06
%
% We consider a set of linear inequalities A*x <= b which are
% infeasible. Here A is a matrix in R^(m-by-n) and b belongs
% to R^m. We apply a l1-norm heuristic to find a small subset
% of mutually infeasible inequalities from a larger set of
% infeasible inequalities. The heuristic finds a sparse solution
% to the alternative inequality system.
%
% Original system is A*x <= b and it alternative ineq. system is:
%
%   lambda >= 0,   A'*lambda == 0.   b'*lambda < 0
%
% where lambda in R^m. We apply the l1-norm heuristic:
%
%   minimize   sum( lambda )
%       s.t.   A'*lambda == 0
%              b'*lambda == -1
%              lambda >= 0
%
% Positive lambdas gives us a small subset of inequalities from
% the original set which are mutually inconsistent.

% problem dimensions (m inequalities in n-dimensional space)
m = 150;
n = 10;

% fix random number generator so we can repeat the experiment
seed = 0;
randn('state',seed);

% construct infeasible inequalities
A = randn(m,n);
b = randn(m,1);

fprintf(1, ['Starting with an infeasible set of %d inequalities ' ...
            'in %d variables.\n'],m,n);

% you can verify that the set is infeasible
% cvx_begin
%   variable x(n)
%   A*x <= b;
% cvx_end

% solve the l1-norm heuristic problem applied to the alternative system
cvx_begin
   variables lambda(m)
   minimize( sum( lambda ) )
   subject to
     A'*lambda == 0;
     b'*lambda == -1;
     lambda >= 0;
cvx_end

% report the smaller set of mutually inconsistent inequalities
infeas_set = find( abs(b.*lambda) > sqrt(eps)/n );
disp(' ');
fprintf(1,'Found a smaller set of %d mutually inconsistent inequalities.\n',...
        length(infeas_set));
disp(' ');
disp('A smaller set of mutually inconsistent inequalities are the ones');
disp('with row indices:'), infeas_set'

% check that this set is infeasible
% cvx_begin
%    variable x_infeas(n)
%    A(infeas_set,:)*x_infeas <= b(infeas_set);
% cvx_end


function res = glp(im,thresh)

% inputs
% im is the fourier transform of the image
% thresh is the cutoff circle radius

%outputs
% res is the filtered image

[r,c]=size(im);
d0=thresh;

d=zeros(r,c);
h=zeros(r,c);

for i=1:r
    for j=1:c
     d(i,j)=  sqrt( (i-(r/2))^2 + (j-(c/2))^2);
    end
end

for i=1:r
    for j=1:c
      h(i,j)= exp ( -( (d(i,j)^2)/(2*(d0^2)) ) );
    end
end

for i=1:r
    for j=1:c
    res(i,j)=(h(i,j))*im(i,j);

    end
end


function  test_rosenbrock()

    clc;
    clear;
    close all;

    %% Set algorithms
    if 0
        algorithms = gd_solver_list('ALL');
    else
        algorithms = gd_solver_list('NCG');
    end

    % initialize
    d = 2;
    w_init = zeros(d,1);

    %% define problem definitions
    problem = rosenbrock(d);

    % obtain optimal solution
    w_opt = problem.calc_solution();
    f_opt = problem.cost(w_opt);
    fprintf('f_opt: %.24e\n', f_opt);

    % initialize
    w_list = cell(1);
    info_list = cell(1);

    %% perform algorithms
    for alg_idx=1:length(algorithms)
        fprintf('\n\n### [%02d] %s ###\n\n', alg_idx, algorithms{alg_idx});

        clear options;
        % general options for optimization algorithms
        options.w_init = w_init;
        options.tol_gnorm = 1e-10;
        options.max_iter = 100;
        options.verbose = true;
        options.f_opt = f_opt;
        options.store_w = true;

        switch algorithms{alg_idx}
            case {'SD-STD'}

                options.step_alg = 'fix';
                options.step_init = 1;
                [w_list{alg_idx}, info_list{alg_idx}] = sd(problem, options);

            case {'SD-BKT'}

                options.step_alg = 'backtracking';
                [w_list{alg_idx}, info_list{alg_idx}] = sd(problem, options);

            case {'SD-EXACT'}

                options.step_alg = 'exact';
                [w_list{alg_idx}, info_list{alg_idx}] = sd(problem, options);

            case {'SD-WOLFE'}

                options.step_alg = 'strong_wolfe';
                [w_list{alg_idx}, info_list{alg_idx}] = sd(problem, options);

            case {'SD-SCALE-EXACT'}

                options.sub_mode = 'SCALING';
                options.step_alg = 'exact';
                [w_list{alg_idx}, info_list{alg_idx}] = sd(problem, options);

            case {'Newton-STD'}

                [w_list{alg_idx}, info_list{alg_idx}] = newton(problem, options);

            case {'Newton-DAMP'}

                options.sub_mode = 'DAMPED';
                options.step_alg = 'backtracking';
                [w_list{alg_idx}, info_list{alg_idx}] = newton(problem, options);

            case {'Newton-CHOLESKY'}

                options.sub_mode = 'CHOLESKY';
                options.step_alg = 'backtracking';
                [w_list{alg_idx}, info_list{alg_idx}] = newton(problem, options);

            case {'CG-PRELIM'}

                options.sub_mode = 'PRELIM';
                options.step_alg = 'exact';
                %options.beta_alg = 'PR';
                [w_list{alg_idx}, info_list{alg_idx}] = cg(problem, options);

            case {'CG-BKT'}

                options.sub_mode = 'STANDARD';
                options.step_alg = 'backtracking';
                %options.beta_alg = 'PR';
                [w_list{alg_idx}, info_list{alg_idx}] = cg(problem, options);

            case {'CG-EXACT'}

                options.sub_mode = 'STANDARD';
                options.step_alg = 'exact';
                %options.beta_alg = 'PR';
                [w_list{alg_idx}, info_list{alg_idx}] = cg(problem, options);

            case {'CG-PRECON-EXACT'}

                options.sub_mode = 'PRECON';
                % diagonal scaling
                options.M = diag(diag(A));
                options.step_alg = 'exact';
                options.beta_alg = 'PR';

                [w_list{alg_idx}, info_list{alg_idx}] = cg(problem, options);

            case {'NCG-PR-BTK'}

                options.sub_mode = 'STANDARD';
                options.step_alg = 'backtracking';
                options.beta_alg = 'PR';
                [w_list{alg_idx}, info_list{alg_idx}] = ncg(problem, options);

            case {'NCG-PR-WOLFE'}

                options.sub_mode = 'STANDARD';
                options.step_alg = 'strong_wolfe';
                options.beta_alg = 'PR';
                [w_list{alg_idx}, info_list{alg_idx}] = ncg(problem, options);

            case {'NCG-FR-BTK'}

                options.sub_mode = 'STANDARD';
                options.step_alg = 'backtracking';
                options.beta_alg = 'FR';
                [w_list{alg_idx}, info_list{alg_idx}] = ncg(problem, options);

            case {'NCG-FR-WOLFE'}

                options.sub_mode = 'STANDARD';
                options.step_alg = 'strong_wolfe';
                options.beta_alg = 'FR';
                [w_list{alg_idx}, info_list{alg_idx}] = ncg(problem, options);

            case {'BFGS-H-BKT'}

                options.step_alg = 'backtracking';
                [w_list{alg_idx}, info_list{alg_idx}] = bfgs(problem, options);

            case {'BFGS-H-EXACT'}

                options.step_alg = 'exact';
                [w_list{alg_idx}, info_list{alg_idx}] = bfgs(problem, options);

            case {'BFGS-B-BKT'}

                options.step_alg = 'backtracking';
                options.update_mode = 'B';
                [w_list{alg_idx}, info_list{alg_idx}] = bfgs(problem, options);

            case {'BFGS-B-EXACT'}

                options.step_alg = 'exact';
                options.update_mode = 'B';
                [w_list{alg_idx}, info_list{alg_idx}] = bfgs(problem, options);

            case {'DAMPED-BFGS-BKT'}

                options.step_alg = 'backtracking';
                options.update_mode = 'Damping';
                [w_list{alg_idx}, info_list{alg_idx}] = bfgs(problem, options);

            case {'DAMPED-BFGS-EXACT'}

                options.step_alg = 'exact';
                options.update_mode = 'Damping';
                [w_list{alg_idx}, info_list{alg_idx}] = bfgs(problem, options);

            case {'L-BFGS-BKT'}

                options.step_alg = 'backtracking';
                [w_list{alg_idx}, info_list{alg_idx}] = lbfgs(problem, options);

            case {'L-BFGS-EXACT'}

                options.step_alg = 'exact';
                [w_list{alg_idx}, info_list{alg_idx}] = lbfgs(problem, options);

            case {'L-BFGS-WOLFE'}

                options.step_alg = 'strong_wolfe';
                [w_list{alg_idx}, info_list{alg_idx}] = lbfgs(problem, options);

            case {'BB'}

                options.step_alg = 'exact';
                [w_list{alg_idx}, info_list{alg_idx}] = bb(problem, options);

            case {'SGD'}

                options.batch_size = 1;
                options.step = 0.1 * options.batch_size;
                %options.step_alg = 'decay';
                options.step_alg = 'fix';

                [w_list{alg_idx}, info_list{alg_idx}] = sgd(problem, options);

            otherwise
                warn_str = [algorithms{alg_idx}, ' is not supported.'];
                warning(warn_str);
                w_list{alg_idx} = '';
                info_list{alg_idx} = '';
        end

    end

    %% plot all
    close all;

    % display iter vs cost/gnorm
    display_graph('iter','cost', algorithms, w_list, info_list);
    display_graph('iter','gnorm', algorithms, w_list, info_list);

    % draw convergence sequence
    w_history = cell(1);
    cost_history = cell(1);
    for alg_idx=1:length(algorithms)
        w_history{alg_idx} = info_list{alg_idx}.w;
        cost_history{alg_idx} = info_list{alg_idx}.cost;
    end
    draw_convergence_sequence(problem, w_opt, algorithms, w_history, cost_history);

end


function p4 = angle_half ( p1, p2, p3 )

%*****************************************************************************80
%
%% ANGLE_HALF finds half an angle.
%
%  Discussion:
%
%    The original angle is defined by the sequence of points P1, P2 and P3.
%
%    The point P4 is calculated so that:
%
%      (P1,P2,P4) = (P1,P2,P3) / 2
%
%        P1
%        /
%       /   P4
%      /  .
%     / .
%    P2--------->P3
%
%    Thanks to Cesar Fraga Bobis for pointing out a typographical error in
%    a previous version of this routine.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 December 2010
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real P1(2,1), P2(2,1), P3(2,1), points defining the angle.
%
%    Input, real P4(2,1), a point defining the half angle.
%    The vector P4 - P2 will have unit norm.
%
  p4(1:2,1) = 0.5 * ( ...
      ( p1(1:2,1) - p2(1:2,1) ) / sqrt ( sum ( ( p1(1:2,1) - p2(1:2,1) ).^2 ) ) ...
    + ( p3(1:2,1) - p2(1:2,1) ) / sqrt ( sum ( ( p3(1:2,1) - p2(1:2,1) ).^2 ) ) );

  p4(1:2,1) = p2(1:2,1) + p4(1:2,1) / sqrt ( sum ( ( p4(1:2,1) ).^2 ) );

  return
end


function xBnd = SmoothBnd(x,alpha,Bnd)
%
% xBnd = SmoothBnd(x,alpha,Bnd)
%
% This function is used to smoothly bound the input x;
%
% INPUTS:
%   x = a vector of real numbers to apply bounds
%   alpha = a positive smoothing parameter. Small values correspond to
%           little smoothing
%   Bnd = the desired bounds of the function, expressed as a 2-element row
%         vector. If ommitted it will default to [0,1];
%
% Written by Matthew Kelly
% October 2013
% Cornell University
%

if nargin==2
    Low = 0;
    Upp = 1;
else
    Low = Bnd(1);
    Upp = Bnd(2);
end

infTest1 = exp(max(x-Low)/alpha);
infTest2 = exp(max(-(x-Upp))/alpha);

if isinf(infTest1) || isinf(infTest2)  %Then there is a sharp transition
    xBnd = x;
    xBnd(x<Low) = Low;
    xBnd(x>Upp) = Upp;
else
    %Apply bounding to each part of the input:
    xLow = Low + alpha*log(exp((x-Low)/alpha)+1);
    xUpp = Upp - alpha*log(exp(-(x-Upp)/alpha)+1);

    %Combine:
    xBnd = xLow + xUpp - x;
end

end


function pdf = coupon_complete_pdf ( type_num, box_num )

%*****************************************************************************80
%
%% COUPON_COMPLETE_PDF evaluates the Complete Coupon Collection PDF.
%
%  Discussion:
%
%    PDF(TYPE_NUM;BOX_NUM) is the probability that, given an inexhaustible
%    supply of boxes, inside each of which there is one of TYPE_NUM distinct
%    coupons, which are uniformly distributed among the boxes, that it will
%    require opening exactly BOX_NUM boxes to achieve at least one of each
%    kind of coupon.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    25 August 2006
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Herbert Wilf,
%    Some New Aspects of the Coupon Collector's Problem,
%    SIAM Review,
%    Volume 48, Number 3, September 2006, pages 549-565.
%
%  Parameters:
%
%    Input, integer BOX_NUM, the number of boxes that had to be opened
%    in order to just get at least one of each coupon.
%    0 <= BOX_NUM.  If BOX_NUM < TYPE_NUM, then PDF is surely 0.
%
%    Input, integer TYPE_NUM, the number of distinct coupons.
%    1 <= TYPE_NUM.
%
%    Output, real PDF, the value of the PDF.
%

%
%  Nonsense cases.
%
  if ( box_num < 0 )

    pdf = 0.0;

  elseif ( type_num < 1 )

    pdf = 0.0;
%
%  Degenerate but meaningful case.
%
  elseif ( type_num == 1 )

    if ( box_num == 1 )
      pdf = 1.0;
    else
      pdf = 0.0;
    end
%
%  Easy cases.
%
  elseif ( box_num < type_num )

    pdf = 0.0;
%
%  General case.
%
  else

    factor = 1.0;
    for i = 1 : type_num
      factor = factor * i / type_num;
    end
    for i = type_num+1 : box_num
      factor = factor / type_num;
    end

    pdf = factor * stirling2_value ( box_num-1, type_num-1 );

  end

  return
end


function integral = piecewise_linear_product_integral ( a, b, f_num, f_x, ...
  f_v, g_num, g_x, g_v )

%*****************************************************************************80
%
%% PIECEWISE_LINEAR_PRODUCT_INTEGRAL: piecewise linear product integral.
%
%  Discussion:
%
%    We are given two piecewise linear functions F(X) and G(X) and we wish
%    to compute the exact value of the integral
%
%      INTEGRAL = Integral ( A <= X <= B ) F(X) * G(X) dx
%
%    The functions F(X) and G(X) are defined as tables of coordinates X and
%    values V.  A piecewise linear function is evaluated at a point X by
%    evaluating the interpolant to the data at the endpoints of the interval
%    containing X.
%
%    It must be the case that A <= B.
%
%    It must be the case that the node coordinates F_X(*) and G_X(*) are
%    given in ascending order.
%
%    It must be the case that:
%
%      F_X(1) <= A and B <= F_X(F_NUM)
%      G_X(1) <= A and B <= G_X(G_NUM)
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    30 April 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real A, B, the limits of integration.
%
%    Input, integer F_NUM, the number of nodes for F.
%
%    Input, real F_X(F_NUM), the node coordinates for F.
%
%    Input, real F_V(F_NUM), the nodal values for F.
%
%    Input, integer G_NUM, the number of nodes for G.
%
%    Input, real G_X(G_NUM), the node coordinates for G.
%
%    Input, real G_V(G_NUM), the nodal values for G.
%
%    Output, real INTEGRAL, the integral of F(X) * G(X)
%    from A to B.
%
  integral = 0.0;

  if ( f_x(f_num) <= a || g_x(g_num) <= a )
    return
  end

  if ( f_num < 2 || g_num < 2 )
    return
  end

  xr = a;

  f_left = 1;
  f_left = r8vec_bracket3 ( f_num, f_x, xr, f_left );
  fr = f_v(f_left) + ( xr - f_x(f_left) ) * ( f_v(f_left+1) - f_v(f_left) ) ...
    / ( f_x(f_left+1) - f_x(f_left) );

  g_left = 1;
  g_left = r8vec_bracket3 ( g_num, g_x, xr, g_left );
  gr = g_v(g_left) + ( xr - g_x(g_left) ) * ( g_v(g_left+1) - g_v(g_left) ) ...
    / ( g_x(g_left+1) - g_x(g_left) );

  xr_max = b;
  xr_max = min ( xr_max, f_x(f_num) );
  xr_max = min ( xr_max, g_x(g_num) );

  while ( xr < xr_max )
%
%  Shift right values to left.
%
    xl = xr;
    fl = fr;
    gl = gr;
%
%  Determine the new right values.
%  The hard part is figuring out how to advance XR some, but not too much.
%
    xr = xr_max;

    for i = 1 : 2
      if ( f_left + i <= f_num )
        if ( xl < f_x(f_left+i) && f_x(f_left+i) < xr )
          xr = f_x(f_left+i);
          break
        end
      end
    end

    for i = 1 : 2
      if ( g_left + i <= g_num )
        if ( xl < g_x(g_left+i) && g_x(g_left+i) < xr )
          xr = g_x(g_left+i);
          break
        end
      end
    end

    f_left = r8vec_bracket3 ( f_num, f_x, xr, f_left );
    fr = f_v(f_left) + ( xr - f_x(f_left) ) * ( f_v(f_left+1) - f_v(f_left) ) ...
      / ( f_x(f_left+1) - f_x(f_left) );

    g_left = r8vec_bracket3 ( g_num, g_x, xr, g_left );
    gr = g_v(g_left) + ( xr - g_x(g_left) ) * ( g_v(g_left+1) - g_v(g_left) ) ...
      / ( g_x(g_left+1) - g_x(g_left) );
%
%  Form the linear polynomials for F(X) and G(X) over [XL,XR],
%  then the product H(X), integrate H(X) and add to the running total.
%
    if ( eps <= abs ( xr - xl ) )

      f1 = fl - fr;
      f0 = fr * xl - fl * xr;

      g1 = gl - gr;
      g0 = gr * xl - gl * xr;

      h2 = f1 * g1;
      h1 = f1 * g0 + f0 * g1;
      h0 = f0 * g0;

      h2 = h2 / 3.0;
      h1 = h1 / 2.0;

      bit = ( ( h2 * xr + h1 ) * xr + h0 ) * xr ...
          - ( ( h2 * xl + h1 ) * xl + h0 ) * xl;

      integral = integral + bit / ( xr - xl ) / ( xr - xl );

    end

  end

  return
end


function [x,z]=constrainedLSEq(A,b,B,d,algorithm)
%%CONSTRAINEDLSEQ Find x to minimize norm(A*x-b)^2 under the constraint
%                 that B*x=d. It is assumed that the (m+p)Xn stacked matrix
%                 [A;B] has linearly independent columns (left invertible)
%                 and B has linearly independent rows (right invertible).
%                 This means that p<=n<=m+p. This is equality constrained
%                 least squares.
%
%INPUTS: A A real mXn matrix
%        b A real mX1 vector.
%        B A real pXn matrix.
%        d A real pX1 vector.
% algorithm An optional prameter specfying the algorithm to use. Possible
%          values are:
%          0 (The default if omitted or an empty matrix is passed) Use
%            Algorithm  6.2.2 in Chapter 6.2.3 of [1].
%          1 In Chapter 14 of [2], it is shown that x solves the
%            constrained least squares problem if and only if there exists
%            a z such that [A'*A, B'; B, zeros(p,p)]*[x;z]=[A'*b;d]
%            This is a set of n+p equations and unknowns. This solution
%            just solves that system.
%          2 Use the algorithm of Chapter 6.2.5 of [1], which makes use of
%            the generalized singular value decomposition (GSVD).
%
%OUTPUTS: x The solution to the equality constrained least squares problem.
%           An mX1 vector.
%         z If algorithm=0, this is an (n-p)X1 unconstrained solution that
%           is an intermediate result. If algorithm=1, this is the pX1 set
%           of Lagrangian multipliers used in the solution. If algorithm=2,
%           this is an empty matrix.
%
%REFERENCES:
%[1] G. H. Golub and C. F. Van Loan, Matrix Computations, 4th ed.
%    Baltimore: Johns Hopkins University Press, 2013.
%[2] S. Boyd and L. Vandenberghe, Vectors, Matrices, and Least Squares,
%    Sep. 2015, draft version of book. [Online].
%    Available: http://www.seas.ucla.edu/~vandenbe/133A/133A-textbook.pdf
%
%November 2015 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

if(nargin<5||isempty(algorithm))
    algorithm=0;
end

switch(algorithm)
    case 0%Algorithm 6.2.2 in Chapter 6.2.3 of [1].
        [~,n1]=size(A);
        [m2,~]=size(B);

        [Q,R]=qr(B');
        opts.UT=false;
        opts.LT=true;
        opts.RECT=false;
        y=linsolve(R(1:m2,1:m2)',d,opts);

        A=A*Q;
        z=linearLeastSquares(A(:,(m2+1):n1),b-A(:,1:m2)*y);
        x=Q(:,1:m2)*y+Q(:,(m2+1):n1)*z;
    case 1%From Chapter 14 of [2].
        m=size(A,2);
        p=size(B,1);
        H=A'*A;
        c=A'*b;
        xz=[H,B';
            B,zeros(p,p)]\[c;d];

        x=xz(1:m);
        z=xz((m+1):end); %The Lagrangian multipliers.
    case 2%The GSVD approach of Chapter 6.2.5 of [1].
        [~,n1]=size(A);
        [m2,~]=size(B);

        [U1,U2,X,DA,DB]=gsvd(A,B);
        bTilde=U1'*b;
        dTilde=U2'*d;

        %The definition of the GSVD used in Chapter 6.1.6 of [1] is not the
        %same as that implemented by Matlab's gsvd function. Specifically,
        %we have to modify X as follows:
        X=inv(X');

        alphaVals=diag(DA);
        betaVals=diag(DB);

        x=zeros(n1,1);
        for i=1:m2
            x=x+(dTilde(i)/betaVals(i))*X(:,i);
        end

        for i=(m2+1):n1
            x=x+(bTilde(i)/alphaVals(i))*X(:,i);
        end
        z=[];
    otherwise
        error('Unknown algorithm specified.')
end
end

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


function M = makeFslXfmMatrix(T,R,S,filename)
%MAKEFSLXFMMATRIX Make FSL-compatible transformation matrix.
%   M = MAKEFSLXFMMATRIX(T,R,S,FILENAME) outputs a 4x4 transformation
%   matrix performing the translations in T, the rotations in R and the
%   scalings in S and writes this matrix to the file specified by the
%   string FILENAME. This file is compatible with FSL's flirt and thus can
%   be directly used without further modification.
%
%   This function is actually the inverse function of FSL's avscale in that
%   avscale reads a transformation matrix file and lists the corresponding
%   translation, rotation and so on.
%
%   MAKEFSLXFMMATRIX can be especially useful if you would like to run
%   simulations.
%
%   Please note that, just as in avscale, T is in millimeters, R is in
%   radians and S is unitless.
%
%   Usage example:
%   ==============
%   T = [1.433440 19.715600 0.786690]; % in mm.
%   R = [0.102735 -0.155470 0.121564]; % in rad.
%   S = [1 1 1]; % unitless
%   filename = 'thisIsWhatIWant.mat'; % :))
%
%   M = makeFslXfmMatrix(T,R,S,filename);
%
%   Now you can use avscale to see if things are working correctly.
%
%   [status,result] = system(['avscale --allparams thisIsWhatIWant.mat']);
%   disp(result)
%
%   Best.

% Check inputs
if ~isnumeric(T) || ~isnumeric(R) || ~isnumeric(S)
    error('T, R and S have to be numeric...');
end

if ~ischar(filename)
    error('FILENAME has to be a string...');
end

% Get rotation angles about each axis.
thetaX = R(1);
thetaY = R(2);
thetaZ = R(3);

% Compute the rotation matrices.
Rx = [1 0 0; 0 cos(thetaX) sin(thetaX);0 -sin(thetaX) cos(thetaX)];
Ry = [cos(thetaY) 0 -sin(thetaY);0 1 0;sin(thetaY) 0 cos(thetaY)];
Rz = [cos(thetaZ) sin(thetaZ) 0;-sin(thetaZ) cos(thetaZ) 0;0 0 1];

% Concatenate rotations.
R_3x3 = Rx*Ry*Rz;

% Put scalings on the diagonal.
S_3x3 = diag(S);

% Make the 4x4 transformation matrix.
M = [R_3x3*S_3x3 T(:); 0 0 0 1];

% Try to open the file
fid = fopen(filename,'w');

% Check if it worked
if fid == -1
    error(['Could not open for writing: ' filename]);
end

for k = 1:4
    fprintf(fid,[num2str(M(k,:)) '\n']);
end

fclose(fid);


function variance = english_word_length_variance ( )

%*****************************************************************************80
%
%% ENGLISH_WORD_LENGTH_VARIANCE: variance of the English Word Length PDF.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    31 July 2006
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Henry Kucera, Winthrop Francis,
%    Computational Analysis of Present-Day American English,
%    Brown University Press, 1967.
%
%  Parameters:
%
%    Output, real VARIANCE, the variance of the PDF.
%
  word_length_max = 27;

  pdf_vec = [ ...
    0.03160, ...
    0.16975, ...
    0.21192, ...
    0.15678, ...
    0.10852, ...
    0.08524, ...
    0.07724, ...
    0.05623, ...
    0.04032, ...
    0.02766, ...
    0.01582, ...
    0.00917, ...
    0.00483, ...
    0.00262, ...
    0.00099, ...
    0.00050, ...
    0.00027, ...
    0.00022, ...
    0.00011, ...
    0.00006, ...
    0.00005, ...
    0.00002, ...
    0.00001, ...
    0.00001, ...
    0.00001, ...
    0.00001, ...
    0.00001 ];
  pdf_sum = 0.99997;

  mean = 0.0;
  for j = 1 : word_length_max
    mean = mean + j * pdf_vec(j);
  end

  mean = mean / pdf_sum;

  variance = 0.0;
  for j = 1 : word_length_max
    variance = variance + pdf_vec(j) * ( j - mean )^2;
  end

  variance = variance / pdf_sum;

  return
end


function [ x, w ] = nco_set ( n )

%*****************************************************************************80
%
%% NCO_SET sets abscissas and weights for open Newton-Cotes quadrature.
%
%  Discussion:
%
%    The open Newton-Cotes rules use equally spaced abscissas, and
%    hence may be used with equally spaced data.
%
%    The rules are called "open" because they do not include the interval
%    endpoints.
%
%    Most of the rules involve negative weights.  These can produce loss
%    of accuracy due to the subtraction of large, nearly equal quantities.
%
%    The integral:
%
%      Integral ( -1 <= X <= 1 ) F(X) dX
%
%    The quadrature rule:
%
%      Sum ( 1 <= I <= N ) W(I) * F ( X(I) )
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    02 May 2006
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Abramowitz and Stegun,
%    Handbook of Mathematical Functions,
%    National Bureau of Standards, 1964.
%
%    Stephen Wolfram,
%    The Mathematica Book,
%    Fourth Edition,
%    Wolfram Media / Cambridge University Press, 1999.
%
%    Daniel Zwillinger, editor,
%    Standard Mathematical Tables and Formulae,
%    30th Edition,
%    CRC Press, 1996.
%
%  Parameters:
%
%    Input, integer N, the order.
%    N must be between 1 and 7, and 9.
%
%    Output, real X(N), the abscissas.
%
%    Output, real W(N), the weights.
%
  x = zeros ( n, 1 );
  w = zeros ( n, 1 );

  if ( n == 1 )

    w(1) = 2.0;

  elseif ( n == 2 )

    w(1) = 1.0;
    w(2) = 1.0;

  elseif ( n == 3 )

    d = 3.0;

    w(1) =   4.0 / d;
    w(2) = - 2.0 / d;
    w(3) =   4.0 / d;

  elseif ( n == 4 )

    d = 12.0;

    w(1) = 11.0 / d;
    w(2) =  1.0 / d;
    w(3) =  1.0 / d;
    w(4) = 11.0 / d;

  elseif ( n == 5 )

    d = 10.0;

    w(1) =   11.0 / d;
    w(2) = - 14.0 / d;
    w(3) =   26.0 / d;
    w(4) = - 14.0 / d;
    w(5) =   11.0 / d;

  elseif ( n == 6 )

    d = 1440.0;

    w(1) =  1222.0 / d;
    w(2) = - 906.0 / d;
    w(3) =  1124.0 / d;
    w(4) =  1124.0 / d;
    w(5) = - 906.0 / d;
    w(6) =  1222.0 / d;

  elseif ( n == 7 )

    d = 945.0;

    w(1) =    920.0 / d;
    w(2) = - 1908.0 / d;
    w(3) =   4392.0 / d;
    w(4) = - 4918.0 / d;
    w(5) =   4392.0 / d;
    w(6) = - 1908.0 / d;
    w(7) =    920.0 / d;

  elseif ( n == 9 )

    d = 4536.0;

    w(1) =    4045.0 / d;
    w(2) = - 11690.0 / d;
    w(3) =   33340.0 / d;
    w(4) = - 55070.0 / d;
    w(5) =   67822.0 / d;
    w(6) = - 55070.0 / d;
    w(7) =   33340.0 / d;
    w(8) = - 11690.0 / d;
    w(9) =    4045.0 / d;

  else

    fprintf ( 1, '\n' );
    fprintf ( 1, 'NCO_SET - Fatal error!\n' );
    fprintf ( 1, '  Illegal value of N = %d\n', n );
    fprintf ( 1, '  Legal values are 1 to 7, and 9.\n' );
    error ( 'NCO_SET - Fatal error!' );

  end
%
%  Set the abscissas.
%
  for i = 1 : n
    x(i) = ( 2 * i - n - 1 ) / ( n + 1 );
  end

  return
end


  function [lo hi] = ir_dwt_filters(wname, varargin)
%|function [coef codes] = ir_odwt1(x, varargin)
%|
%| filters for discrete wavelet transform DWT
%|
%| in
%|	'wname'	char	'haar' (default) or 'db4' or 'sym2'
%|
%| option
%|	'usemat' 0|1	default: 0. (if 1 then use matlab wfilters)
%|	'ortho'	0|1	default: 1 (make normalized)
%|	'abs'	0|1	default: 0. (if 1 then take abs of filters)
%|
%| out
%|	lo	[K]	low-pass decomposition filter
%|	hi	[K]	hi-pass decomposition filter
%|
%| 2012-05-21, Jeff Fessler, Univ. of Michigan
%| 2014-01-23, Matt Muckley: added 'db4'

if nargin < 1, ir_usage, end
if streq(wname, 'test'), ir_dwt_filters_test, return, end

arg.wname = wname;
arg.ortho = true;
arg.usemat = false;
arg.abs = false;
arg = vararg_pair(arg, varargin);

if isempty(arg.wname)
	 arg.wname = 'haar';
end

% decomposition filters
if arg.usemat
	[lo hi lo_r hi_r] = wfilters(arg.wname);
	lo = lo'; lo_r = lo_r';
	hi = hi'; hi_r = hi_r';

	jf_equal(lo_r, flipud(lo))
	jf_equal(hi_r, flipud(hi))
else
	switch arg.wname
	case 'haar'
		lo = [1 1]';
		hi = [-1 1]';

	case 'db4'
		h1 = (1 + sqrt(3))/4;
		h2 = (3 + sqrt(3))/4;
		h3 = (3 - sqrt(3))/4;
		h4 = (1 - sqrt(3))/4;
		lo = [h1 h2 h3 h4]';
		hi = [h4 -h3 h2 -h1]';
		clear h1 h2 h3 h4;

	case 'sym2'
		lo = [-0.129409522550921; 0.224143868041857; ...
			0.836516303737469; 0.482962913144690];
		hi = [-0.482962913144690; 0.836516303737469; ...
			-0.224143868041857; -0.129409522550921];
	otherwise
		fail('unknown wname "%s"', arg.wname)
	end
end

if arg.ortho
	lo = lo / norm(lo);
	hi = hi / norm(hi);
end

if arg.abs
	lo = abs(lo);
	hi = abs(hi);
end

% ir_dwt_filters_test()
function ir_dwt_filters_test

list = {'haar', 'sym2', 'db4'};
for ii=1:numel(list)
	wname = list{ii};

	[lo0 hi0] = ir_dwt_filters(wname, 'usemat', 0);
	if numel(lo0) == 2
		jf_equal(lo0' * hi0, 0)
	else
		equivs(1, 1 + lo0' * hi0)
	end

	if exist('dwt', 'file') == 2 && exist('wfilters', 'file') == 2
		[lo1 hi1] = ir_dwt_filters(wname, 'usemat', 1);
	end

	[lo hi] = ir_dwt_filters(wname, 'ortho', 0);
	jf_equal(lo/norm(lo), lo0)
	jf_equal(hi/norm(hi), hi0)

	[lo hi] = ir_dwt_filters(wname, 'abs', 1);
	jf_equal(abs(lo0), lo)
	jf_equal(abs(hi0), hi)
end


%% RATE OF CONVERGENCE OF LINEAR FINITE ELEMENT METHOD
%
% This example is to show the rate of convergence of linear finite element
% approximation of the Poisson equation on the unit square:
%
% $$- \Delta u = f \; \hbox{in } (0,1)^2$$
%
% for the following boundary condition:
%
% # Non-empty Dirichlet boundary condition. $u=g_D \hbox{ on }\Gamma_D, \quad \nabla u\cdot n=g_N \hbox{ on }\Gamma_N. \Gamma _D = \{(x,y): x=0, y\in [0,1]\}, \; \Gamma _N = \partial \Omega \backslash \Gamma _D$.
% # Pure Neumann boundary condition. $\Gamma _N = \partial \Omega$.
% # Robin boundary condition. $g_R u + \nabla u\cdot n=g_N \hbox{ on }\partial \Omega$

%%
clear all; close all;
[node,elem] = cubemesh([0,1,0,1,0,1],0.25);
pde = sincosdata3;
option.L0 = 0;
option.maxIt = 4;
option.printlevel = 1;
option.elemType = 'CR';
option.plotflag = 0;

%% Non-empty Dirichlet boundary condition.
bdFlag = setboundary3(node,elem,'Dirichlet','~(x==0)','Neumann','x==0');
% bdFlag = setboundary3(node,elem,'Dirichlet');
femPoisson3(node,elem,pde,bdFlag,option);

%% Pure Neumann boundary condition.
% pde = sincosNeumanndata;
bdFlag = setboundary3(node,elem,'Neumann');
femPoisson3(node,elem,pde,bdFlag,option);

%% Pure Robin boundary condition.
pdeRobin = sincosRobindata3;
bdFlag = setboundary3(node,elem,'Robin');
femPoisson3(node,elem,pdeRobin,bdFlag,option);

%% Conclusion
%
% The optimal rate of convergence of the H1-norm (1st order) and L2-norm
% (2nd order) is observed. No superconvergence for ||DuI-Duh||.
%
% MGCG converges uniformly in all cases.


function [xx, yy, zz] = chebpts3(nx, ny, nz, dom, kind)
%CHEBPTS3   3D tensor product Chebyshev grid.
%   [XX YY ZZ] = CHEBPTS3(N) constructs an N by N by N grid of Chebyshev
%   tensor points on [-1 1]^3.
%
%   [XX YY ZZ] = CHEBPTS3(NX,NY,NZ) constructs an NX by NY by NZ grid of
%   Chebyshev tensor points on [-1 1]^3.
%
%   [XX YY ZZ] = CHEBPTS3(NX,NY,NZ,DOM) constructs an NX by NY by NZ grid
%   of Chebyshev tensor points on the cube [a b] x [c d] x [e g], where
%   DOM = [a b c d e g].
%
%   [XX YY ZZ] = CHEBPTS3(NX,NY,NZ,D,KIND) constructor Chebyshev tensor
%   grid of the kind KIND. KIND = 2 is default.
%
% See also CHEBPTS and CHEBPTS2.

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

if ( nargin > 3 )
   % Third argument should be a domain.
   dom = dom(:).';  % make a row vector.
   if ( ~all(size(dom) == [1 6]) )
        error('CHEBFUN:chebpts3:domain', 'Unrecognised domain.');
   end
else  % Default to the canoncial domain.
    dom = [-1, 1, -1, 1, -1, 1];
end

if ( nargin == 1 )
    % Make it a square Chebyshev grid if only one input.
    ny = nx;
    nz = nx;
end
if ( nargin < 5 )
    % default to Chebyshev points of the 2nd kind.
    kind = 2;
end

% Get points:
x = chebpts(nx, dom(1:2), kind);
y = chebpts(ny, dom(3:4), kind);
z = chebpts(nz, dom(5:6), kind);

% Tensor product.
[xx, yy, zz] = ndgrid(x, y, z);

end


function quality=meshquality(node,elem,maxnode)
%
% quality=meshquality(node,elem)
%
% compute the Joe-Liu mesh quality measure of an N-D mesh (N<=3)
%
% author: Qianqian Fang, <q.fang at neu.edu>
% date: 2011/02/26
%
% input:
%    node:  node coordinates of the mesh (nn x 3)
%    elem:  element table of an N-D mesh (ne x (N+1))
%
% output:
%    quality: a vector of the same length as size(elem,1), with
%           each element being the Joe-Liu mesh quality metric (0-1) of
%           the corresponding element. A value close to 1 represents
%           higher mesh quality (1 means equilateral tetrahedron);
%           a value close to 0 means nearly degenerated element.
%
% reference:
%    A. Liu, B. Joe, Relationship between tetrahedron shape measures,
%                    BIT 34 (2) (1994) 268-287.
%
% -- this function is part of iso2mesh toolbox (http://iso2mesh.sf.net)
%

if(nargin<3)
    maxnode=4;
end
if(size(elem,2)>maxnode)
    elem=elem(:,1:maxnode);
end
enum=size(elem,1);
vol=elemvolume(node,elem);
edges=meshedge(elem);
ed=node(edges(:,1),:)-node(edges(:,2),:);
ed=sum((ed.*ed)');
ed=sum(reshape(ed,[enum length(ed)/enum])')';
dim=size(elem,2)-1;

coeff=10/9; % for tetrahedral
if(dim==2)
    coeff=1;
end
quality=coeff*dim*2^(2*(1-1./dim))*3^((dim-1)/2)*vol.^(2/dim)./ed;
maxquality=max(quality);
if(maxquality>1)
    quality=quality./maxquality;
end


function [theta, J_history] = gradientDescent(X, y, theta, alpha, num_iters)
%GRADIENTDESCENT Performs gradient descent to learn theta
%   theta = GRADIENTDESENT(X, y, theta, alpha, num_iters) updates theta by
%   taking num_iters gradient steps with learning rate alpha

% Initialize some useful values
m = length(y); % number of training examples
J_history = zeros(num_iters, 1);

for iter = 1:num_iters

    % ====================== YOUR CODE HERE ======================
    % Instructions: Perform a single gradient step on the parameter vector
    %               theta.
    %
    % Hint: While debugging, it can be useful to print out the values
    %       of the cost function (computeCost) and gradient here.
    %

    delta = (1/m)*sum(X.*repmat((X*theta - y), 1, size(X,2)));

    theta = (theta' - (alpha * delta))';

    % ============================================================

    % Save the cost J in every iteration
    J_history(iter) = computeCost(X, y, theta);

end

end

github-repos/MATLAB/Borye-machine-learning-coursera-1/machine-learning-coursera-1-033fdc2e6da393eeb1179a09aafe92362021effb/Week 2 Assignments/Linear Regression with Multiple Variables/mlclass-ex1/gradientDescent.m


%% Ellipsoid parameters
%
% Silson et al. have a very different set of ellipses, far more oriented
% than anyone else.  This was pointed out by a few of us at Stanford, and
% in discussing with Reynolds (the AFNI guy) it turned out that they solved
% the ellipse using
%
%    ax^2 + bxy + cy^2
%
% That's the wrong equation.  The correction equation is
%
%    ax^2 + 2bxy + cy^2
%
% So when the true value is b, they calculate a value of 2b.  This script
% analyses what we expect to find in terms of the ratios of major and minor
% axes if we solve erroneously, as per the AFNI calculation published by
% Silson et al.
%
% The formulae for the ellipsoid calculations are taken from Wolfram in
%
%   http://mathworld.wolfram.com/Ellipse.html
%
% The calculation shows that in many cases the ratio of the lengths of the
% major and minor axes differs quite significantly when one makes the AFNI
% error.
%
% The significance of this calculation is that Silson et al. deny that
% there is a significant difference.  Hence, there is a dispute based on
% mathematics.  Let's check this code and see who is right.
%
% Wandell, September 24, 2018

%% General quadratic notes
%
%  ax^2 + 2bxy + cy^2 + 2dx + 2fy + g=0
%
% For the centered ellipse we have d = f = 0.
% We set g = -1 for this case so
%
%   ax^2 + 2bxy + cy^2 = 1
%
% J = det([ a b; b c]) > 0 and
% D = det([ a b 0; b c 0; 0 0 1])
% I = a + c
% We require D .n.e. 0, J > 0 and D/I < 0
%

%% Set parameters

% These are the three parameters that can be changed
a = 4;
b = 1; originalB = b;
c = 3;

%{
a = 2;  b = 2; c = 3;  % 3.225 and 1.618
%}
g = -1;  % We fix g to -1 because we can always scale a,b and c to make it so

%%  The formulae for the axis lengths from the Wolfram web-page
%
% a' = sqrt((2(af^2+cd^2+gb^2-2bdf-acg))/((b^2-ac)[sqrt((a-c)^2+4b^2)-(a+c)]))
% b' = sqrt((2(af^2+cd^2+gb^2-2bdf-acg))/((b^2-ac)[-sqrt((a-c)^2+4b^2)-(a+c)])).
%
% The formulae below simplify because d=f=0 and g = -1;

b = originalB;
if ellipseValidate(a,b,c,g)

    top    = (2*(g*b^2 - a*c*g));
    bottom = (b^2 - a*c)*(sqrt((a - c)^2 + 4*b^2) - (a + c));
    aLength = sqrt(top / bottom);

    top    = (2*(g*b^2 - a*c*g));
    bottom = (b^2 - a*c)*(-1*sqrt((a - c)^2 + 4*b^2) - (a + c));
    bLength = sqrt(top / bottom);

    mx = max(aLength, bLength);
    mn = min(aLength, bLength);
    fprintf('Ratio 1: %f (b = %.2f)\n',mx/mn,b);
else
    fprintf('Not an ellipse when b = %f\n',b);
end

%% If we incorrectly solve using b2 = 2b
%
% It doesn't really matter whether we use b2 = 2b or b2 = b/2
% The b values are related by a factor of 2 and one is right and the other
% is wrong.  Reynolds says that this has no impact on the ratio of the
% lengths of the two axes.  That is bogus, as running most cases show, such
% as the ones above

b = originalB/2;
if ellipseValidate(a,b,c,g)

    top    = (2*(g*b^2 - a*c*g));
    bottom = (b^2 - a*c)*(sqrt((a - c)^2 + 4*b^2) - (a + c));
    aLength = sqrt(top / bottom);

    top    = (2*(g*b^2 - a*c*g));
    bottom = (b^2 - a*c)*(-1*sqrt((a - c)^2 + 4*b^2) - (a + c));
    bLength = sqrt(top / bottom);

    mx = max(aLength, bLength);
    mn = min(aLength, bLength);
    fprintf('Ratio 2: %f (b = %.2f)\n',mx/mn,b);
else
    fprintf('Not an ellipse when b = %f\n',b);
end

%%  Or if we divide by 2

b = originalB*2;
if ellipseValidate(a,b,c,g)

    top    = (2*(g*b^2 - a*c*g));
    bottom = (b^2 - a*c)*(sqrt((a - c)^2 + 4*b^2) - (a + c));
    aLength = sqrt(top / bottom);

    top    = (2*(g*b^2 - a*c*g));
    bottom = (b^2 - a*c)*(-1*sqrt((a - c)^2 + 4*b^2) - (a + c));
    bLength = sqrt(top / bottom);

    mx = max(aLength, bLength);
    mn = min(aLength, bLength);
    fprintf('Ratio 3: %f (b = %.2f)\n',mx/mn,b);
else
    fprintf('Not an ellipse when b = %f\n',b);
end

%%