clear all; close all; clc

n=100;
L=20; x=linspace(-L,L,n); y=x;
[X,Y]=meshgrid(x,y);

Xd=[];
for j=1:100
u=tanh(sqrt(X.^2+Y.^2)).*cos(angle(X+i*Y)-(sqrt(X.^2+Y.^2))+j/10);
f=exp(-0.01*(X.^2+Y.^2));
uf=u.*f;
Xd(:,j)=reshape(uf,n^2,1);
pcolor(x,y,uf), shading interp, colormap(hot), caxis([-1 1]), drawnow
end

%%
[U,S,V]=svd(Xd,0);

figure(2)
subplot(4,1,3)
plot(100*diag(S)/sum(diag(S)),'ko','Linewidth',[2])
subplot(4,1,4)
semilogy(100*diag(S)/sum(diag(S)),'ko','Linewidth',[2])
subplot(2,1,1)
plot(V(:,1:4),'Linewidth',[2])
legend('mode1','mode2','mode3','mode4')
set(gca,'Fontsize',[15],'Xtick',[0 20 40 60 80 100])
subplot(4,1,3), set(gca,'Fontsize',[15],'Ylim',[0 60],'Ytick',[0 20 40 60],'Xlim',[0 40],'Xtick',[0 10 20 30 40])
subplot(4,1,4), set(gca,'Fontsize',[15],'Ylim',[10^(-20) 10^2],'Ytick',[10^(-20) 10^(-10) 10^2],'Xlim',[0 40],'Xtick',[0 10 20 30 40])

figure(3)
for j=1:4
  subplot(4,4,j)
  mode=reshape(U(:,j),n,n);
  pcolor(X,Y,mode), shading interp,caxis([-0.03 0.03]), colormap(gray)
  axis off
end

%%

figure(11)
u=tanh(sqrt(X.^2+Y.^2)).*cos(angle(X+i*Y)-(sqrt(X.^2+Y.^2)));
f=exp(-0.01*(X.^2+Y.^2));
uf=u.*f;
subplot(3,3,1),pcolor(x,y,uf), shading interp, caxis([-1 1]), axis off
subplot(3,3,2),pcolor(x,y,abs(uf)), shading interp, caxis([-1 1]), axis off
subplot(3,3,3),pcolor(x,y,uf.^5), shading interp, caxis([-1 1]), axis off
colormap(gray)

%% TRANSLATION
figure(5)
n=200; L=20; x=linspace(-L,L,n); y=x;  % space
m=41; T=10; t=linspace(0,T,m);         % time
c=3;   % wave speed

X=[];
for j=1:m
    X(:,j)=exp(-(x+15-c*t(j)).^2).';  % data snapshots
end
[U,S,V]=svd(X);  % SVD decomposition

%%
figure(6)
subplot(2,2,1)
waterfall(x,t,X.'),colormap([0 0 0])
view(20,75)
set(gca,'Xlim',[-20 20],'Xtick',[-20 -10 0 10 20],'Ylim',[0 10], ...
    'Ytick',[0 5 10],'Zlim',[0 1],'Ztick',[0  1],'Fontsize',[12])

[U2,S2,V2]=svd(X);

subplot(4,2,2)
plot(100*diag(S2)/sum(diag(S2)),'ko','Linewidth',[2])
set(gca,'Xlim',[0 40],'Xtick',0:10:40,'Ylim',[0 8],'Ytick',[0 4 8])
subplot(4,2,4)
semilogy(100*diag(S2)/sum(diag(S2)),'ko','Linewidth',[2])
grid on
set(gca,'Xlim',[0 40],'Xtick',0:10:40,'Ylim',[10^(-3) 2*10^1],'Ytick',[10^(-3) 10^(-2) 10^(-1) 10^0 10^1])

figure(8)
subplot(2,1,1)
plot(x,U2(:,1:4),'Linewidth',[2]);
legend('mode1','mode2','mode3','mode4','Location','SouthEast')
set(gca,'Fontsize',[15],'Ylim',[-0.15 0.15],'Ytick',[-0.15 0 0.15])
subplot(2,1,2)
plot(t,V2(:,1:4),'Linewidth',[2])
set(gca,'Fontsize',[15],'Ylim',[-.3 0.3],'Ytick',[-0.3 0 0.3])


function C=HestonCall(St,K,r,T,vt,kap,th,sig,rho,lda)
%--------------------------------------------------------------------------
%PURPOSE: computes the option price using Heston's model.
%--------------------------------------------------------------------------
%USAGE: C=HestonCall(St,K,r,sig,T,vt,kap,th,lda,rho)
%--------------------------------------------------------------------------
%INPUT: St - scalar or vector, price of underlying at time t
%       K - scalar or vector, strike price
%       r - scalar or vector, continuously compound risk free rate expressed as a
%       positive decimal number.
%       sig- scalar or vector, volatility of the volatility of the
%       underlying(same time units as for r)
%       T - scalar or vector, time to maturity (same time units as for r)
%       vt - scalar or vector, instantaneous volatility
%       kap - scalar or vector, is the rate at which vt reverts to th
%       th - scalar or vector, is the long vol, or long run average price
%       volatility; as t tends to infinity, the expected value of ?t tends to ?
%       lda - scalar or vector, risk premium for volatility
%       rho - scalar or vector, correlation between underlying and
%       volatility (rho<0 generates the leverage effect)
%--------------------------------------------------------------------------
%OUTPUT: C - scalar or vector, Heston's model call option price
%--------------------------------------------------------------------------

dphi=0.01;
maxphi=50;
phi=(eps:dphi:maxphi)';

%f1 = CF_SVj(log(St),vt,T,r,kap*th,0.5,kap+lda-rho*sig,rho,sig,phi);
%P1 = 0.5+(1/pi)*sum(real(exp(-i*phi*log(K)).*f1./(i*phi))*dphi);
%f2 = CF_SVj(log(St),vt,T,r,kap*th,-0.5,kap+lda,rho,sig,phi);
%P2 = 0.5+(1/pi)*sum(real(exp(-i*phi*log(K)).*f2./(i*phi))*dphi);
%C = St*P1 -K*exp(-r*T)*P2;

f1 = CF_SVj(log(St),vt,T,0,kap*th,0.5,kap+lda-rho*sig,rho,sig,phi);
P1 = 0.5+(1/pi)*sum(real(exp(-i*phi*log(K)).*f1./(i*phi))*dphi);
f2 = CF_SVj(log(St),vt,T,0,kap*th,-0.5,kap+lda,rho,sig,phi);
P2 = 0.5+(1/pi)*sum(real(exp(-i*phi*log(K)).*f2./(i*phi))*dphi);
C = St*P1 -K*exp(-r*T)*P2;


function [X_t,Mu_t,Sig_t]=OUstep(X_0,t,Mu,Th,Sig)

[NumSimul,N]=size(X_0);

% location
ExpM=expm(-Th*t);

Mu_t = repmat((Mu-ExpM*Mu)',NumSimul,1) +  X_0*ExpM';

% scatter
TsT=kron(Th,eye(N))+kron(eye(N),Th);

VecSig=reshape(Sig,N^2,1);
VecSig_t=inv(TsT)*(eye(N^2)-expm(-TsT*t))*VecSig;
Sig_t=reshape(VecSig_t,N,N);
Sig_t=(Sig_t+Sig_t')/2;

Eps=mvnrnd(zeros(N,1),Sig_t,NumSimul);

X_t=Mu_t+Eps;
Mu_t=mean(Mu_t,1)';


%% Machine Learning Online Class - Exercise 2: Logistic Regression
%
%  Instructions
%  ------------
%
%  This file contains code that helps you get started on the second part
%  of the exercise which covers regularization with logistic regression.
%
%  You will need to complete the following functions in this exericse:
%
%     sigmoid.m
%     costFunction.m
%     predict.m
%     costFunctionReg.m
%
%  For this exercise, you will not need to change any code in this file,
%  or any other files other than those mentioned above.
%

%% Initialization
clear all; close all; clc

%% Load Data
%  The first two columns contains the exam scores and the third column
%  contains the label.

data = csvread('ex2data2.txt');
X = data(:, [1, 2]); y = data(:, 3);

plotData(X, y);

% Put some labels
hold on;

% Labels and Legend
xlabel('Microchip Test 1')
ylabel('Microchip Test 2')

% Specified in plot order
legend('y = 1', 'y = 0')
hold off;

%% =========== Part 1: Regularized Logistic Regression ============
%  In this part, you are given a dataset with data points that are not
%  linearly separable. However, you would still like to use logistic
%  regression to classify the data points.
%
%  To do so, you introduce more features to use -- in particular, you add
%  polynomial features to our data matrix (similar to polynomial
%  regression).
%

% Add Polynomial Features

% Note that mapFeature also adds a column of ones for us, so the intercept
% term is handled
X = mapFeature(X(:,1), X(:,2));

% Initialize fitting parameters
initial_theta = zeros(size(X, 2), 1);

% Set regularization parameter lambda to 1
lambda = 1;

% Compute and display initial cost and gradient for regularized logistic
% regression
[cost, grad] = costFunctionReg(initial_theta, X, y, lambda);

fprintf('Cost at initial theta (zeros): %f\n', cost);

fprintf('\nProgram paused. Press enter to continue.\n');
pause;

%% ============= Part 2: Regularization and Accuracies =============
%  Optional Exercise:
%  In this part, you will get to try different values of lambda and
%  see how regularization affects the decision coundart
%
%  Try the following values of lambda (0, 1, 10, 100).
%
%  How does the decision boundary change when you vary lambda? How does
%  the training set accuracy vary?
%

% Initialize fitting parameters
initial_theta = zeros(size(X, 2), 1);

% Set regularization parameter lambda to 1 (you should vary this)
lambda = 1;

% Set Options
options = optimset('GradObj', 'on', 'MaxIter', 400);

% Optimize
[theta, J, exit_flag] = ...
	fminunc(@(t)(costFunctionReg(t, X, y, lambda)), initial_theta, options);

% Plot Boundary
plotDecisionBoundary(theta, X, y);
hold on;
title(sprintf('lambda = %g', lambda))

% Labels and Legend
xlabel('Microchip Test 1')
ylabel('Microchip Test 2')

legend('y = 1', 'y = 0', 'Decision boundary')
hold off;

% Compute accuracy on our training set
p = predict(theta, X);

fprintf('Train Accuracy: %f\n', mean(double(p == y)) * 100);


#!/usr/bin/env octave
%% Machine Learning Online Class - Exercise 2: Logistic Regression
%
%  Instructions
%  ------------
%
%  This file contains code that helps you get started on the second part
%  of the exercise which covers regularization with logistic regression.
%
%  You will need to complete the following functions in this exericse:
%
%     sigmoid.m
%     costFunction.m
%     predict.m
%     costFunctionReg.m
%
%  For this exercise, you will not need to change any code in this file,
%  or any other files other than those mentioned above.
%

%% Initialization
clear ; close all; clc

%% Load Data
%  The first two columns contains the exam scores and the third column
%  contains the label.

data = load('ex2data2.txt');
X = data(:, [1, 2]); y = data(:, 3);

plotData(X, y);

% Put some labels
hold on;

% Labels and Legend
xlabel('Microchip Test 1')
ylabel('Microchip Test 2')

% Specified in plot order
legend('y = 1', 'y = 0')
hold off;

%% =========== Part 1: Regularized Logistic Regression ============
%  In this part, you are given a dataset with data points that are not
%  linearly separable. However, you would still like to use logistic
%  regression to classify the data points.
%
%  To do so, you introduce more features to use -- in particular, you add
%  polynomial features to our data matrix (similar to polynomial
%  regression).
%

% Add Polynomial Features

% Note that mapFeature also adds a column of ones for us, so the intercept
% term is handled
X = mapFeature(X(:,1), X(:,2));

% Initialize fitting parameters
initial_theta = zeros(size(X, 2), 1);

% Set regularization parameter lambda to 1
lambda = 1;

% Compute and display initial cost and gradient for regularized logistic
% regression
[cost, grad] = costFunctionReg(initial_theta, X, y, lambda);

fprintf('Cost at initial theta (zeros): %f\n', cost);

fprintf('\nProgram paused. Press enter to continue.\n');
pause;

%% ============= Part 2: Regularization and Accuracies =============
%  Optional Exercise:
%  In this part, you will get to try different values of lambda and
%  see how regularization affects the decision coundart
%
%  Try the following values of lambda (0, 1, 10, 100).
%
%  How does the decision boundary change when you vary lambda? How does
%  the training set accuracy vary?
%

% Initialize fitting parameters
initial_theta = zeros(size(X, 2), 1);

% Set regularization parameter lambda to 1 (you should vary this)
lambda = 1;

% Set Options
options = optimset('GradObj', 'on', 'MaxIter', 400);

% Optimize
[theta, J, exit_flag] = ...
	fminunc(@(t)(costFunctionReg(t, X, y, lambda)), initial_theta, options);

% Plot Boundary
plotDecisionBoundary(theta, X, y);
hold on;
title(sprintf('lambda = %g', lambda))

% Labels and Legend
xlabel('Microchip Test 1')
ylabel('Microchip Test 2')

legend('y = 1', 'y = 0', 'Decision boundary')
hold off;

% Compute accuracy on our training set
p = predict(theta, X);

fprintf('Train Accuracy: %f\n', mean(double(p == y)) * 100);

pause;


% Sympoly demos

%% Various ways to create a sympoly

% A scalar (zero) sympoly
z = sympoly;

% Scalar sympolys 'x', 'y', 'u', 'v' created in the current workspace
sympoly x y u v

% A sympoly (identity matrix) array. The numeric element format is
% specified by the command window format style.
format short g
ayuh = sympoly(eye(3));

% Use deal to replicate a sympoly into several
[a,b] = deal(sympoly);

% Deal can also create a sympoly array
S(1:2) = deal(sympoly('x'));

% As can repmat
R = repmat(sympoly('x'),2,3);

whos

%% Arithmetic between sympolys, add, subtract, multiply, divide.

% add 1 to x
1 + x

%%

% double times a sympoly
2*y

%%

% subtraction, and a simple power
(x - y)^2

%%

% More complex expressions
(x - 2*y)^3/x + sqrt(y^3)

%% Synthetic division
[quotient,remainder] = syndivide(x^2+2*x-1,x+1)

%% Arrays of sympolys
[x , y ; 1 , x+y]

%%

% Arrays of sympolys
v = [1 x y x+y]

%% matrix multiplication
A = v*v'
B = v'*v
%% Selective extraction of terms
% The second term
terms(A,2)

%%
terms(A,x^2,'extract')

%%
% Delete a term
p = (1 + x^2 + x^7)^3
terms(p,x^2,'delete')

%% Selective deletion of terms
B = terms(A,x,'extract')

%%
% Operations on arrays
sympoly lambda
(rand(3) - lambda*eye(3))

%% Even eigenvalues, using det, then roots
roots(det(hilb(4) - lambda*eye(4)))

%% Sum on any dimension
sum(v,2)

%% And prod
prod(A(:))

%% Orthogonal polynomials from a variety of familes

% 3rd and 4th order Legendre polynomials
p3 = orthpoly(3,'legendre')
p4 = orthpoly(4,'legendre')

%%

% Orthogonal polynomials are orthogonal over the proper domain
defint(p3*p4,'x',[-1,1])

%%

% 2nd and 5th order Jacobi polynomials
p2 = orthpoly(2,'jacobi',2,3)
p5 = orthpoly(5,'jacobi',2,3)

%%

% Orthogonal polynomials are orthogonal over the proper domain.
% Numerical issures left this just eps shy from zero.
defint(p2*p5*(1-x)^2*(1+x)^5,'x',[-1,1])

%% Roots of the derivative of a sympoly
sort(roots(diff(orthpoly(6,'cheby2'))))

%% Error propagation through a sympoly

%  Given a unit Normal N(0,1) random variable, compute the
%  mean and variance of p(x) = 3*x + 2*x^2 - x^3

sympoly x
[polymean, polyvar] = polyerrorprop(3*x + 2*x^2 - x^3,'x',0,1)

%%

% Compute the mean and variance of x*y + 3*y^3, where x and y are
% respectively N(mux,sx^2), and N(muy,sy^2)

sympoly x y mux muy sx sy
[polymean,polyvar] = polyerrorprop(x*y+3*y^3,{'x' 'y'},[mux,muy],[sx,sy])

%% A simple construction for a Newton-Cotes integration rule
% Here I'll generate Simpson's 3/8 rule.
%
% <http://mathworld.wolfram.com/Simpsons38Rule.html |Simpson's 3/8 rule|>
%
M = vander(0:3);
sympoly x f0 f1 f2 f3
% an interpolating polynomial on this set of points
% { (0,f0), (1,f1), (2,f2), (3,f3) }
P_of_x = [x^3, x^2, x, 1]*pinv(M)*[f0;f1;f2;f3];

%% sympoly uses the command window format style to write out the coefficients
% Here, I'll force it to be in rational form
format rat

%%
% integrate the polynomial over its support
defint(P_of_x,'x',[0 3])

%%
% Or here, a 4 point open Newton-Cotes rule
M = vander(1:4);
sympoly x f1 f2 f3 f4
% an interpolating polynomial on this set of points
% { (1,f1), (2,f2), (3,f3) (4,f4) }
P_of_x = [x^3, x^2, x, 1]*pinv(M)*[f1;f2;f3;f4]

%%
% integrate the polynomial over the full domain of the rule
defint(P_of_x,'x',[0 5])


function z = generateSimulatedBouncingPath(iterationNum, roundTimes)
% This function generates the Z-coordinate path for the center of heart.

% by Xin Zhao
% Feb 14, 2008

% define the z path of the center of ball for rountTimes of bouncing along z-axis
if nargin < 2
    roundTimes = 3;
end

if nargin < 1
    iterationNum = 40;
end

radius = 1;
deltaH = 1.5; % the highest point comapred with radius
deltaL = -0.3;% the lowest point comapred with radius

rangeY = [-2, 1];

% gravity accelerator constant
% Note: this is smaller to the real 9.8 value, but this makes the bouncing slower
g = 5;

% define the accelerator for the z < 0
% k is similar to spring coefficient, but it's more complicated than that.
% k just needs to satisfy one condition here, i.e. it will stop at location defined by
% deltaL*radius
k = g * deltaH/(-deltaL);

% start point
startZ = deltaH*radius;

% speed when z =0
V0 = sqrt(2*startZ*g);

% calcualte the total time for rountTimes of bouncing
% time for z > 0
plusZtime = sqrt(2*deltaH*radius/g);
% time for z < 0
minusZtime = sqrt(-2*deltaL*radius/k);

% half period
qPeriod = plusZtime + minusZtime;

% define totalTime
qPeriodTime = linspace(0, qPeriod, iterationNum);

% z path when z > 0
zPlus = startZ - 0.5 * g * qPeriodTime(qPeriodTime<plusZtime).^2;

% z path when z < 0
zMinus = -V0 * (qPeriodTime(qPeriodTime >=plusZtime)-plusZtime) + 0.5 * k* (qPeriodTime(qPeriodTime >=plusZtime)-plusZtime).^2;

z = [zPlus, zMinus, fliplr(zMinus), fliplr(zPlus)];
% the last zPlus is for the stop action
z = [repmat(z, 1, roundTimes), zPlus];
y = linspace(rangeY(1), rangeY(2), numel(z));


function testRansac

% real model coef
k = .5;
b = 10;
ptNum = 200;
outlrRatio = .4;
inlrStd = 5;
pts = genRansacTestPoints(ptNum,outlrRatio,inlrStd,[k b]);
figure,plot(pts(1,:),pts(2,:),'.'),hold on
X = -ptNum/2:ptNum/2;
plot(X,k*X+b,'k')
err0 = sqrError(k,b,pts(:,1:ptNum*(1-outlrRatio)))

% RANSAC
iterNum = 300;
thDist = 2;
thInlrRatio = .1;
[t,r] = ransac(pts,iterNum,thDist,thInlrRatio);
k1 = -tan(t);
b1 = r/cos(t);
plot(X,k1*X+b1,'r')
err1 = sqrError(k1,b1,pts(:,1:ptNum*(1-outlrRatio)))

% least square fitting
coef2 = polyfit(pts(1,:),pts(2,:),1);
k2 = coef2(1);
b2 = coef2(2);
plot(X,k2*X+b2,'g')
err2 = sqrError(k2,b2,pts(:,1:ptNum*(1-outlrRatio)))

end

function err = sqrError(k,b,pts)
%	Calculate the square error of the fit

theta = atan(-k);
n = [cos(theta),-sin(theta)];
pt1 = [0;b];
err = sqrt(sum((n*(pts-repmat(pt1,1,size(pts,2)))).^2));

end


%demo
clc;
clear
a0=10;a1=5;a2=-4;a3=0;a4=-2;a5=0;
b1=-3;b2=15;b3=0;b4=0;b5=0;
w0=2; % a pulse (rd/s) of a signal y
pas=pi/10
t=0:pas:pi-pas; % in this examle a period is T=2pi/w0=2pi/2=pi
y=a0+a1*cos(w0*t)+b1*sin(w0*t)+a2*cos(2*w0*t)+b2*sin(2*w0*t)+a4*cos(4*w0*t);
%note that a wmax=4*w0=8rd/s which means that a sample pulse we must be
%>=2*wmax , we>= 16rd/s, then pas<= 2pi/16 (Shanon theorem)
plot(t,y);
[wc,w0,a0,ak,bk,c0,ck]=get_harmonics(y,pas);
figure;
stem(wc,abs(ck));
xlabel('pulse w(rd/s)');
ylabel('abs(C_k)')
title ('Amplitude spectrum')
[a0 ak(1:5) bk(1:5)]
%check the ak and bk


function [nll,g,H,T] = LogisticLoss(w,X,y)
% w(feature,1)
% X(instance,feature)
% y(instance,1)

[n,p] = size(X);

Xw = X*w;
yXw = y.*Xw;

nll = sum(mylogsumexp([zeros(n,1) -yXw]));

if nargout > 1
    if nargout > 2
        sig = 1./(1+exp(-yXw));
        g = -X.'*(y.*(1-sig));
    else
        %g = -X.'*(y./(1+exp(yXw)));
        g = -(X.'*(y./(1+exp(yXw))));
    end
end

if nargout > 2
    H = X.'*diag(sparse(sig.*(1-sig)))*X;
end

if nargout > 3
    T = zeros(p,p,p);
    for j1 = 1:p
        for j2 = 1:p
            for j3 = 1:p
                T(j1,j2,j3) = sum(y(:).^3.*X(:,j1).*X(:,j2).*X(:,j3).*sig.*(1-sig).*(1-2*sig));
            end
        end
    end
end


function [J, grad] = linearRegCostFunction(X, y, theta, lambda)
%LINEARREGCOSTFUNCTION Compute cost and gradient for regularized linear
%regression with multiple variables
%   [J, grad] = LINEARREGCOSTFUNCTION(X, y, theta, lambda) computes the
%   cost of using theta as the parameter for linear regression to fit the
%   data points in X and y. Returns the cost in J and the gradient in grad

% Initialize some useful values
m = length(y); % number of training examples

% You need to return the following variables correctly
J = 0;
grad = zeros(size(theta));

% ====================== YOUR CODE HERE ======================
% Instructions: Compute the cost and gradient of regularized linear
%               regression for a particular choice of theta.
%
%               You should set J to the cost and grad to the gradient.
%

H = X*theta;
J = sum((H - y).^2) / (2 * m) + lambda*sum(theta(2:end).^2) / (2 * m);

grad = X'*(H - y) / m + lambda*[0;theta(2:end)] / m;

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

grad = grad(:);

end


function variance = normal_truncated_a_variance ( mu, s, a )

%*****************************************************************************80
%
%% NORMAL_TRUNCATED_A_VARIANCE: variance of the lower truncated Normal PDF.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    20 August 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real MU, S, the mean and standard deviation of the
%    parent Normal distribution.
%
%    Input, real A, the lower truncation limit.
%
%    Output, real VARIANCE, the variance of the PDF.
%
  alpha = ( a - mu ) / s;
% beta = Inf;

  alpha_pdf = normal_01_pdf ( alpha );

  alpha_cdf = normal_01_cdf ( alpha );

  variance = s * s * ( 1.0 ...
    + ( alpha * alpha_pdf ) / ( 1.0 - alpha_cdf ) ...
    - ( alpha_pdf / ( 1.0 - alpha_cdf ) ) ^ 2 );

  return
end


% bpExampleScript

ctol = 0.000001;  % convergence tolerance
T = 0.1;       % annealing temperature
maxiter = Inf; % max iter for maxBeliefPropBethe

% factor for P(x1 | x2)
factor2var{1} = [1 2]; % which variables the factor involves
factors{1} = [0.9 0.5 ; ...
              0.1 0.5]; % P(x1=1|x2=1) = 0.9, P(x1=2|x2=1)=0.1
% factor for P(x2 | x3)
factor2var{2} = [2 3];
factors{2} = [0.25 0.01 ; ...
              0.75 0.99];
% factor for P(x3)
factor2var{3} = [3];
factors{3} = [0.25 ; ...
              0.75];  % P(x1=1)=0.25, P(x1=2)=0.75

nvals = [2 ; 2 ; 2]; % number of states for each node (variable)

[vals_max, bel_max] = maxBeliefPropBethe(factors, factor2var, nvals, ctol, T, maxiter);
bel_max = reshape(cell2mat(bel_max), [nvals(1) numel(nvals)])';

bel_marg = marginalBeliefPropBethe(factors, factor2var, nvals, ctol);
bel_marg = reshape(cell2mat(bel_marg), [nvals(1) numel(nvals)])';

% marginal answer should be:
%   P(x3=1) = 0.25;
%   P(x2=1) = (0.25)*P(x3=1) + (0.01)*P(x3=2) =  0.07
%   P(x1=1) = (0.9)*P(x2=1) + 0.5*P(x2=2) = 0.528
bel_marg

% max solution should be:
%   x1 = 2;
%   x2 = 2;
%   x3 = 1 or 2; (equally likely)
bel_max


%% Parzen Probabilistic Neural Networks
%  The Parzen Probabilistic Neural Networks (PPNN) are a simple type of
% neural network used to classify data vectors. This classifiers are based
% on the Bayesian theory where the a posteriori probability density
% function (apo-pdf) is estimated from data using the Parzen window
% technique.

%% A brief overview on the theory of the Parzen window and PPNN
%  The Bayesian classifiers use the Bayesian equation:
%
%                 P(x|wi)P(wi)
%  P(wi|x) = ----------------------
%             SUM_j P(x|wj)P(wj)
%
% to estimate the apo-pdf P(wi|x). Obviously to be usefull, this method
% needs the probabilities P(x|wi) and P(wi) to be known. A technique is to
% parametrize this pdfs, another is to estimate them from data.
%  The Parzen window technique estimates the probability defining a window
% (given the winow size) and a function on this window (i.e. an hypersphere
% with the gaussian function truncated inside). The computes the estimation
% of the probability function convolving the window function with the
% samples function. This obviously requires that the window function must
% have the integral (the hypervolume under the funciton) equal to 1 to
% mantain the scale in the estimated pdf.
%  The PPNN is a simple tool that is the composition of the pdf estimation
% with the Parzen window and the Bayesian classification selecting for a
% feature vector x the class wi where P(wi|x) is maximum.
%  In this quick explanation the particular derivations aren't reported but
% can be found in [1].
%
%  A PPNN is a two layer neural network (NN) where the input data are fully
% connected with the first neuron layer and the first layer is sparsely
% connected with the second (and ouput) layer. The output layer is composed
% of c neurons where c is the number of classes of the classifier.
% The wheights on the first layer are trained as follows: each sample data
% is normalized so that its length becames unitary, each sample data
% becames a neuron with the normalized values as weights w. The input data
% x is so dot-multiplied by the weights obtaining the network activation
% signal net=w^Tx. Then the exponential nonlinearity:
%
%          net - 1
%         ---------
%               2
%           sigm
%  act = e
%
% is computed to obtain the synaptic activation signals. During the
% learning process each first layer neuron is connected to the output layer
% neuron related to its class with wheight 1. During the classification
% process the output neuron of each class sums the activation signals from
% all the neurons of the neurons of the first layer. Simply the highest
% output value selects the class of the input data.
%
%  (w1)  (w2)  ...        OUTPUT
%    \     \ \__
%     |     |    \
%    ( )   ( )   ( )      internal layer
%    /|\   /|\   /|\
%                         INPUT
%
% [1] "Pattern Classification", second edition,
%     by Richard O. Duda, Peter E. Hart. and David G. Stork

%% A first simple example with 2D data
% In this simple example three set of points in the plane are selected in
% the region [1:100;1:100]. A PPNN is trained with this samples and then
% an image of the classification regions is produced.

% A training set for the class 'a' and 'b':
img=ones(100);
f=figure; imshow(img); [X,Y]=getpts; sa=[X,Y]'; close(f);
f=figure; imshow(img); [X,Y]=getpts; sb=[X,Y]'; close(f);
f=figure; imshow(img); [X,Y]=getpts; sc=[X,Y]'; close(f);
% The samples matrix:
S = [sa,sb,sc];
% The classification vector:
C = [repmat('a',[1,size(sa,2)]),repmat('b',[1,size(sb,2)]),repmat('c',[1,size(sc,2)])];
% Generating the network:
net = parzenPNNlearn(S,C);

% Generating the whole grid:
[X,Y] = meshgrid(1:100,1:100);
D = [X(:),Y(:)]';
% Classification of all points:
class = parzenPNNclassify(net,D);
class = reshape(class,[100,100]);
% Plotting:
sep = double(class=='a') + 2*double(class=='c');
figure; imshow(sep/2); hold on;
plot(sa(1,:),sa(2,:),'r.');
plot(sb(1,:),sb(2,:),'g.');
plot(sc(1,:),sc(2,:),'b.');

%% Adding samples to the network to increase the training
%  A PPNN can be simply improved adding new samples to it, the new samples
% generates new neurons in the internal layer that so can grow. Here an
% example of improving of the generated neural network.

% Getting new samples:
f=figure; imshow(img); hold on; plot(sa(1,:),sa(2,:),'r.');
[X,Y]=getpts; nsa=[X,Y]'; close(f);
f=figure; imshow(img); hold on; plot(sb(1,:),sb(2,:),'g.');
[X,Y]=getpts; nsb=[X,Y]'; close(f);
f=figure; imshow(img); hold on; plot(sc(1,:),sc(2,:),'b.');
[X,Y]=getpts; nsc=[X,Y]'; close(f);
Sa = [sa,nsa];
Sb = [sb,nsb];
Sc = [sc,nsc];

% The samples matrix:
nS = [nsa,nsb,nsc];
% The classification vector:
nC = [repmat('a',[1,size(nsa,2)]),repmat('b',[1,size(nsb,2)]),repmat('c',[1,size(nsc,2)])];
% Improving the network:
net = parzenPNNimprove(net,nS,nC);

% Classification of all points:
class = parzenPNNclassify(net,D);
class = reshape(class,[100,100]);
% Plotting:
sep = double(class=='a') + 2*double(class=='c');
figure; imshow(sep/2); hold on;
plot(Sa(1,:),Sa(2,:),'r.');
plot(Sb(1,:),Sb(2,:),'g.');
plot(Sc(1,:),Sc(2,:),'b.');


function [EC,ec,degij] = edge_nei_overlap_bd(CIJ)
% EDGE_NEI_OVERLAP_BD     Overlap amongst neighbors of two adjacent nodes
%
%   [EC,ec,degij] = edge_nei_bd(CIJ);
%
%   This function determines the neighbors of two nodes that are linked by
%   an edge, and then computes their overlap.  Connection matrix must be
%   binary and directed.  Entries of 'EC' that are 'inf' indicate that no
%   edge is present.  Entries of 'EC' that are 0 denote "local bridges",
%   i.e. edges that link completely non-overlapping neighborhoods.  Low
%   values of EC indicate edges that are "weak ties".
%
%   If CIJ is weighted, the weights are ignored. Neighbors of a node can be
%   linked by incoming, outgoing, or reciprocal connections.
%
%   Inputs:     CIJ,      directed (binary/weighted) connection matrix
%
%   Outputs:    EC,     edge neighborhood overlap matrix
%               ec,     edge neighborhood overlap per edge, in vector format
%               degij,  degrees of node pairs connected by each edge
%
%   Reference:
%
%       Easley and Kleinberg (2010) Networks, Crowds, and Markets.
%           Cambridge University Press, Chapter 3
%
%   Olaf Sporns, Indiana University, 2012

[ik,jk,ck] = find(CIJ);
lel = length(ck);
N = size(CIJ,1);

[~,~,deg] = degrees_dir(CIJ);

ec = zeros(1,lel);
degij = zeros(2,lel);
for e=1:lel
    neiik = setdiff(union(find(CIJ(ik(e),:)),find(CIJ(:,ik(e))')),[ik(e) jk(e)]);
    neijk = setdiff(union(find(CIJ(jk(e),:)),find(CIJ(:,jk(e))')),[ik(e) jk(e)]);
    ec(e) = length(intersect(neiik,neijk))/length(union(neiik,neijk));
    degij(:,e) = [deg(ik(e)) deg(jk(e))];
end;

ff = find(CIJ);
EC = 1./zeros(N);
EC(ff) = ec;                            %#ok<FNDSB>


function geometry_test0023 ( )

%*****************************************************************************80
%
%% TEST0023 tests ANGLE_HALF_2D;
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 December 2010
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST0023\n' );
  fprintf ( 1, '  ANGLE_HALF_2D computes the half angle between two rays;\n' );
  fprintf ( 1, '  The angle is defined by the points (P1,P2,P3)\n' );
  fprintf ( 1, '  or by the rays P2-->P3, P2-->P1.\n' );

  p2(1:2,1) = [ 5.0; 3.0 ];

  angle_deg = 75.0;
  r = 3.0;
  p1(1,1) = p2(1,1) + r * cos_deg ( angle_deg );
  p1(2,1) = p2(2,1) + r * sin_deg ( angle_deg );

  angle_deg = 15.0;
  r = 2.0;
  p3(1,1) = p2(1,1) + r * cos_deg ( angle_deg );
  p3(2,1) = p2(2,1) + r * sin_deg ( angle_deg );

  r8vec_print ( 2, p1, '  Point P1:' );
  r8vec_print ( 2, p2, '  Point P2:' );
  r8vec_print ( 2, p3, '  Point P3:' );

  p4 = angle_half_2d ( p1, p2, p3 );

  r8vec_print ( 2, p4, ...
    '  End point of unit ray from P2, defining half angle, P4:' );

  angle_deg = 45.0;
  r = 1.0;
  p4(1,1) = p2(1,1) + r * cos_deg ( angle_deg );
  p4(2,1) = p2(2,1) + r * sin_deg ( angle_deg );

  r8vec_print ( 2, p4, '  Expected value of P4:' );

  return
end


function test_example_effects_of_tapering

% MEM 4gb
% WALLTIME 00:10:00

%
%% Effects of tapering for power estimates
%
% A simple way of looking at how (multi-)tapering affects the estimate of power in your signal is by using a very simple simulated signal. The **[ft_freqsimulation](https://github.com/fieldtrip/fieldtrip/blob/release/ft_freqsimulation.m)** function allows you to quickly create a simulated signal with a well-defined frequency component in it. Subsequently you can use **[ft_freqanalysis ](https://github.com/fieldtrip/fieldtrip/blob/release/ft_freqanalysis.m)** with different taper settings to see the effect of tapering on your power estimate.
%
% Create and plot a simulated signal. The simulated data contains only one trial, with a length of one second and a 50Hz sine wave.
%
close all

cfg = [];
cfg.method  = 'superimposed';
cfg.fsample = 1000;
cfg.numtrl  = 1;
cfg.trllen  = 1;
cfg.s1.freq = 50;
cfg.s1.ampl = 1;
cfg.s1.phase = 0;
cfg.noise.ampl = 0;
data = ft_freqsimulation(cfg);
figure
plot(data.time{1}, data.trial{1}(1,:))

%
% Compare the power estimate using a single Hanning taper with a single dpss taper (cfg.taper).
%
cfg        = [];
cfg.method = 'mtmfft';
cfg.output = 'pow';
cfg.pad    = 'maxperlen';
cfg.foilim = [0 100];
cfg.taper  = 'hanning';
freq       = ft_freqanalysis(cfg, data);
figure
semilogy(freq.freq, freq.powspctrm(1,:), 'b-');

cfg.taper     = 'dpss';
cfg.tapsmofrq = 1;   % i.e. no real smoothing
freq          = ft_freqanalysis(cfg, data);
hold on
semilogy(freq.freq, freq.powspctrm(1,:), 'g-');
legend({'hanning', 'dpss'});

%
% Look at the effect of multitapering with various amounts of smoothing (cfg.tapsmofrq).
%
cfg           = [];
cfg.method    = 'mtmfft';
cfg.output    = 'pow';
cfg.pad       = 'maxperlen';
cfg.foilim    = [0 100];
cfg.taper     = 'dpss';
cfg.tapsmofrq = 1;
freq          = ft_freqanalysis(cfg, data);
figure
semilogy(freq.freq, freq.powspctrm(1,:), 'b-');

cfg.tapsmofrq = 5;
freq          = ft_freqanalysis(cfg, data);
hold on
semilogy(freq.freq, freq.powspctrm(1,:), 'g-');

cfg.tapsmofrq = 10;
freq          = ft_freqanalysis(cfg, data);
hold on
semilogy(freq.freq, freq.powspctrm(1,:), 'r-');

legend({'1 Hz', '5 Hz', '10 Hz'});

%
% Look at the effect of spectral leakage of frequencies that are in between the natural frequencies of your time segment (cfg.pad). Note that the power spectral density per sqrt(Hz) decreases due to the zero-padding (compare the green and the blue). Multiplying the time series with a scaling factor fixes this, and makes the power spectral density estimates easier to compare (red and blue).
%
cfg           = [];
cfg.method    = 'mtmfft';
cfg.output    = 'pow';
cfg.foilim    = [0 100];
cfg.taper     = 'dpss';
cfg.tapsmofrq = 2;
cfg.pad       = 1;  % this is the same as the actual length of the data segment
freq          = ft_freqanalysis(cfg, data);
figure
semilogy(freq.freq, freq.powspctrm(1,:), 'b.-');

cfg.pad       = 100;
freq          = ft_freqanalysis(cfg, data);
hold on
semilogy(freq.freq, freq.powspctrm(1,:), 'g-');

data.trial{1} = data.trial{1}*10;           % equate the power spectral density to the first one
freq          = ft_freqanalysis(cfg, data);
hold on
semilogy(freq.freq, freq.powspctrm(1,:), 'r-');

legend({'1s', '5s', '10s'});


function gx = p01_gx ( x )

%*****************************************************************************80
%
%% P01_GX evaluates the underlying function for problem 1.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    02 September 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real X(2), the point at which the function is to
%    be evaluated.
%
%    Output, real GX(2), the value of the function at X.
%
  gx(1) = x(1) - ( ( x(2) - 5.0 ) * x(2) + 2.0 ) * x(2) - 13.0;
  gx(2) = x(1) + ( ( x(2) + 1.0 ) * x(2) - 14.0 ) * x(2) - 29.0;

  return
end


function [ cc_est, r_min, r_max ] = cube3d_grid_centralize ( ng, oc )

%*****************************************************************************80
%
%% CUBE3D_GRID_CENTRALIZE centralizes grid data from the surface of a 3D cube.
%
%  Discussion:
%
%    We generate a hypersphere grid of 1D index NG, with origin at OC,
%    and project these points onto the 3D cube of center [0,0,0]
%    and radius 1.
%
%    The cube is aligned with the coordinate axes.
%
%    We seek to estimate the value of the center.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    20 May 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer NG, the grid index.  The hypersphere grid will have
%    order N = (2*NG+1) * (NG+1)^(M-2).
%
%    Input, real OC(M,1), the observation point, the original of the
%    hypersphere coordinate system.  OC should be inside the cube.
%
%    Output, real CC_EST(M,1), the estimated cube center.
%
%    Output, real R_MIN, R_MAX, the minimum and maximum distances
%    between the observation point and sample points on the cube surface.
%
  m = 3;
  n = ( 2 * ng + 1 ) * ( ng + 1 ) ^ ( m - 2 );
%
%  Destroy all row vectors!
%
  oc = oc(:);
%
%  Compute sample points on the cube surface.
%
  [ x1, x2, x3 ] = cube3d_grid ( ng, oc );
%
%  "Flatten" the data into vectors.
%
  x1 = reshape ( x1, n, 1 );
  x2 = reshape ( x2, n, 1 );
  x3 = reshape ( x3, n, 1 );
%
%  The center estimate is simply the average.
%
  cc_est = zeros ( 3, 1 );
  cc_est(1,1) = sum ( x1 ) / n;
  cc_est(2,1) = sum ( x2 ) / n;
  cc_est(3,1) = sum ( x3 ) / n;
%
%  For each point on the cube surface, the "radius" ROC is the norm of X - OC.
%
  roc = [ x1, x2, x3 ]' - repmat ( oc, 1, n );
  roc = roc.^2;
  roc = sum ( roc, 1 );
  roc = sqrt ( roc );
%
%  Return the minimum and maximum radiuses.
%
  r_min = min ( roc );
  r_max = max ( roc );

  return
end


function result = is_orthogonal_matrix(P)
%
% Orthogonal Matrices
%
% is_orthogonal_matrix(P) determines if the matrix P is an orthogonal
% matrix. An error is returned if a matrix that is not square is attempted
% to be determined for orthogonality.
%
%  Function written by Anthony Russo, downloaded from MatlabCentral.
%

matrix_size = size(P);

m = matrix_size(1,1);
n = matrix_size(1,2);

tolerance = 10^-10;

if m ~= n
    error('Only square matrices can be orthogonal.');
else
    count = 0;

    identity_matrix = P*P';

    if det(P) ~= 0
        for i = 1:m
            if abs(identity_matrix(i,i) - 1) <= tolerance
                count = count + 1;
            else
                break
            end
        end
    end

    if count == m
        result = 1;
    else
        result = 0;
    end
end


%% Demo of *plot_littlewood_paley_1d*

%% Usage
% littlewood = *plot_littlewood_paley_1d*(filters) (see
% <matlab:doc('plot_littlewood_paley_1d') plot_littlewood_paley_1d>).
%
%% Description
% *plot_littlewood_paley* computes, at every frequency, the
% Littlewood-Paley sum of a filter bank, i.e. the total power spectral
% density
% \sum_{j, \theta} |\hat{\psi_j} (\omega)|^2 + |\hat{\phi_J}(\omega)|^2
% If this sum is between $(1-epsilon)$ and $1$ for small $epsilon,
% the associated wavelet transform is proved to be contractive and
% almost unitary.

% In this demo, we display the Littlewood-Paley sum of a dyadic Morlet
% wavelet filter bank, with a very low averaging size of 8 samples. The
% Littlewood-Paley sum is shown in red, while the lowpass filter phi and
% the bandpass filters psi are respectively shown in green and blue.

figure;
T = 2^3;
interpolation = 2^10;
filt_opt.Q = 1;
filt_opt.J = T_to_J(T,filt_opt);
dyadic_filters = morlet_filter_bank_1d(T*interpolation,filt_opt);

plot_littlewood_paley_1d(dyadic_filters);
title('Q = 1 ; T = 8 samples (interpolated)');

% A more realistic example is constructed with an averaging size of 4096
% samples and a quality factor of 8. These values are typical in audio
% signal processing. The lowpass filter has such a narrow bandwidth that it
% is almost not visible in this second plot.

figure;
T = 2^12;
filt_opt.Q = 8;
filt_opt.J = T_to_J(T,filt_opt);
audio_filters = morlet_filter_bank_1d(T,filt_opt);

plot_littlewood_paley_1d(audio_filters);
title('Q = 8 ; T = 4096 samples');


function [ fea, out ] = ex_heattransfer7( varargin )
%EX_HEATTRANSFER7 1D Transient heat diffusion with analytic solution.
%
%   [ FEA, OUT ] = EX_HEATTRANSFER7( VARARGIN ) Transient heat
%   diffusion problem with analytic solution. A 1 m rod is kept at
%   fixed temperature on one end and constant outward heat flux at the
%   other end as in the following illustration.
%
%              +---------- L=1m ----------+ T = 25
%            q_n = 1       T(t=0) = 25
%
%   Accepts the following property/value pairs.
%
%       Input       Value/{Default}        Description
%       -----------------------------------------------------------------------------------
%       hmax        scalar {0.1}           Grid cell size
%       sfun        string {sflag1}        Finite element shape function
%       solver      string fenics/{}       Use FEniCS or default solver
%       ischeme     scalar {2}/1/3         Time stepping scheme
%       tmax        scalar {0.2}           Maximum time
%       tstep       scalar {0.01}          Time step size
%       iplot       scalar {1}/0           Plot solution (=1)
%                                                                                .
%       Output      Value/(Size)           Description
%       -----------------------------------------------------------------------------------
%       fea         struct                 Problem definition struct
%       out         struct                 Output struct
%
%   See also EX_HEATTRANSFER8.

% Copyright 2013-2022 Precise Simulation, Ltd.

cOptDef = { 'hmax',     0.1;
            'sfun',     'sflag1';
            'solver',   '';
            'ischeme',  2;
            'tmax',     0.2;
            'tstep',    0.01;
            'nstbwe',   0;
            'iplot',    1;
            'tol',      1e-3;
            'fid',      1 };
[got,opt] = parseopt(cOptDef,varargin{:});

% Grid generation.
fea.grid = linegrid( round(1/opt.hmax), 0, 1 );

% Problem definition.
fea.sdim  = { 'x' };                      % Space coordinate name.
fea = addphys( fea, @heattransfer );      % Add heat transfer physics mode.
fea.phys.ht.sfun = { opt.sfun };          % Set shape function.

% Equation coefficients.
fea.phys.ht.eqn.coef{1,end} = 1;          % Density.
fea.phys.ht.eqn.coef{2,end} = 1;          % Heat capacity.
fea.phys.ht.eqn.coef{3,end} = 1;          % Thermal conductivity.
fea.phys.ht.eqn.coef{6,end} = { 25 };     % Initial temperature.

% Boundary conditions.
fea.phys.ht.bdr.sel = [ 4 1 ];
fea.phys.ht.bdr.coef{1,end} = { [] 25 };
fea.phys.ht.bdr.coef{4,end}{1}{1} = -1;

% Parse physics modes and problem struct.
fea = parsephys(fea);
fea = parseprob(fea);

% Compute solution.
if( strcmp(opt.solver,'fenics') )
  fea = fenics( fea, 'fid', opt.fid, ...
                'tstep', opt.tstep, 'tmax', opt.tmax, 'ischeme', opt.ischeme );
  tlist = fea.sol.t;
else
  [fea.sol.u, tlist] = solvetime( fea, 'fid', opt.fid, 'init', {'T0_ht'}, 'ischeme', opt.ischeme, ...
                                  'tmax', opt.tmax, 'tstep', opt.tstep, 'nstbwe', opt.nstbwe );
end

% Postprocessing.
T_ref = refsol( fea.grid.p', tlist(end) );
if( opt.iplot>0 )
  postplot( fea, 'surfexpr', 'T', 'axequal', 0 )
  title(['Temperature at t=',num2str(tlist(end))])
  xlabel('x')
  ylabel('T')

  hold on
  plot( fea.grid.p, T_ref, 'r--' )
end

% Error checking.
T_sol = evalexpr( 'T', fea.grid.p, fea );
out.err  = norm( abs(T_sol-T_ref)/T_ref );
out.pass = out.err<opt.tol;

if( nargout==0 )
  clear fea out
end

% -----------------------------------
function [ u ] = refsol( x, t, dtol )

if( nargin<3 )
  dtol = 1e-7;
end

u0  = x + 24;
bdo = true;
n   = 0;
while( bdo )

  n   = n + 1;
  u   = u0 + 8/(1-2*n)^2/pi^2*cos((n-1/2)*pi*x)*exp(-((n-1/2)^2*pi^2)*t);
  bdo = any( max( u - u0 ) > dtol );
  u0  = u;

  if( n>1e3 )
    warning( ['Reference solution did not converge to tolerance ',num2str(dtol)] )
    break
  end
end


function [Ht,weights] = riskmetrics2006(data,tau0,tau1,kmax,rho)
% Computes the Riskmetrics 2006 covariance, which is a weighted average of
% EWMA covariances
%
% USAGE:
%  [HT,WEIGHTS] = riskmetrics2006(DATA,TAU0,TAU1,KMAX,RHO)
%
% INPUTS:
%   DATA     - A T by K matrix of zero mean residuals -OR-
%                K by K by T array of covariance estimators (e.g. realized covariance)
%   TAU0     - [OPTIONAL] Half-life of slowest EWMA
%   TAU1     - [OPTIONAL] Half-life of fastest EWMA
%   KMAX     - [OPTIONAL] Number of EWMA components to use
%   RHO      - [OPTIONAL] Decay factor to use in half-lives.  The
%                half-lives used are TAU1, TAU1*RHO, TAU1*RHO^2, ...
%
% OUTPUTS:
%   HT       - A [K K T] dimension matrix of conditional covariances
%   WEIGHTS  - A T by T matrix which contains the final weights used
%                computing all conditional covariances.  WEIGHT(i,j)
%                contains the weight of the outer-product in time period j
%                in the covariance forecast at period i+1
%
% COMMENTS:
%   The conditional variance, H(t), of a RM2006 covariance model
%
%      H(t) = w(i)*Htilde(t,i)
%
%   where Htilde(t,i) is an EWMA covariance, i=1,2,..., and
%
%   w(i) = 1-log(TAU1^((i-1)*RHO))/log(TAU0)
%
%   where the weights have been normalized so that they sum to 1.  All
%   EWMAs are initialized using a backward EWMA with the same decay.
%
% EXAMPLES:
%   RiskMetrics 2006 methodology using the suggested reference values
%     tau0   = 1560;
%     tau1   = 4;
%     taumax = 512;
%     rho    = sqrt(2);
%     kmax   = round(log(taumax/tau1)/log(rho)); % 14
%     Ht     = riskmetrics2006(data,tau0,tau1,kmax,rho)
%
%   RiskMetrics 1994 methodology using .94 as a special case of RM2006
%     tau0 = 1560;         % Does not matter
%     rho  = 1;            % Does not matter
%     tau1 = -1/log(.94);
%     kmax = 1;
%     Ht = riskmetrics2006(data,tau0,tau1,kmax,rho)

% Copyright: Kevin Sheppard
% kevin.sheppard@economics.ox.ac.uk
% Revision: 3    Date: 03/10/2011

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Input Checking
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
switch nargin
    case 1
        tau0=[];
        tau1=[];
        kmax=[];
        rho =[];
    case 2
        tau1=[];
        kmax=[];
        rho =[];
    case 3
        kmax=[];
        rho =[];
    case 4
        rho =[];
    case 5
        % Nothing
    otherwise
        error('1 to 5 inputs required.')
end

if isempty(tau0)
    tau0 = 1560;
end
if isempty(tau1)
    tau1 = 4;
end
if isempty(kmax)
    kmax = 14;
end
if isempty(rho)
    rho = sqrt(2);
end

if tau1*rho^(kmax-1)>tau0
    error('The inputs must satisfy: TAU1*RHO^(KMAX-1)<TAU0')
end
if tau1<0
    error('TAU1 must be positive')
end
if tau0<0
    error('TAU0 must be positive')
end
if kmax<1 || floor(kmax)~=kmax
    error('KMAX must be an integer (weakly) larger than 1.')
end
if rho<0
    error('RHO must be positive')
end

if ndims(data)==2
    [T,K] = size(data);
    temp = zeros(K,K,T);
    for t=1:T
        temp(:,:,t) = data(t,:)'*data(t,:);
    end
    data = temp;
else
    K = size(data,1);
    T = size(data,3);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Input Checking
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
tauks = tau1*rho.^((1:kmax)-1);
w= 1-log(tauks)/log(tau0);
w=w/sum(w);
Ht = zeros(K,K,T);
Httilde = zeros(K,K,T);

for k=1:kmax
    tauk = tauks(k);
    mu = exp(-1/tauk);
    % back casting
    endPoint = max(min(floor(log(.01)/log(mu)),T),k);
    weights = (1-mu).*mu.^(0:endPoint-1);
    weights = weights/sum(weights);
    backCast = zeros(K);
    for i=1:endPoint
        backCast = backCast + weights(i)*data(:,:,i);
    end
    Httilde(:,:,1) = backCast;

    for t=2:T
        Httilde(:,:,t) = mu*Httilde(:,:,t-1) + (1-mu)*data(:,:,t-1);
    end
    Ht = Ht + w(k) * Httilde;
end

if nargout>1
    weights = zeros(T,T);
    for k=1:kmax
        tauk = tauks(k);
        mu = exp(-1/tauk);
        weightMatrix = [mu.^(0:T-1)' zeros(T,T-1)];
        weightMatrix(T,T) = (1-mu);
        for j=1:(T-2);
            weightMatrix(T,T-j) = mu * weightMatrix(T,T-j+1);
        end
        for t=2:T-1
            weightMatrix(t,2:t) = weightMatrix(T,T+(-t+2:0));
        end
        weights = weights + w(k) * weightMatrix;
    end
end


% Reduce polygon to a given number of vertices
%
% poly = reduce_poly(poly, num)
%
% Inputs: poly        Polygon (2 rows, n columns)
%         num         Required number of vertices
%
% Outputs: poly       Final polygon
%
% Description: This code reduces the number of vertices in a closed polygon
% to the number specified by 'num'. It does this by calculating the
% importance of each vertex based on angle and segment length and then
% removing the least important. The process is repeated until the desired
% number of vertices is reached.
%
% Example:
% t = 0:0.1:2*pi;
% poly1 = [sin(t); cos(t)];
% poly2 = reduce_poly(poly1, 21);
% poly_draw = [poly2 poly2(:,1)];
% plot(poly_draw(1,:), poly_draw(2,:), '.-')
% axis equal
%
% Coded by: Peter Bone (peterbone@hotmail.com)
%------------------------------------------------------------------------
function poly = reduce_poly(poly, num)

numv = length(poly);

% Calculate initial importance of each vertex
imp = zeros(1,numv);
for v = 1 : numv
    imp(v) = vertex_importance(v, poly, numv);
end

% Iterate until desired number of vertices is reached
while numv > num

    [~, i] = min(imp(1:numv));

    % Remove vertex with least importance
    if i < numv
        poly(:,i:numv-1) = poly(:,i+1:numv);
        imp(i:numv-1) = imp(i+1:numv);
        vp = i;
    else
        vp = 1;
    end
    numv = numv - 1;

    % Recalculate importance for vertices neighbouring the removed one
    vm = 1 + mod(i - 2, numv);
    imp(vp) = vertex_importance(vp, poly, numv);
    imp(vm) = vertex_importance(vm, poly, numv);

end

% Clip polygon to the final length
poly = poly(:,1:num);

function a = vertex_importance(v, poly, numv)

% Find adjacent vertices
vp = 1 + mod(v, numv);
vm = 1 + mod(v - 2, numv);

% Obtain adjacent line segments and their lengths
dir1 = poly(:,v) - poly(:,vm);
dir2 = poly(:,vp) - poly(:,v);
len1 = norm(dir1);
len2 = norm(dir2);

% Calculate angle between vectors and multiply by segment lengths
% This is the importance of the vertex.
% Vertices with large angle and large segments attached are less
% likely to be removed
len1len2 = len1 * len2;
a = abs(acos((dir1' * dir2) / len1len2)) * len1len2;
%a = abs(1 - ((dir1' * dir2) / len1len2)) * len1len2;


% book : Signals and Systems Laboratory with MATLAB
% authors : Alex Palamides & Anastasia Veloni
%
%
%
%
% problem 2- Evaluate the Laplace Transform of  y''(t) and then replace y(t) by sin(t)u(t)

sym 'y(t)' ;
syms t s
z=laplace( diff('y(t)',2),s)

z=subs(z,'y(t)',sin(t))

z=subs(z,'y(0)',0)
z=subs(z,'D(y)(0)',1)
simplify(z)

%verification
x=sin(t);
x2=diff(x,2,t)
laplace(x2,s)


function y = pow_p( x, p )

%POW_P   Positive branch of the power function.
%   POW_P(X,P) computes a convex or concave branch of the power function:
%           P < 0: POW_P(X,P) = X.^P if X >  0, +Inf otherwise
%      0 <= P < 1: POW_P(X,P) = X.^P if X >= 0, -Inf otherwise
%      1 <= P    : POW_P(X,P) = X.^P if X >= 0, +Inf otherwise
%   Both P and X must be real.
%
%   Disciplined convex programming information:
%       The geometry of POW_P(X,P) depends on the precise value of P,
%       which must be a real constant:
%                P < 0: convex  and nonincreasing; X must be concave.
%           0 <= P < 1: concave and nondecreasing; X must be concave.
%           1 <= P    : convex  and nonmonotonic;  X must be affine.
%       In all cases, X must be real.

y = power( pdom( x ), p );

% Copyright 2005-2014 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function  [mls,row,col] = mls(n)

%[mls,row,col] = mls(n);
%
%Generates a Maximum Length Sequence of n bits by utilizing a
%linear feedback shift register with an XOR gate on the tap bits
%Also given are the permutation vector row and col, used by prior and after
%the autocorreltion calculation via FHT.
%
%Function can accept bit lengths of between 2 and 24
%
%y is a vector of 1's & -1's that is (2^n)-1 in length.
%
%reference:
%	Davies, W.D.T. (June, July, August, 1966). Generation and
%properties of maximum-length sequences. Control, 302-4, 364-5,431-3.
%
%Spring 2001, Christopher Brown, cbrown@phi.luc.edu

switch n							%assign taps which will yeild a maximum
case 2								%length sequence for a given bit length
   taps=2;							%I forget the reference I used, but theres
   tap1=1;							%a list of appropriate tap values in
   tap2=2;							%Vanderkooy, JAES, 42(4), 1994.
case 3
   taps=2;
   tap1=1;
   tap2=3;
case 4
   taps=2;
   tap1=1;
   tap2=4;
case 5
   taps=2;
   tap1=2;
   tap2=5;
case 6
   taps=2;
   tap1=1;
   tap2=6;
case 7
   taps=2;
   tap1=1;
   tap2=7;
case 8
   taps=4;
   tap1=1;
   tap2=5;
   tap3=6;
   tap4=8;
case 9
   taps=2;
   tap1=4;
   tap2=9;
case 10
   taps=2;
   tap1=3;
   tap2=10;
case 11
   taps=2;
   tap1=2;
   tap2=11;
case 12
   taps=4;
   tap1=3;
   tap2=4;
   tap3=7;
   tap4=12;
case 13
   taps=4;
   tap1=1;
   tap2=3;
   tap3=4;
   tap4=13;
case 14
   taps=4;
   tap1=1;
   tap2=11;
   tap3=12;
   tap4=14;
case 15
   taps=2;
   tap1=1;
   tap2=15;
case 16
   taps=4;
   tap1=2;
   tap2=3;
   tap3=5;
   tap4=16;
case 17
   taps=2;
   tap1=3;
   tap2=17;
case 18
   taps=2;
   tap1=7;
   tap2=18;
case 19
   taps=4;
   tap1=1;
   tap2=5;
   tap3=6;
   tap4=19;
case 20
   taps=2;
   tap1=3;
   tap2=20;
case 21
   taps=2;
   tap1=2;
   tap2=21;
case 22
   taps=2;
   tap1=1;
   tap2=22;
case 23
   taps=2;
   tap1=5;
   tap2=23;
case 24
   taps=4;
   tap1=1;
   tap2=3;
   tap3=4;
   tap4=24;
case 25
  taps=2;
  tap1=3;
  tap2=25;
case 26
  taps=4;
  tap1=1;
  tap2=7;
  tap3=8;
  tap4=26;
case 27
  taps=4;
  tap1=1;
  tap2=7;
  tap3=8;
  tap4=27;
case 28
  taps=2;
  tap1=3;
  tap2=28;
case 29
  taps=2;
  tap1=2;
  tap2=29;
case 30
  taps=4;
  tap1=1;
  tap2=15;
  tap3=16;
  tap4=30;
case 31
  taps=2;
  tap1=3;
  tap2=31;
case 32
  taps=4;
  tap1=1;
  tap2=27;
  tap3=28;
  tap4=32;
otherwise
   disp(' ');
   error('input bits must be between 2 and 32');
end

if taps == 2
    [mls,row,col]=mls2tap(tap2,tap1,tap2);
elseif taps == 4
    [mls,row,col]=mls4tap(tap4,tap1,tap2,tap3,tap4);
end


function idx = findClosestCentroids(X, centroids)
%FINDCLOSESTCENTROIDS computes the centroid memberships for every example
%   idx = FINDCLOSESTCENTROIDS (X, centroids) returns the closest centroids
%   in idx for a dataset X where each row is a single example. idx = m x 1
%   vector of centroid assignments (i.e. each entry in range [1..K])
%

% Set K
K = size(centroids, 1);

% You need to return the following variables correctly.
idx = zeros(size(X,1), 1);

% ====================== YOUR CODE HERE ======================
% Instructions: Go over every example, find its closest centroid, and store
%               the index inside idx at the appropriate location.
%               Concretely, idx(i) should contain the index of the centroid
%               closest to example i. Hence, it should be a value in the
%               range 1..K
%
% Note: You can use a for-loop over the examples to compute this.
%

for i = 1:length(idx)
    distance = zeros(K, 1);
    for j = 1:K
        % TODO(SaveTheRbtz@): Can be vectorized as diff * diff'
        distance(j) = sum(sum((X(i, :) - centroids(j, :)) .^ 2 ));
    endfor
    [value, idx(i)] = min(distance);
endfor

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

end


function geometry_test0846 ()

%*****************************************************************************80
%
%% TEST0846 tests POLYLOOP_POINTS_ND.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    19 March 2009
%
%  Author:
%
%    John Burkardt
%
  dim_num = 2;
  nk = 4;
  nt = 12;

  pk = [ ...
    0.0, 2.0; ...
    0.0, 0.0; ...
    1.0, 0.0; ...
    1.0, 2.0]';

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST0846\n' );
  fprintf ( 1, '  POLYLOOP_POINTS_ND computes points on a polyloop.\n' );

  r8mat_transpose_print ( dim_num, nk, pk, '  The defining points:' );

  pt = polyloop_points_nd ( dim_num, nk, pk, nt );

  r8mat_transpose_print ( dim_num, nt, pt, '  The computed points:' );

  return
end


function value = fibonacci2_determinant ( n )

%*****************************************************************************80
%
%% FIBONACCI2_CONDITION returns the L1 condition of the FIBONACCI2 matrix.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    08 April 2015
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the order of A.
%
%    Output, real VALUE, the L1 condition.
%
  if ( n == 1 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'FIBONACCI2_CONDITION - Fatal error!\n' );
    fprintf ( 1, '  The condition number is infinite for N=1\n' );
    error ( 'FIBONACCI2_CONDITION - Fatal error!' )
  end

  if ( n == 1 )
    a_norm = 0.0;
  elseif ( n == 2 )
    a_norm = 2.0;
  else
    a_norm = 3.0;
  end
  b_norm = n;
  value = a_norm * b_norm;

  return
end


% Chapter 2 - Nonlinear Discrete Dynamical Systems.
% Program 2g - Computing the Lyapunov Exponents of the Henon map.
% Copyright Birkhauser 2013. Stephen Lynch.

itermax=500;
a=1.2;b=0.4;x=0;y=0;
vec1=[1;0];vec2=[0;1];
for i=1:itermax
    x1=1-a*x^2+y;y1=b*x;
    x=x1;y=y1;
    J=[-2*a*x 1;b 0];
    vec1=J*vec1;
    vec2=J*vec2;
    dotprod1=dot(vec1,vec1);
    dotprod2=dot(vec1,vec2);
    vec2=vec2-(dotprod2/dotprod1)*vec1;
    lengthv1=sqrt(dotprod1);
    area=vec1(1)*vec2(2)-vec1(2)*vec2(1);
    h1=log(lengthv1)/i;
    h2=log(area)/i-h1;
end
fprintf('h1= %12.10f\n',h1)
fprintf('h2= %12.10f\n',h2)

% End of Program 2g.


% X = NGROUPSK(N, K)
%
% The number of ways N*K objects can be divided into N groups of equal size
% (K objects per group).
%
% N = number of groups
% K = size of the groups
%
% X = number of different group division combinations

% Last modified 2011-01-28
% Copyright (c) Jaakko Luttinen (jaakko.luttinen@tkk.fi)

function x = groupsk(n, k)

x = factorial(n.*k) ./ ( factorial(n) .* factorial(k).^n );


function model = knReg(X, t, lambda, kn)
% Gaussian process (kernel) regression
% Input:
%   X: d x n data
%   t: 1 x n response
%   lambda: regularization parameter
% Output:
%   model: trained model structure
% Written by Mo Chen (sth4nth@gmail.com).
if nargin < 4
    kn = @knGauss;
end
if nargin < 3
    lambda = 1e-2;
end
K = knCenter(kn,X);
tbar = mean(t);
U = chol(K+lambda*eye(size(X,2)));    % 6.62
a = U\(U'\(t(:)-tbar));               % 6.68

model.kn = kn;
model.a = a;
model.X = X;
model.tbar = tbar;
%% for probability prediction
y = a'*K+tbar;
beta = 1/mean((t-y).^2);              % 3.21
alpha = lambda*beta;           % lambda=a/b P.153 3.55
model.alpha = alpha;
model.beta = beta;
model.U = U;


clear;
% some integration experiments

% Example 1: E[p(x)], x~N(0,1), p(x) polynomial
degree = 10;
p = rand(1,degree+1); % make some polynomial
fprintf('adaptive quad, tol %.1g = %.10g\n', ...
        1e-10, quad(@(x) polyval(p,x).*normpdf(x), ...
                    -30,30,1e-10));

fprintf(' gauss-hermite quadrature\n');
for n=1:((degree+1)/2+4)
  % use hermite -- will be exact for n>=(degree+1)/2
  int = gaussHermite(n);
  % notice the change of variables!
  ep = polyval(p,int.x*sqrt(2))'*int.w/sqrt(pi);
  if (n==round((degree+1)/2))
    fprintf('--- the rest should be exact ----\n');
  end
  fprintf('n=%2d  E[p(x)] = %.10g\n',n,ep);
end

fprintf('\n monte carlo integration\n')
for n=1:6
  fprintf('n=10^%d  E[p(x)] = %.10g\n',n, ...
          mean(polyval(p,randn(10^n,1))));
end

pause();

% Example 2: E[p(x)|x>-0.1], x~N(0,1)
fprintf('adaptive quad, tol %.1g = %.10g\n', ...
        1e-10, quad(@(x) polyval(p,x).*normpdf(x), ...
                    -0.1,30,1e-10) / ...
        quad(@(x) normpdf(x),-0.1,30,1e-10));

fprintf('\n gauss-hermite quadrature (not the right rule)\n');
for n=1:2:60
  int = gaussHermite(n);
  m = int.x>-0.1;
  ep = polyval(p,int.x(m)*sqrt(2))'* ...
       int.w(m)/sqrt(pi) ...
       * sum(int.w)/sum(int.w(m));
  fprintf('n=%2d  E[p(x)] = %.10g\n',sum(m),ep);
end

fprintf('\n monte carlo integration\n')
for n=1:6
  x = randn(10^n,1);
  x = x(x>-0.1);
  fprintf('n=10^%d  E[p(x)] = %.10g\n',numel(x), ...
          mean(polyval(p,x)));
end
pause();

% Example 2: E[p(x)|x>-0.1], x~N(0,1)
% Example 2: E[p(x)|x>-0.1], x~N(0,1)
fprintf('adaptive quad, tol %.1g = %.10g\n', ...
        1e-10, quad(@(x) exp(x).*normpdf(x), ...
                    -30,30,1e-10));

fprintf('\n gauss-hermite quadrature (not the right rule)\n');
for n=1:20
  int = gaussHermite(n);
  ep = exp(int.x*sqrt(2))'*int.w/sqrt(pi);
  fprintf('n=%2d  E[p(x)] = %.10g\n',n,ep);
end

fprintf('\n monte carlo integration\n')
for n=1:6
  x = randn(10^n,1);
  fprintf('n=10^%d  E[p(x)] = %.10g\n',numel(x), ...
          mean(exp(x)));
end
pause();


%inPoints = getPolygonGrid(xv,yv,ppa) returns points that are within a
%concave or convex polygon using the inpolygon function.

%xv and yv are columns representing the vertices of the polygon, as used in
%the Matlab function inpolygon

%ppa refers to the points per unit area you would like inside the polygon.
%Here unit area refers to a 1.0 X 1.0 square in the axes.

%Example:
% L = linspace(0,2.*pi,6); xv = cos(L)';yv = sin(L)'; %from the inpolygon documentation
% inPoints = getPolygonGrid(xv, yv, 10^5)
% plot(inPoints(:, 1),inPoints(:,2), '.k');

function [inPoints] = polygrid( xv, yv, ppa)

	N = sqrt(ppa);
%Find the bounding rectangle
	lower_x = min(xv);
	higher_x = max(xv);

	lower_y = min(yv);
	higher_y = max(yv);
%Create a grid of points within the bounding rectangle
	inc_x = 1/N;
	inc_y = 1/N;

	interval_x = lower_x:inc_x:higher_x;
	interval_y = lower_y:inc_y:higher_y;
	[bigGridX, bigGridY] = meshgrid(interval_x, interval_y);

%Filter grid to get only points in polygon
	in = inpolygon(bigGridX(:), bigGridY(:), xv, yv);
%Return the co-ordinates of the points that are in the polygon
	inPoints = [bigGridX(in), bigGridY(in)];

end


%% Optimal Kernel Selection
%
%%
% In the section <DensityEstimation.html density estimation> we have seen
% that the correct choice of the kernel halfwidth is essential for creating a good
% match between the true density function and the reconstructed density
% function. If the halfwidth is set too small the reconstructed density
% function is usually oscillating and the indiviudual sampling points are
% visible as sharp peaks. If the halfwidth is too large the resulting
% density function is usually too smooth and does not reproduce the
% features of the original density function.
%
% Finding an optimal kernel halfwidth is a hard problem as the optimal
% kernel halfwidth depends not only on the number of sampling points but also
% on the smoothness of the true but unknown density function.
% MTEX offers several options set by flags during the kernel calculation operation.  A very
% conserative choice for the kernel halfwidth that takes into account only
% the number of sampling points is implemented in MTEX with the flag |'magicRule'|. The flag
% |'RuleOfThumb'| considers both the number of sampling
% points and the variance of the sampling points as an estimate of the
% smoothness of the true density function. The most advanced (and default)
% method for estimating the optimal kernel halfwidth is
% <orientation.KLCV.html Kullback Leibler cross validation>.
% This method tests different kernel halfwidths on a subset of the
% random sample and selects the halfwidth which best reproduces the
% ommited points of the random sample.
%
% In order to demonstrate this functionality let's start with the following
% orientation density function

% Define trigonal crystal symmetry using Enantiomorphic Point Group notation
cs = crystalSymmetry('32');

% Build a density function by combining a uniform texture with two pre-defined texture components
odf = 0.25*uniformODF(cs) + 0.25*unimodalODF(orientation.brass(cs)) + ...
  0.5*fibreODF(fibre.alpha(cs),'halfwidth',10*degree);

% plot the density function as six sigma sections
plot(odf,'sections',6,'silent','sigma')
mtexColorbar

%%
% and compute $10000$ random orientations representing this density function using the command
% |<orientation.discreteSample.html discreteSample>|

ori = odf.discreteSample(10000)

%%
% Next we estimate the optimal <ODFShapes.html kernel function> using the
% command |<orientation.calcKernel.html calcKernel>| with the default settings.

psi  = calcKernel(ori)

%%
% This kernel can now be used to reconstruct the original ODF from the sampled points using the command
% <DensityEsimation.html density estimation>

odf_rec = calcDensity(ori,'kernel',psi)

% plot the reconstructed ODF and compare it to the plot of the original function.  The results are similar but not identical.
figure;plot(odf_rec,'sections',6,'silent','sigma')
mtexColorbar

%% Exploration of the relationship between estimation error and number of single orientations
%
% In this section we want to compare the different methods for estimating
% the optimal kernel halfwidth. To this end we simulate 10, 100, ...,
% 1000000 single orientations from the model ODF |odf|, compute optimal
% kernels according to the |'magicRule'|, the |'RuleOfThumb'| and
% <orientation.KLCV.html Kullback Leibler cross validation> and then
% compute the fit between the reconstructed |odf_rec| and the original
% |odf|.

% define a variable to hold the calculated error values
e = [];
for i = 1:6

  % calculate a sample of orientations from the model ODF
  ori = discreteSample(odf,10^i,'silent');

  % calculate the kernel using the function defaults, reconstruct the odf, and calculate error between this and the original ODF
  psi1 = calcKernel(ori,'SamplingSize',10000,'silent');
  odf_rec = calcDensity(ori,'kernel',psi1,'silent');
  e(i,1) = calcError(odf_rec,odf,'resolution',2.5*degree);

  % calculate the kernel using the RuleOfThumb, reconstruct the odf, and calculate error between this and the original ODF
  psi2 = calcKernel(ori,'method','RuleOfThumb','silent');
  odf_rec = calcDensity(ori,'kernel',psi2,'silent');
  e(i,2) = calcError(odf_rec,odf,'resolution',2.5*degree);

  % calculate the kernel using the magicRule, reconstruct the odf, and calculate error between this and the original ODF
  psi3 = calcKernel(ori,'method','magicRule','silent');
  odf_rec = calcDensity(ori,'kernel',psi3,'silent');
  e(i,3) = calcError(odf_rec,odf,'resolution',2.5*degree);

  % generate text showing the kernel size calculated with each method in each loop
  disp(['RuleOfThumb: ' int2str(psi2.halfwidth/degree) mtexdegchar ...
    ' KLCV: ' int2str(psi1.halfwidth/degree) mtexdegchar ...
    ' magicRule: ' int2str(psi3.halfwidth/degree) mtexdegchar ...
    ]);

end

%%
% Plot the error to the number of single orientations sampled from the original ODF.

close all;
loglog(10.^(1:length(e)),e,'LineWidth',2)
legend('Default','RuleOfThumb','magicRule')
xlabel('Number of orientations (log scale)')
ylabel('Estimation Error in degrees')
title('Error between original ODF model and the reconstructed ODF','FontWeight','bold')


function linplus_test385 ( )

%*****************************************************************************80
%
%% TEST385 tests R8GE_PLU.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 March 2009
%
%  Author:
%
%    John Burkardt
%
  m = 5;
  n = 4;
  seed = 123456789;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST385\n' );
  fprintf ( 1, '  For a matrix in general storage,\n' );
  fprintf ( 1, '  R8GE_PLU returns the PLU factors of a matrix.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Matrix rows M =    %d\n', m );
  fprintf ( 1, '  Matrix columns N = %d\n', n );

  a = r8ge_random ( m, n, seed );

  r8ge_print ( m, n, a, '  Matrix A:' );
%
%  Compute the PLU factors.
%
  [ p, l, u ] = r8ge_plu ( m, n, a );

  r8ge_print ( m, m, p, '  Factor P:' );

  r8ge_print ( m, m, l, '  Factor L:' );

  r8ge_print ( m, n, u, '  Factor U:' );

  plu(1:m,1:n) = p(1:m,1:m) * ( l(1:m,1:m) * u(1:m,1:n) );

  r8ge_print ( m, n, plu, '  Product P*L*U:');

  return
end


function [X,Y,Z] = EquinNdes3D(N)

% function [X,Y,Z] = EquinNdes3D(N)
% Purpose: compute the equidistributed nodes on the reference tetrahedron

% total number of nodes
Np = (N+1)*(N+2)*(N+3)/6;

% 2) create equidistributed nodes on equilateral triangle
X = zeros(Np,1); Y = zeros(Np,1); Z = zeros(Np,1);

sk = 1;
for n=1:N+1
  for m=1:N+2-n
    for q=1:N+3-n-m
      X(sk) = -1 + (q-1)*2/N; Y(sk) = -1 + (m-1)*2/N; Z(sk) = -1 + (n-1)*2/N;
      sk = sk+1;
    end
  end
end
return;


function m = sqdist(p, q, A)
% SQDIST      Squared Euclidean or Mahalanobis distance.
% SQDIST(p,q)   returns m(i,j) = (p(:,i) - q(:,j))'*(p(:,i) - q(:,j)).
% SQDIST(p,q,A) returns m(i,j) = (p(:,i) - q(:,j))'*A*(p(:,i) - q(:,j)).
% The Lightspeed Matlab toolbox
% Written by Tom Minka

[d, pn] = size(p);
[d, qn] = size(q);

if pn == 0 || qn == 0
  m = zeros(pn,qn);
  return
end

if nargin == 2

  pmag = col_sum(p .* p);
  qmag = col_sum(q .* q);
  m = repmat(qmag, pn, 1) + repmat(pmag', 1, qn) - 2*p'*q;
  %m = ones(pn,1)*qmag + pmag'*ones(1,qn) - 2*p'*q;

else

  Ap = A*p;
  Aq = A*q;
  pmag = col_sum(p .* Ap);
  qmag = col_sum(q .* Aq);
  m = repmat(qmag, pn, 1) + repmat(pmag', 1, qn) - 2*p'*Aq;

end


function eps = leviCivita
% the Levi Civita permutation tensor
%
% Syntax
%   eps = tensor.leviCivita
%

eps = zeros(3,3,3);
eps(1,2,3) = 1;
eps(3,1,2) = 1;
eps(2,3,1) = 1;

eps(1,3,2) = -1;
eps(3,2,1) = -1;
eps(2,1,3) = -1;

eps = tensor(eps,'rank',3,'name','Levi Cevita');

end


function centroids = computeCentroids(X, idx, K)
%COMPUTECENTROIDS returns the new centroids by computing the means of the
%data points assigned to each centroid.
%   centroids = COMPUTECENTROIDS(X, idx, K) returns the new centroids by
%   computing the means of the data points assigned to each centroid. It is
%   given a dataset X where each row is a single data point, a vector
%   idx of centroid assignments (i.e. each entry in range [1..K]) for each
%   example, and K, the number of centroids. You should return a matrix
%   centroids, where each row of centroids is the mean of the data points
%   assigned to it.
%

% Useful variables
[m n] = size(X);

% You need to return the following variables correctly.
centroids = zeros(K, n);

% ====================== YOUR CODE HERE ======================
% Instructions: Go over every centroid and compute mean of all points that
%               belong to it. Concretely, the row vector centroids(i, :)
%               should contain the mean of the data points assigned to
%               centroid i.
%
% Note: You can use a for-loop over the centroids to compute this.
%
centroidsSum = zeros(K,1);
for i = 1 : m
	centroids(idx(i), :) = centroids(idx(i), :) .+ X(i, :);
	centroidsSum(idx(i)) = centroidsSum(idx(i)) + 1;
end
for i = 1 : K
	centroids(i,:) = centroids(i,:) ./ centroidsSum(i) ;
end

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

end


% Demonstration of Rank Aware Order Recursive Matching Pursuit.

close all;
clear all;
clc;
rng('default');
png_export = true;
pdf_export = false;
% Create the directory for storing images
[status_code,message,message_id] = mkdir('bin');

mf = spx.graphics.Figures();

% Signal space
N = 256;
% Number of measurements
M = 64;
% Sparsity level
K = 8;
% Number of signals
S = 4;
% Construct the signal generator.
gen  = spx.data.synthetic.SparseSignalGenerator(N, K, S);
% Generate bi-uniform signals
X = gen.biUniform(1, 2);
% Sensing matrix
Phi = spx.dict.simple.gaussian_dict(M, N);
% Measurement vectors
Y = Phi.apply(X);
% Rank Aware ORMP MMV solver instance
solver = spx.pursuit.joint.RankAwareORMP(Phi, K);
% Solve the sparse recovery problem
result = solver.solve(Y);
% Solution vector
Z = result.Z;

for s=1:S
    mf.new_figure(sprintf('Rank Aware ORMP signal: %d', s));
    subplot(411);
    stem(X(:, s), '.');
    title('Sparse vector');
    subplot(412);
    stem(Z(:, s), '.');
    title('Recovered sparse vector');
    subplot(413);
    stem(abs(X(:, s) - Z(:, s)), '.');
    title('Recovery error');
    subplot(414);
    stem(Y(:, s), '.');
    title('Measurement vector');
end


%% housekeeping
clearvars
close all
clc

%% choose some options
% scramble the pseudo-random numbers or not
scramble_flag=true;
% optimal polynomial or theoretical ones
optimal_poly=true;
% debug or not
debug_flag=true;
%% read information about the function of interest
[objective,bounds]=ishigami();
% [objective,bounds]=satelli_sobol95();
lb=bounds(:,1);
ub=bounds(:,2);
npar=numel(lb);
param_names=strcat('pp_',num2str((1:npar)'));
%% choose the polynomial order
pol_order=4;
%% choose the expansion_order
expansion_order=3;
%% choose the number of samples
N=2^9;%2048;
%% option 1: generate samples and create the hdmr object

% theta=quasi_monte_carlo.sobol(npar,N,lb,ub,scramble_flag); % number of sub-intervals
theta=quasi_monte_carlo.sobol(lb,ub,N,scramble_flag); % number of sub-intervals
f=objective(theta);
objective_={f,theta};
%% option 2: let the hdmr object generate the samples for you
% objective_={objective,bounds,N};
%% construct the object
obj=hdmr(objective_,param_names,bounds,expansion_order,pol_order,optimal_poly);

%% estimate the object
profile off
profile on
obj=estimate(obj,debug_flag);
profile off
profile viewer
%% plot the fit insample
plot_fit(obj,'insample');
%% plot the fit out of sample
plot_fit(obj,'outofsample');
%% plot the individual effects
for ii=1:size(theta,1)
    figure();
    first_order_effect(obj,'insample',ii);
end


function value = r8mat_norm_fro_affine ( m, n, a1, a2 )

%*****************************************************************************80
%
%% R8MAT_NORM_FRO_AFFINE returns the Frobenius norm of an R8MAT difference.
%
%  Discussion:
%
%    The Frobenius norm is defined as
%
%      value = sqrt ( sum ( 1 <= I <= M ) sum ( 1 <= j <= N ) A(I,J)^2 )
%
%    The matrix Frobenius norm is not derived from a vector norm, but
%    is compatible with the vector L2 norm, so that:
%
%      vec_norm_l2 ( A * x ) <= mat_norm_fro ( A ) * vec_norm_l2 ( x ).
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    26 September 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer M, the number of rows.
%
%    Input, integer N, the number of columns.
%
%    Input, real A1(M,N), A2(M,N), the matrices for whose difference
%    the Frobenius norm is desired.
%
%    Output, real VALUE, the Frobenius norm of A1 - A2.
%
  value = sqrt ( sum ( sum ( ( a1(1:m,1:n) - a2(1:m,1:n) ).^2 ) ) );

  return
end


function mbasis = basis_matrix_beta_uni ( beta1, beta2 )

%*****************************************************************************80
%
%% BASIS_MATRIX_BETA_UNI sets up the uniform beta spline basis matrix.
%
%  Discussion:
%
%    If BETA1 = 1 and BETA2 = 0, then the beta spline reduces to
%    the B spline.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    12 February 2004
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Foley, van Dam, Feiner, Hughes,
%    Computer Graphics: Principles and Practice,
%    page 505.
%
%  Parameters:
%
%    Input, real BETA1, the skew or bias parameter.
%    BETA1 = 1 for no skew or bias.
%
%    Input, real BETA2, the tension parameter.
%    BETA2 = 0 for no tension.
%
%    Output, real MBASIS(4,4), the basis matrix.
%
  mbasis = zeros(4,4);

  mbasis(1,1) = - 2.0 * beta1 * beta1 * beta1;
  mbasis(1,2) =   2.0 * beta2 ...
    + 2.0 * beta1 * ( beta1 * beta1 + beta1 + 1.0 );
  mbasis(1,3) = - 2.0 * ( beta2 + beta1 * beta1 + beta1 + 1.0 );
  mbasis(1,4) =   2.0;

  mbasis(2,1) =   6.0 * beta1 * beta1 * beta1;
  mbasis(2,2) = - 3.0 * beta2 ...
    - 6.0 * beta1 * beta1 * ( beta1 + 1.0 );
  mbasis(2,3) =   3.0 * beta2 + 6.0 * beta1 * beta1;
  mbasis(2,4) =   0.0;

  mbasis(3,1) = - 6.0 * beta1 * beta1 * beta1;
  mbasis(3,2) =   6.0 * beta1 * ( beta1 - 1.0 ) * ( beta1 + 1.0 );
  mbasis(3,3) =   6.0 * beta1;
  mbasis(3,4) =   0.0;

  mbasis(4,1) =   2.0 * beta1 * beta1 * beta1;
  mbasis(4,2) =   4.0 * beta1 * ( beta1 + 1.0 ) + beta2;
  mbasis(4,3) =   2.0;
  mbasis(4,4) =   0.0;

  delta = ( ( 2.0   ...
    * beta1 + 4.0 ) ...
    * beta1 + 4.0 ) ...
    * beta1 + 2.0 + beta2;

  mbasis(1:4,1:4) = mbasis(1:4,1:4) / delta;

  return
end


function [pval, k, K] = circ_kuipertest(alpha1, alpha2, res, vis_on)

% [pval, k, K] = circ_kuipertest(sample1, sample2, res, vis_on)
%
%   The Kuiper two-sample test tests whether the two samples differ
%   significantly.The difference can be in any property, such as mean
%   location and dispersion. It is a circular analogue of the
%   Kolmogorov-Smirnov test.
%
%   H0: The two distributions are identical.
%   HA: The two distributions are different.
%
% Input:
%   alpha1    fist sample (in radians)
%   alpha2    second sample (in radians)
%   res       resolution at which the cdf is evaluated
%   vis_on    display graph
%
% Output:
%   pval        p-value; the smallest of .10, .05, .02, .01, .005, .002,
%               .001, for which the test statistic is still higher
%               than the respective critical value. this is due to
%               the use of tabulated values. if p>.1, pval is set to 1.
%   k           test statistic
%   K           critical value
%
% References:
%   Batschelet, 1980, p. 112
%
% Circular Statistics Toolbox for Matlab

% Update 2012
% By Marc J. Velasco and Philipp Berens, 2009
% velasco@ccs.fau.edu

if nargin < 3
    res = 100;
end
if nargin < 4
    vis_on = 0;
end

n = length(alpha1(:));
m = length(alpha2(:));

% create cdfs of both samples
[phis1 cdf1 phiplot1 cdfplot1] = circ_samplecdf(alpha1, res);
[foo, cdf2 phiplot2 cdfplot2] = circ_samplecdf(alpha2, res); %#ok<ASGLU>

% maximal difference between sample cdfs
[dplus, gdpi] = max([0 cdf1-cdf2]);
[dminus, gdmi] = max([0 cdf2-cdf1]);

% calculate k-statistic
k = n * m * (dplus + dminus);

% find p-value
[pval K] = kuiperlookup(min(n,m),k/sqrt(n*m*(n+m)));
K = K * sqrt(n*m*(n+m));

% visualize
if vis_on
    figure
    plot(phiplot1, cdfplot1, 'b', phiplot2, cdfplot2, 'r');
    hold on
    plot([phis1(gdpi-1), phis1(gdpi-1)], [cdf1(gdpi-1) cdf2(gdpi-1)], 'o:g');
    plot([phis1(gdmi-1), phis1(gdmi-1)], [cdf1(gdmi-1) cdf2(gdmi-1)], 'o:g');
    hold off
    set(gca, 'XLim', [0, 2*pi]);
    set(gca, 'YLim', [0, 1.1]);
    xlabel('Circular Location')
    ylabel('Sample CDF')
    title('CircStat: Kuiper test')
    h = legend('Sample 1', 'Sample 2', 'Location', 'Southeast');
    set(h,'box','off')
    set(gca, 'XTick', pi*(0:.25:2))
    set(gca, 'XTickLabel', {'0', '', '', '', 'pi', '', '', '', '2pi'})
end

end

function [p K] = kuiperlookup(n, k)

load kuipertable.mat;
alpha = [.10, .05, .02, .01, .005, .002, .001];
nn = ktable(:,1);  %#ok<NODEF>

% find correct row of the table
[easy row] = ismember(n, nn);
if ~easy
   % find closest value if no entry is present)
   row = length(nn) - sum(n<nn);
   if row == 0
       error('N too small.');
   else
      warning('N=%d not found in table, using closest N=%d present.',n,nn(row)) %#ok<WNTAG>
   end
end

% find minimal p-value and test-statistic
idx = find(ktable(row,2:end)<k,1,'last');
if ~isempty(idx)
  p = alpha(idx);
else
  p = 1;
end
K = ktable(row,idx+1);

end


function bernstein_polynomial_test04 ( )

%*****************************************************************************80
%
%% BERNSTEIN_POLYNOMIAL_TEST04 tests BERNSTEIN_POLY_AB_APPROX.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    11 July 2011
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'BERNSTEIN_POLYNOMIAL_TEST04\n' );
  fprintf ( 1, '  BERNSTEIN_POLY_AB_APPROX evaluates the Bernstein polynomial\n' );
  fprintf ( 1, '  approximant to a function F(X).\n' );

  a = 1.0;
  b = 3.0;

  fprintf ( 1, '\n' );
  fprintf ( 1, '     N      Max Error\n' );
  fprintf ( 1, '\n' );

  for degree = 0 : 20
%
%  Generate data values.
%
    xdata = zeros ( degree + 1, 1 );
    ydata = zeros ( degree + 1, 1 );

    for i = 0 : degree

      if ( degree == 0 )
        xdata(i+1) = 0.5 * ( a + b );
      else
        xdata(i+1) = ( ( degree - i ) * a   ...
                     + (          i ) * b ) ...
                     / ( degree     );
      end

      ydata(i+1) = sin ( xdata(i+1) );

    end
%
%  Compare the true function and the approximant.
%
    nval = 501;

    xval = linspace ( a, b, nval );

    yval = bernstein_poly_ab_approx ( degree, a, b, ydata, nval, xval );

    error_max = max ( abs ( yval(1:nval) - sin ( xval(1:nval) ) ) );

    fprintf ( 1, '  %4d  %14.6g\n', degree, error_max );

  end

  return
end


function P = vecperm(m, n)
%VECPERM    Vec-permutation matrix.
%           VECPERM(M, N) is the vec-permutation matrix, an MN-by-MN
%           permutation matrix P with the property that if A is M-by-N then
%           vec(A) = P*vec(A').
%           If N is omitted, it defaults to M.

%   P is formed by taking every n'th row from EYE(M*N), starting with
%   the first and working down - see p. 277 of the reference.

%   Reference:
%   H. V. Henderson and S. R. Searle The vec-permutation matrix,
%   the vec operator and Kronecker products: A review Linear and
%   Multilinear Algebra, 9 (1981), pp. 271-288.

if nargin == 1, n = m; end

P = zeros(m*n);
I = eye(m*n);

k = 1;
for i=1:n
    for j=i:n:m*n
        P(k,:) = I(j,:);
        k = k+1;
    end
end
end


function [p1ext p2ext degen] = extline(p1, p2, imgwidth, imgheight)
% p1: [x y]
% p2: [x y]

dir = p2 - p1;

% intersection with top
% p1(1) + alpha*dir(2) = 1
% int1 = p1 + alpha*dir
alpha = (1 - p1(2)) / dir(2);
intp{1} = p1 + alpha*dir;
intp{1}(2) = 1; % numerical precision issues....
intp{1} = intp{1}(:)'; % [2x1]

% intersection with bottom
% p1(1) + alpha*dir(2) = imgheight
% int2 = p1 + alpha*dir
alpha = (imgheight - p1(2)) / dir(2);
intp{2} = p1 + alpha*dir;
intp{2}(2) = imgheight; % numerical precision issues....
intp{2} = intp{2}(:)'; % [2x1]

% intersection with left
% p1(2) + alpha*dir(1) = 1
% int3 = p1 + alpha*dir
alpha = (1 - p1(1)) / dir(1);
intp{3} = p1 + alpha*dir;
intp{3}(1) = 1; % numerical precision issues....
intp{3} = intp{3}(:)'; % [2x1]

% intersection with right
% p1(2) + alpha*dir(2) = imgwidth
% int4 = p1 + alpha*dir
alpha = (imgwidth - p1(1)) / dir(1);
intp{4} = p1 + alpha*dir;
intp{4}(1) = imgwidth; % numerical precision issues....
intp{4} = intp{4}(:)'; % [2x1]

b(1) = isinimage(intp{1}, imgwidth, imgheight);
b(2) = isinimage(intp{2}, imgwidth, imgheight);
b(3) = isinimage(intp{3}, imgwidth, imgheight);
b(4) = isinimage(intp{4}, imgwidth, imgheight);

% should touch at least 2 edges
% greater than 2 when intersects exactly at corner of image
% assert(b(1)+b(2)+b(3)+b(4) >= 2);
if b(1)+b(2)+b(3)+b(4) < 2
    degen = 1;
    p1ext = [0 0];
    p2ext = [0 0];
    return;
else
    degen = 0;
end

% b = find(b);
% p1ext = intp{b(1)};
% p2ext = intp{b(2)};

p = cat(1, intp{logical(b)});
% p = unique(p, 'rows');
% assert(size(p,1)==2);
p1ext = p(1,:);
p2ext = p(2,:);

%%
function flag = isinimage(p, imgwidth, imgheight)
if p(1)>=1 && p(1)<=imgwidth && p(2)>=1 && p(2)<=imgheight
    flag = 1;
else
    flag = 0;
end


%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%   Relevant Vector Regression 1D Example %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%               1) Load 1D Regression Datasets               %%
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%  (simple example) Generate Data from sine function
clear all; close all; clc;
nbSamples = 200;
epsilon   = 0.1;
x_limits  = [0, 100];

% Generate True function and data
X         = linspace(x_limits(1),x_limits(2),nbSamples)';
y_true    = sin(X*0.05);
y         = y_true + normrnd(0,epsilon,1,nbSamples)';

% Plot data
options             = [];
options.points_size = 10;
options.title       = 'noisy sinusoidal data';

if exist('h1','var') && isvalid(h1), delete(h1);end
h1      = ml_plot_data([X(:),y(:)],options); hold on;

% Plot True function and Data
plot(X,y_true,'--k','LineWidth',2);
legend({'data','true function'})

%% (complex example) Generate Data from a sinc function
clear all; close all; clc;
% Set parameters for sinc function data
nbSamples = 200;
epsilon   = 0.2;
y_offset  = 0.5;
x_limits  = [-5, 5];

% Generate True function and data
X = linspace(x_limits(1),x_limits(2),nbSamples) ;
y_true = sinc(X) + y_offset ;
y = y_true + normrnd(0,epsilon,1,nbSamples);

% Plot data
options             = [];
options.points_size = 15;
options.title       = 'noisy sinc data';

if exist('h1','var') && isvalid(h1), delete(h1);end
h1      = ml_plot_data([X(:),y(:)],options); hold on;

% Plot True function and Data
plot(X,y_true,'--k','LineWidth',2);
legend({'data','true function'})

% Transform Data for CV
X = X'; y = y';

%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%                    2)  RELEVANT VECTOR REGRESSION                     %%
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% RVR + RBF Kernel

clear rvr_options

%Set RVR OPTIONS%
rvr_options.useBias = true;
rvr_options.maxIts  = 100;

%Set Kernel OPTIONS%
rvr_options.kernel_ = 'gauss';
rvr_options.width   = 1;

% Train RVR Model
clear model
[~, model] = rvm_regressor(X,y,rvr_options,[]);

% Plot RVR function
ml_plot_rvr_function(X, y, model, rvr_options);

%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%   3) Do K-fold cross validation on hyper-parameters for RVR      %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% K-fold cross validation

Kfold = 10;
disp('Parameter grid search RVR');

%Set RVR OPTIONS%
rvr_options.useBias = true;
rvr_options.maxIts  = 100;

%Set Kernel OPTIONS%
rvr_options.kernel_ = 'gauss';

% Modify these according to your data!
rbf_vars = [0.1:0.1:1];

test  = cell(length(rbf_vars),1);
train = cell(length(rbf_vars),1);

for i=1:length(rbf_vars)
    disp(['[' num2str(i) '/' num2str(length(rbf_vars)) ']']);

    rvr_options.width       = rbf_vars(i);   %  radial basis function: exp(-gamma*|u-v|^2), gamma = 1/(2*sigma^2)

    f                       = @(X,y,model)rvm_regressor(X,y,rvr_options,model);
    [test_eval,train_eval]  = ml_kcv(X,y,Kfold,f,'regression');

    test{i}                 = test_eval;
    train{i}                = train_eval;
    disp(' ');
end

%% Get Statistics

[ stats ] = ml_get_cv_grid_states_regression(test,train);

% Plot Statistics

options             = [];
options.title       = 'RVR k-CV';
options.metrics     = {'nmse'};     % <- you can add many other metrics, see list in next cell box
options.para_name   = 'variance rbf';

[handle,handle_test,handle_train] = ml_plot_cv_grid_states_regression(stats,rbf_vars,options);


function r = msmoothboxrnd(a,b,sigma,n)
%MSMOOTHBOXRND Random arrays from the multivariate smooth-box distribution.
%   R = MSMOOTHBOXRND(A,B,SIGMA) returns an N-by-D matrix R of random
%   vectors chosen from the multivariate smooth-box distribution
%   with pivots A and B and scale SIGMA. A, B and SIGMA are N-by-D matrices,
%   and MSMOOTHBOXRND generates each row of R using the corresponding row
%   of A, B and SIGMA.
%
%   R = MSMOOTHBOXRND(A,B,SIGMA,N) returns a N-by-D matrix R of random
%   vectors chosen from the multivariate smooth-box distribution
%   with pivots A and B and scale SIGMA.
%
%   See also MSMOOTHBOXPDF.

% Luigi Acerbi 2022

[Na,Da] = size(a);
[Nb,Db] = size(b);
[Nsigma,Dsigma] = size(sigma);

if any(sigma(:) <= 0)
    error('msmoothboxrnd:NonPositiveSigma', ...
        'All elements of SIGMA should be positive.');
end

if nargin < 4 || isempty(n)
    n = max([Na,Nb,Nsigma]);
else
    if (Na ~= 1 && Na ~= n) || (Nb ~= 1 && Nb ~= n) || ...
            (Nsigma ~= 1 && Nsigma ~= n)
        error('msmoothboxrnd:SizeError', ...
            'A, B, SIGMA should be 1-by-D or N-by-D arrays.');
    end
end
if Na ~= Nb || Da ~= Db || Na ~= Nsigma || Da ~= Dsigma
    error('msmoothboxrnd:SizeError', ...
        'A, B, SIGMA should be arrays of the same size.');
end

D = Da;

if size(a,1) == 1; a = repmat(a,[n,1]); end
if size(b,1) == 1; b = repmat(b,[n,1]); end
if size(sigma,1) == 1; sigma = repmat(sigma,[n,1]); end

r = zeros(n,D);

nf = 1 + 1/sqrt(2*pi)./sigma.*(b - a);

% Sample one dimension at a time
for d = 1:D
    % Draw component (left/right tails or plateau)
    u = nf(:,d) .* rand(n,1);

    % Left Gaussian tails
    idx = u < 0.5;
    if any(idx)
        z1 = abs(randn(sum(idx),1).*sigma(idx,d));
        r(idx,d) = a(idx) - z1;
    end

    % Right Gaussian tails
    idx = (u >= 0.5 & u < 1);
    if any(idx)
        z1 = abs(randn(sum(idx),1).*sigma(idx,d));
        r(idx,d) = b(idx) + z1;
    end

    % Plateau
    idx = u >= 1;
    if any(idx)
        r(idx,d) = a(idx,d) + (b(idx,d) - a(idx,d)).*rand(sum(idx),1);
    end
end


function c = i4_division ( a, b )

%*****************************************************************************80
%
%% I4_DIVISION returns the result of integer division.
%
%  Discussion:
%
%    This routine computes C = A / B, where the result is rounded to the
%    integer value nearest 0.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    27 March 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer A, B, the number to be divided,
%    and the divisor.
%
%    Output, integer C, the rounded result of the division.
%
  if ( a * b < 0.0 )
    s = -1;
  else
    s = +1;
  end

  a = abs ( a );
  b = abs ( b );
  c = s * floor ( a / b );

  return
end


  function xs = alg_art1(x, At, y, varargin)
%|function xs = alg_art1(x, At, y, [options])
%| classical ART algorithm, aka, Kaczmarz algorithm; tries to solve y=Ax
%|
%| in
%|	x	[np 1]		initial guess, possibly empty
%|	Caution: x must be in the range of A' for convergence!
%|	At	[np nd]		(hermitian) *transpose* of system matrix
%|	y	[nb na]		measurement
%|
%| option
%|	wi	[nb na]		weights
%|	niter			# of iterations
%|	isave			default: [] 'last'
%|	pixmin
%|	pixmax
%|	anorms	[nd 1]		see below
%|	eps
%|
%| out
%|	xs	[np niter]	iterates
%|
%| Copyright 2006-4-2, Jeff Fessler, University of Michigan

if nargin == 1 && streq(x, 'test'), alg_art1_test, return, end
if nargin < 3, ir_usage, end
if isempty(x), x = zeros(nrow(A),1); end

% defaults
arg.niter = 1;
arg.isave = [];
arg.anorms = [];
arg.eps = eps;
%arg.pixmax = inf;
%arg.pixmin = -inf;

% options
arg = vararg_pair(arg, varargin);

arg.isave = iter_saver(arg.isave, arg.niter);

[nb na] = size(y);
starts = subset_start(na);

% For WLS, premultiply y and postmultiply At by W^{1/2}
%Wh = spdiag(sqrt(wi(:)), 'nowarn');
%y = Wh * y(:);
%At = At * Wh;

% weighted row norms
if isempty(arg.anorms)
	arg.anorms = sum(At.^2); % | e_i' A |^2
end

iglist = col(outer_sum(1:nb, (starts-1)*nb));
iglist = iglist(arg.anorms(iglist) ~= 0);

adenom = arg.anorms + eps; % trick:

np = length(x);
xs = zeros(np, length(arg.isave));
if any(arg.isave == 0)
	xs(:, arg.isave == 0) = x;
end

ticker(mfilename, 1, arg.niter)

for iter=1:arg.niter
	ticker(mfilename, iter, arg.niter)

	for ii=iglist'
		ai = At(:,ii);
		step = (y(ii) - ai' * x) / adenom(ii);
		x = x + ai * step;

%		todo: try following approach to see if faster
%		[j ignore ai] = find(At(:,ii));
%		xj = x(j);
%		step = (y(ii) - ai' * xj) / adenom(ii);
%		x(j) = xj - step * ai;
	end

	if any(arg.isave == iter)
		xs(:, arg.isave == iter) = x;
	end
end


function result = graph_adj_is_node_connected ( adj, nnode )

%*****************************************************************************80
%
%% GRAPH_ADJ_IS_NODE_CONNECTED determines if a graph is nodewise connected.
%
%  Definition:
%
%    A graph is nodewise connected if, from every node, there is a path
%    to any other node.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    28 June 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer ADJ(NNODE,NNODE), the adjacency matrix for the
%    graph.  ADJ(I,J) is nonzero if there is an edge from node I to node J.
%
%    Input, integer NNODE, the number of nodes.
%
%    Output, integer RESULT.
%    0, the graph is not nodewise connected.
%    1, the graph is nodewise connected.
%

%
%  FOUND(I) is 1 if node I has been reached.
%  LIST(I) contains a list of the nodes as they are reached.
%
  list(1:nnode) = 0;
  found(1:nnode) = 0;
%
%  Start at node 1.
%
  found(1) = 1;
  list(1) = 1;
  ilo = 1;
  ihi = 1;
%
%  From the batch of nodes found last time, LIST(ILO:IHI),
%  look for unfound neighbors, and store their indices in LIST(JLO:JHI).
%
  while ( 1 )

    jlo = ihi + 1;
    jhi = ihi;

    for ii = ilo : ihi

      i = list(ii);

      for j = 1 : nnode

        if ( adj(i,j) ~= 0 || adj(j,i) ~= 0 )

          if ( found(j) == 0 )
            jhi = jhi + 1;
            list(jhi) = j;
            found(j) = 1;
          end

        end

      end

    end
%
%  If no neighbors were found, exit.
%
    if ( jhi < jlo )
      break
    end
%
%  If neighbors were found, then go back and find THEIR neighbors.
%
    ilo = jlo;
    ihi = jhi;

  end
%
%  No more neighbors were found.  Have we reached all nodes?
%
  if ( ihi == nnode )
    result = 1;
  else
    result = 0;
  end

  return
end


function ellipse_grid_display ( ng, xy )

%*****************************************************************************80
%
%% ELLIPSE_GRID_DISPLAY displays grid points inside an ellipse.
%
%  Discussion:
%
%    The ellipse is specified as
%
%      ( ( X - C1 ) / R1 )^2 + ( ( Y - C2 ) / R2 )^2 = 1
%
%    The user supplies a number N.  There will be N+1 grid points along
%    the shorter axis.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 September 2010
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer NG, the number of grid points inside the ellipse.
%
%    Input, real XY(2,NG), the grid points.
%
  scatter ( xy(1,:), xy(2,:), 'b.' );
  axis equal
  title ( sprintf ( '%d grid points inside an ellipse', ng ) )
  grid on

  return
end


function prob_test012 ( )

%*****************************************************************************80
%
%% PROB_TEST012 tests BETA_CDF, BETA_CDF_INV, BETA_PDF;
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    27 April 2013
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'PROB_TEST012\n' );
  fprintf ( 1, '  For the Beta PDF:\n' );
  fprintf ( 1, '  BETA_CDF evaluates the CDF;\n' );
  fprintf ( 1, '  BETA_CDF_INV inverts the CDF.\n' );
  fprintf ( 1, '  BETA_PDF evaluates the PDF;\n' );

  a = 12.0;
  b = 12.0;

  fprintf ( 1, '\n' );
  fprintf ( 1, '  PDF parameter A = %14f\n', a );
  fprintf ( 1, '  PDF parameter B = %14f\n', b );

  check = beta_check ( a, b );

  if ( ~check );
    fprintf ( 1, '\n' );
    fprintf ( 1, 'PROB_TEST012 - Fatal error!\n' );
    fprintf ( 1, '  The parameters are not legal.\n' );
    return
  end

  seed = 123456789;

  fprintf ( 1, '\n' );
  fprintf ( 1, '        A               B               X               ' )
  fprintf ( 1, 'PDF             CDF             CDF_INV\n' );
  fprintf ( 1, '\n' );

  for i = 1 : 10

    [ x, seed ] = beta_sample ( a, b, seed );

    pdf = beta_pdf ( x, a, b );

    cdf = beta_cdf ( x, a, b );

    x2 = beta_cdf_inv ( cdf, a, b );

    fprintf ( 1, '%14f  %14f  %14f  %14f  %14f  %14f\n', a, b, x, pdf, cdf, x2 );

  end

  return
end


function integral = sphere01_monomial_integral ( e )

%*****************************************************************************80
%
%% SPHERE01_MONOMIAL_INTEGRAL returns monomial integrals on the unit sphere.
%
%  Discussion:
%
%    The integration region is
%
%      X^2 + Y^2 + Z^2 = 1.
%
%    The monomial is F(X,Y,Z) = X^E(1) * Y^E(2) * Z^E(3).
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    22 September 2010
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Philip Davis, Philip Rabinowitz,
%    Methods of Numerical Integration,
%    Second Edition,
%    Academic Press, 1984, page 263.
%
%  Parameters:
%
%    Input, integer E(3), the exponents of X, Y and Z in the
%    monomial.  Each exponent must be nonnegative.
%
%    Output, real INTEGRAL, the integral.
%
  if ( any ( e(1:3) < 0 ) )
    integral = - Inf;
    fprintf ( 1, '\n' );
    fprintf ( 1, 'SPHERE01_MONOMIAL_INTEGRAL - Fatal error!\n' );
    fprintf ( 1, '  All exponents must be nonnegative.\n' );
    fprintf ( 1, '  E(1) = %d\n', e(1) );
    fprintf ( 1, '  E(2) = %d\n', e(2) );
    fprintf ( 1, '  E(3) = %d\n', e(3) );
    error ( 'SPHERE01_MONOMIAL_INTEGRAL - Fatal error!' );
  end

  if ( all ( e(1:3) == 0 ) )

    integral = 2.0 * sqrt ( pi^3 ) / gamma ( 1.5 );

  elseif ( any ( mod ( e(1:3), 2 ) == 1 ) )

    integral = 0.0;

  else

    integral = 2.0;

    for i = 1 : 3
      integral = integral * gamma ( 0.5 * ( e(i) + 1 ) );
    end

    integral = integral / gamma ( 0.5 * sum ( e(1:3) + 1 ) );

  end

  return
end


function [R Rx Ry Rz] = angles2rotmat(angles)
% [R Rx Ry Rz] = angles2rotmat(angles)
%
% Convert 3 euler angles into a rotation matrix
%
% angles is a 3x1 vector in radians
% angles(1) - pitch - rotation about x or LR (gamma)
% angles(2) - yaw   - rotation about y or AP (beta)
% angles(3) - roll  - rotation about z or SI (alpha)
% R = Rz*Ry*Rx;
%
% See also: rotmat2angles
% Ref: Craig, Intro to Robotics
%
% $Id: angles2rotmat.m,v 1.4 2011/03/02 00:04:12 nicks Exp $

%
% angles2rotmat.m
%
% Original Author: Doug Greve
% CVS Revision Info:
%    $Author: nicks $
%    $Date: 2011/03/02 00:04:12 $
%    $Revision: 1.4 $
%
% Copyright © 2011 The General Hospital Corporation (Boston, MA) "MGH"
%
% Terms and conditions for use, reproduction, distribution and contribution
% are found in the 'FreeSurfer Software License Agreement' contained
% in the file 'LICENSE' found in the FreeSurfer distribution, and here:
%
% https://surfer.nmr.mgh.harvard.edu/fswiki/FreeSurferSoftwareLicense
%
% Reporting: freesurfer@nmr.mgh.harvard.edu
%

R  = [];
Rx = [];
Ry = [];
Rz = [];
if(nargin ~= 1)
  fprintf('R = angles2rotmat(angles)\n');
  return;
end

gamma = angles(1);
beta  = angles(2);
alpha = angles(3);

Rx = zeros(3,3);
Rx(1,1) = +1;
Rx(2,2) = +cos(gamma);
Rx(2,3) = -sin(gamma);
Rx(3,2) = +sin(gamma);
Rx(3,3) = +cos(gamma);

Ry = zeros(3,3);
Ry(1,1) = +cos(beta);
Ry(1,3) = +sin(beta);
Ry(2,2) = +1;
Ry(3,1) = -sin(beta);
Ry(3,3) = +cos(beta);

Rz = zeros(3,3);
Rz(1,1) = +cos(alpha);
Rz(1,2) = -sin(alpha);
Rz(2,1) = +sin(alpha);
Rz(2,2) = +cos(alpha);
Rz(3,3) = +1;

R = Rz*Ry*Rx;

return;


function [ pp, normal ] = plane_exp2normal_3d ( p1, p2, p3 )

%*****************************************************************************80
%
%% PLANE_EXP2NORMAL_3D converts an explicit plane to normal form in 3D.
%
%  Discussion:
%
%    The explicit form of a plane in 3D is
%
%      the plane through P1, P2 and P3.
%
%    The normal form of a plane in 3D is
%
%      PP, a point on the plane, and
%      N, the unit normal to the plane.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    26 February 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real P1(3), P2(3), P3(3), three points on the plane.
%
%    Output, real PP(3), a point on the plane.
%
%    Output, real NORMAL(3), a unit normal vector to the plane.
%
  dim_num = 3;

  pp(1:dim_num) = p1(1:dim_num);

  normal(1) = ( p2(2) - p1(2) ) * ( p3(3) - p1(3) ) ...
            - ( p2(3) - p1(3) ) * ( p3(2) - p1(2) );

  normal(2) = ( p2(3) - p1(3) ) * ( p3(1) - p1(1) ) ...
            - ( p2(1) - p1(1) ) * ( p3(3) - p1(3) );

  normal(3) = ( p2(1) - p1(1) ) * ( p3(2) - p1(2) ) ...
            - ( p2(2) - p1(2) ) * ( p3(1) - p1(1) );

  norm = sqrt ( sum ( normal(1:dim_num).^2 ) );

  if ( norm == 0.0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'PLANE_EXP2NORMAL_3D - Fatal error!\n' );
    fprintf ( 1, '  The normal vector is null.\n' );
    fprintf ( 1, '  Two points coincide, or nearly so.\n' );
    error ( 'PLANE_EXP2NORMAL_3D - Fatal error!' );
  end

  normal(1:dim_num) = normal(1:dim_num) / norm;

  return
end


function [points] = UniformPointsOnASphere(p,r)
% This function generates a point cloud equally distributed across the
% surface of a sphere.

% Input sanity check
if nargin < 2
    r = 1;
end

% Constants
viewDir = 3;
goldenRatio     = (1 + sqrt(5))/2;
angleIncrement  = pi*2*goldenRatio;

points = [];
for i = 1:numel(viewDir)
    t = i/viewDir;
    inclination = acos(1-2*t);
    azimuth = angleIncrement*i;

    % Convert spherical to cartesian
    x = p(1) + r*sin(inclination)*cos(azimuth);
    y = p(2) + r*sin(inclination)*sin(azimuth);
    z = p(3) + r*cos(inclination);

    % Assign point to matrix
    points(i,:) = [x,y,z];
end

end

%     static BoidHelper () {
%         directions = new Vector3[BoidHelper.numViewDirections];
%
%         float goldenRatio = (1 + Mathf.Sqrt (5)) / 2;
%         float angleIncrement = Mathf.PI * 2 * goldenRatio;
%
%         for (int i = 0; i < numViewDirections; i++) {
%             float t = (float) i / numViewDirections;
%             float inclination = Mathf.Acos (1 - 2 * t);
%             float azimuth = angleIncrement * i;
%
%             float x = Mathf.Sin (inclination) * Mathf.Cos (azimuth);
%             float y = Mathf.Sin (inclination) * Mathf.Sin (azimuth);
%             float z = Mathf.Cos (inclination);
%             directions[i] = new Vector3 (x, y, z);
%         }
%     }