%% OPTI Wiki Code
% A copy of all code on the Wiki that is run before each release to ensure
% compatibility. Also regenerates all plots if required.
clc
clear
clf
%Setup Figure Generation
% Remember to crop all spy plots (3x) + higher D plots (2x)!
figDir = ''; %'C:\OPTIFigs'; %empty to not generate plots
figure(1);
stdsize = [680   558   560   420];
set(gcf,'position',stdsize);
set(gcf,'PaperPositionMode','auto');

%% Basic OPTI Usage
% https://www.inverseproblem.co.nz/OPTI/index.php/GetStart/Basics

% Ex1
% Problem
f = -[6 5]';                %Objective Function (min f'x)
A = [1,4; 6,4; 2, -5];      %Linear Inequality Constraints (Ax <= b)
b = [16;28;6];
lb = [0;0];                 %Bounds on x (lb <= x <= ub)
ub = [10;10];

% Create OPTI Object
Opt = opti('f',f,'ineq',A,b,'bounds',lb,ub)
[x,fval,exitflag,info] = solve(Opt)

% Alt Strategies
Opt = opti('c',f,'ineq',A,b,'bounds',lb,ub);    %c = f

% OR
Opt = opti('grad',f,'ineq',A,b,'bounds',lb,ub); %grad = f

% OR
Opt = opti('f',f,'A',A,'b',b,'bounds',lb,ub);   %individual A,b

% OR
Opt = opti('f',f,'ineq',A,b,'lb',lb,'ub',ub);   %individual lb,ub

% Choosing a Solver
optiSolver
optiSolver('matrix')
optiSolver('LP')
optiSolver('CLP')
optiset

%Specify to use the COIN-OR LP solver CLP
opts = optiset('solver','clp');

%Rebuild the problem passing the options via the 'options' argument
Opt = opti('f',f,'ineq',A,b,'bounds',lb,ub,'options',opts)

optiSolver('config')

% Ex2
% Objective
fun = @(x) 100*(x(2) - x(1)^2)^2 + (1 - x(1))^2;

% Constraints
lb = [-5;-5];
ub = [5;5];

% Initial Starting Guess (Required for Nonlinear Problems)
x0 = [0;0];

% Setup Options
opts = optiset('solver','lbfgsb','display','iter');

% Create OPTI Object
Opt = opti('fun',fun,'bounds',lb,ub,'options',opts)

% Solve!
[x,fval,ef,info] = solve(Opt,x0)
plot(Opt,7,1)  %plot the object, +-7 from the solution and take log(obj)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ex2_plot']);
end

%% MATLAB Optimization Toolbox Overloads
% https://www.inverseproblem.co.nz/OPTI/index.php/GetStart/Overloads

% Ex1
% Problem
f = -[6 5]';                %Objective Function (min f'x)
A = [1,4; 6,4; 2, -5];      %Linear Inequality Constraints (Ax <= b)
b = [16;28;6];
lb = [0;0];                 %Bounds on x (lb <= x <= ub)
ub = [10;10];

% Solve using MATLAB's linprog:
if (exist('linprog.m','file'))
    x = linprog(f,A,b,[],[],lb,ub)
end

% Solve using corresponding OPTI overload:
x = opti_linprog(f,A,b,[],[],lb,ub)

% Ex2
% Objective
f = [2, 3, 7, 7]';
% Constraints
A = [-1, -1, 2, 5;1, -2, -1, -4];
b = [-2; -3];
lb = zeros(4,1);
ub = [30 100 20 1]';

% Integer Constraints
xtype = [2 4];  %variables 1, 3 are continuous, 2, 4 are integer

% Solve using OPTI overload:
x = opti_intlinprog(f,xtype,A,b,[],[],lb,ub)

% Ex3 NLP
% Objective
fun = @(x) sin(x(1) + x(2)) + (x(1) - x(2))^2 - 1.5*x(1) + 2.5*x(2) + 1;
% Constraints
lb = [-1.5;-3];
ub = [4;3];

% Starting Guess
x0 = [0;0];

% Setup Options
opts = optiset('solver','nomad');

% Solve using OPTI overload:
[x,fval] = opti_fmincon(fun,x0,[],[],[],[],lb,ub,[],opts)

%% Linear Program
% https://www.inverseproblem.co.nz/OPTI/index.php/Probs/LP

% Ex 1
% Objective
f = -[6 5]';                %Objective Function Vector (min f'x)

% Constraints
A = [1,4; 6,4; 2,-5];      %Linear Inequality Constraints (Ax <= b)
b = [16;28;6];
lb = [0;0];                 %Bounds on x (lb <= x <= ub)
ub = [10;10];

% Create OPTI Object
Opt = opti('f',f,'ineq',A,b,'bounds',lb,ub)

% Solve the LP problem
[x,fval,exitflag,info] = solve(Opt)

plot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_exlp']);
end

% Ex2
% Load the LP from .mps file
prob = coinRead('maros-r7.mps')

% Examine A matrix
spy(prob.A)

if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_exlpspy']);
end

prob

% Create an OPTI object from the problem structure
Opt = opti(prob)

% Solve the resulting model
[x,fval] = solve(Opt);

% Ex3
% Objective (f'x)
f = -[1 2 3]';

% Row Constraints (rl <= A*x <= ru)
A = sparse([-1  1  1;     %sparse even though all nz
             1 -3  1;
             1  1  1]);
rl = [-Inf;-Inf;40];      %top two rows are only Ax <= b
ru = [20;30;40];

% Bounds (lb <= x <= ub)
lb = [0;0;0];
ub = [40;Inf;Inf];        %x2 and x3 are unbounded above

% Setup Options
opts = optiset('solver','clp'); %CLP is a row constraint solver

% Build OPTI Object
Opt = opti('f',f,'lin',A,rl,ru,'bounds',lb,ub,'options',opts)

% Solve Problem
[x,fval] = solve(Opt)

% Ex4
% Objective (f'x)
f = -[1 2 3]';

% Linear Constraints
A = sparse([-1  1  1;     %sparse even though all nz
            -1  3 -1;     %note this row inverted just for example purposes
             1  1  1]);
b = [20;-30;40];
e = [-1;1;0]; %-1 <=, 0 ==, 1 >=

% Bounds (lb <= x <= ub)
lb = [0;0;0];
ub = [40;Inf;Inf];        %x2 and x3 are unbounded above

% Setup Options
opts = optiset('solver','clp'); %CLP is a row constraint solver

% Build OPTI Object
Opt = opti('f',f,'mix',A,b,e,'bounds',lb,ub,'options',opts)

% Solve Problem
[x,fval] = solve(Opt)

% Ex5
% Objective (f'x + objbias)
f = -[6 5]';
objbias = 5;

% Linear Constraints (A*x <= b)
A = [1,4; 6,4; 2, -5];
b = [16;28;6];

% Bounds (lb <= x <= ub)
lb = [0;0]; ub = [10;10];

% Build OPTI Object
Opt = opti('f',f,'objbias',objbias,'ineq',A,b,'bounds',lb,ub)

% Solve Problem
[x,fval] = solve(Opt)

%% MILP
% https://www.inverseproblem.co.nz/OPTI/index.php/Probs/MILP

% Ex1
% Objective
f = -[6 5]';                %Objective Function Vector (min f'x)

% Constraints
A = [1,4; 6,4; 2, -5];      %Linear Inequality Constraints (Ax <= b)
b = [16;28;6];
lb = [0;0];                 %Bounds on x (lb <= x <= ub)
ub = [10;10];

% Integer Constraints
xtype = 'II';               %x1 & x2 are Integer
% Create OPTI Object
Opt = opti('f',f,'ineq',A,b,'bounds',lb,ub,'xtype',xtype)

% Solve the MILP problem
[x,fval,exitflag,info] = solve(Opt)
plot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_exmilp']);
end

%Ex 2
xtype = 'CBI';
xtype = [2 3];

% Ex3
% Load the MILP from .mps file
prob = coinRead('testMILP2.mps')

% Examine A matrix
spy(prob.A)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_exmilpspy']);
end

% Create an OPTI object from the problem structure
Opt = opti(prob)

% Solve the resulting model
[x,fval] = solve(Opt)

% Ex4
% Objective (f'x)
f = [-1 -1 -3 -2 -2]';

% Row Constraints (rl <= A*x <= ru)
A = sparse([-1 -1  1  1  0;     %sparse A
             1  0  1 -3  0]);
rl = [-Inf;-Inf];
ru = [30;30];

% Bounds (lb <= x <= ub)
lb = [0;0;0;0;0];
ub = [40;1;Inf;Inf;1];

% SOS
sos_type = '1';
sos_index = [1 2 3 4 5]';
sos_weight = [1 2 3 4 5]';

% Setup Options
opts = optiset('solver','cbc'); %CBC is a SOS constraint solver

% Build OPTI Object
Opt = opti('f',f,'lin',A,rl,ru,'bounds',lb,ub,'sos',sos_type,sos_index,...
           sos_weight,'options',opts)

% Solve Problem
[x,fval] = solve(Opt)

% SOS Structure
sos.type = '12'; %each character represents a SOS set
sos.index = {[1 2]' [3:5]'};
sos.weight = {[1 2]' [1:3]'};

% Build OPTI Object
Opt = opti('f',f,'lin',A,rl,ru,'bounds',lb,ub,'sos',sos,'options',opts)

% Ex5
% Objective
nC = 10; %Number of Continuous Variables
nI = 10; %Number of Integer Variables
nB = 10; %Number of Binary Variables

% Build xtype vector
xtype = [repmat('C',1,nC),repmat('I',1,nI),repmat('B',1,nB)]

%% SDP
% https://www.inverseproblem.co.nz/OPTI/index.php/Probs/SDP

% Ex1
% Objective
f = 1;

% Semidefinite Constraint
F0 = -[0 sqrt(2); sqrt(2) 0];
F1 = eye(2);
sdcone = sparse([F0(:) F1(:)]);
% Create OPTI Object
Opt = opti('f',f,'sdcone',sdcone)

% Solve the QP problem
[x,fval,exitflag,info] = solve(Opt)

% Ex2
% Objective
f = [1;1];
% Bounds on x (lb <= x <= ub)
lb = [0;0];
ub = [10;10];
% Semidefinite Constraint (using alternative notation)
C = -[0 2; 2 0];
A1 = [1 0; 0 0];
A2 = [0 0; 0 1];
sdcone = sparse([C(:) A1(:) A2(:)]);

% Options
opts = optiset('solver','dsdp','display','iter');

% Create OPTI Object
Opt = opti('f',f,'bounds',lb,ub,'sdcone',sdcone,'options',opts)

% Solve the bounded SDP
[x,f] = solve(Opt)
plot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ex2sdp']);
end

% Ex 3
clear sdcone
% Objective
f = [1;0;0;0];
% Semidefinite Constraint 1
F0 = zeros(2);
F1 = eye(2);
F2 = -[1 0; 0 0];
F3 = -[0 1; 1 0];
F4 = -[0 0; 0 1];
sdcone{1} = [F0 F1 F2 F3 F4];
% Semidefinite Constraint 2
F0 = [1 0.2; 0.2 1];
F1 = zeros(2);
F2 = [1 0; 0 0];
F3 = [0 1; 1 0];
F4 = [0 0; 0 1];
sdcone{2} = [F0 F1 F2 F3 F4];

% Options
opts = optiset('solver','csdp','display','iter');

% Create OPTI Object
Opt = opti('f',f,'sdcone',sdcone,'options',opts)

% Solve the SDP
[x,f] = solve(Opt)

%Ex 4
% Load SeDuMi problem variables from MAT file
load sdp_truss1.mat

% Options
opts = optiset('display','iter');

% Create OPTI Object from SeDuMi Args
Opt = opti('sedumi',At,b,c,K,'options',opts)

% Solve the SDP
if(~isempty(which('sedumi.m')))
    [x,f] = solve(Opt)
end

%% QP
% https://www.inverseproblem.co.nz/OPTI/index.php/Probs/QP

% Ex 1
% Objective
H = [1 -1; -1  2];          %Objective Function (min 0.5x'Hx + f'x)
f = -[2 6]';

% Constraints
A = [1,1; -1,2; 2, 1];      %Linear Inequality Constraints (Ax <= b)
b = [2;2;3];
lb = [0;0];                 %Bounds on x (lb <= x)
% Create OPTI Object
Opt = opti('qp',H,f,'ineq',A,b,'lb',lb)

% Solve the QP problem
[x,fval,exitflag,info] = solve(Opt)
plot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_exqp']);
end

%Ex2
% Load the QP from .qps file
prob = coinRead('MPCqp1.qps')

% Examine A matrix
spy(prob.A')
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ex2qpspy']);
end

% Create an OPTI object from the problem structure
Opt = opti(prob)

% Solve the resulting model
[x,fval] = solve(Opt)

e = eig(H)

% Ex 3 Plots
data.d = [1 1]; data.name = 'Positive Definite QP';
opti_wikiplot('qp',data)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_pdqp']);
end

data.d = [-1 -1]; data.name = 'Negative Definite QP';
opti_wikiplot('qp',data)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ndqp']);
end

data.d = [0 1]; data.name = 'Positive Semi-Definite QP';
opti_wikiplot('qp',data)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_psdqp']);
end

data.d = [-1 1]; data.name = 'Indefinite QP';
opti_wikiplot('qp',data)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_idqp']);
end

% Ex 4
%Problem
H = [0 -2; -2 0];           %Objective Function (min 1/2x'Hx + f'x)
f = [0 0]';
lb = [-0.5;-0.5];           %Bounds on x (lb <= x <= ub)
ub = [1;1];

% Options
opts = optiset('solver','clp');

% Create OPTI Object
Opt = opti('qp',H,f,'bounds',lb,ub,'options',opts)

% Solve the Indefinite QP
[x,f,~,info] = solve(Opt)

plot(Opt,1.5)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ex2qp']);
end

%% MIQP
% https://www.inverseproblem.co.nz/OPTI/index.php/Probs/MIQP

% Ex 1
% Objective
H = [1 -1; -1  2];          %Objective Function (min 0.5x'Hx + f'x)
f = -[2 6]';

% Constraints
A = [1,1; -1,2; 2, 1];      %Linear Inequality Constraints (Ax <= b)
b = [2;2;3];
lb = [0;0];                 %Bounds on x (lb <= x)

% Integer Constraints
xtype = 'IC';

% Create OPTI Object
Opt = opti('qp',H,f,'ineq',A,b,'lb',lb,'xtype',xtype)

% Solve the MIQP problem
[x,fval,exitflag,info] = solve(Opt)

plot(Opt,2)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_exmiqp']);
end

%% QCQP
% https://www.inverseproblem.co.nz/OPTI/index.php/Probs/QCQP

% Ex1
% Objective
H = eye(2);                 %Objective Function (min 0.5x'Hx + f'x)
f = -[2 2]';

% Linear Constraints
A = [-1,1; 1,3];            %Linear Inequality Constraints (Ax <= b)
b = [2;5];
lb = [0;0];                 %Bounds on x (lb <= x)

% Quadratic Constraint
Q = [1 0; 0 1];             %Quadratic Inequality (x'Qx + l'x <= r)
l = [0;-2];
r = 1;
% Create OPTI Object
Opt = opti('qp',H,f,'ineq',A,b,'lb',lb,'qc',Q,l,r)

% Solve the QCQP problem
[x,fval,exitflag,info] = solve(Opt)

plot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_exqcqp']);
end

%Ex 2
% Objective
H = eye(2);                 %Objective Function (min 0.5x'Hx + f'x)
f = -[2 2]';

% Linear Constraints
A = [-1,1; 1,3];            %Linear Inequality Constraints (Ax <= b)
b = [2;5];
lb = [0;0];                 %Bounds on x (lb <= x)

% Quadratic Constraints
Q = {[1 0; 0 1]             %Quadratic Inequalities (x'Qx + l'x <= r)
     [1 0; 0 1]};
l = [[0;-2] [-1;2]];
r = [1;1.2];

% Create OPTI Object
Opt = opti('qp',H,f,'ineq',A,b,'lb',lb,'qc',Q,l,r)

% Solve the QCQP problem
[x,fval,exitflag,info] = solve(Opt)

% Plot Solution
plot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ex2qcqp']);
end

%Ex3
% Objective
H = eye(2);                 %Objective Function (min 0.5x'Hx + f'x)
f = -[2 2]';

% Linear Constraints
A = [-1,1; 1,3];            %Linear Inequality Constraints (Ax <= b)
b = [2;5];
lb = [0;0];                 %Bounds on x (lb <= x)

% Quadratic Constraints
Q = {[1 0; 0 1]             %Quadratic Inequalities (x'Qx + l'x <= r)
     [1 0; 0 1]};
l = {[0;-2]; [-1;2]};
r = {1; 1.2};

% Create OPTI Object
Opt = opti('qp',H,f,'ineq',A,b,'lb',lb,'qc',Q,l,r)

% Solve the QCQP problem
[x,fval,exitflag,info] = solve(Opt)

% Plot Solution
plot(Opt)

% Ex4
% Objective
H = eye(2);                 %Objective Function (min 0.5x'Hx + f'x)
f = -[2 2]';

% Linear Constraints
A = [-1,1; 1,3];            %Linear Inequality Constraints (Ax <= b)
b = [2;3.8];
lb = [0;0];                 %Bounds on x (lb <= x)
ub = [40;inf];

% Quadratic Constraints
Q = [0 0; 0 10];            %Quadratic Inequalities (x'Qx + l'x <= r)
l = [0;-2];
r = 3

% Set OPTI Options
opts = optiset('solver','ipopt','display','iter');

% Create OPTI Object
Opt = opti('qp',H,f,'ineq',A,b,'bounds',lb,ub,'qc',Q,l,r,'options',opts)

% Solve the QCQP problem [as an NLP]
[x,fval,exitflag,info] = solve(Opt)

% Plot Solution
plot(Opt,3)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ex4qcqp']);
end

% Ex5
% Objective
H = eye(2);                 %Objective Function (min 0.5x'Hx + f'x)
f = -[2 2]';

% Linear Constraints
A = [-1,1; 1,3];            %Linear Inequality Constraints (Ax <= b)
b = [2;5];
lb = [0;0];                 %Bounds on x (lb <= x)

% Quadratic Constraints
Q = {[1 0; 0 1]             %Quadratic Constraints (qrl <= x'Qx + l'x <= qru)
     [1 0; 0 1]};
l = {[0;-2]; [-2;2]};
qrl = {3; 1};               %QC1 is double sided, QC2 is an equality
qru = {5; 1};

% Create OPTI Object
Opt = opti('qp',H,f,'ineq',A,b,'lb',lb,'qcrow',Q,l,qrl,qru)

% Solve the QCQP problem
[x,fval,exitflag,info] = solve(Opt)

% Plot Solution
plot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ex5qcqp']);
end

%% MIQCQPs
% https://www.inverseproblem.co.nz/OPTI/index.php/Probs/MIQCQP

%Ex1
% Objective
H = eye(2);                 %Objective Function (min 0.5x'Hx + f'x)
f = -[2 2]';

% Constraints
A = [-1,1; 1,3];            %Linear Inequality Constraints (Ax <= b)
b = [2;5];
lb = [0;0];                 %Bounds on x (lb <= x)

% Quadratic Constraint
Q = [1 0; 0 1];             %Quadratic Inequality (x'Qx + l'x <= r)
l = [0;-2];
r = 1;

% Integer Constraints
xtype = 'IC';
% Create OPTI Object
Opt = opti('qp',H,f,'ineq',A,b,'lb',lb,'qc',Q,l,r,'xtype',xtype)

% Solve the MIQCQP problem
[x,fval,exitflag,info] = solve(Opt)
plot(Opt,3)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_exmiqcqp']);
end

%% SNLE
% https://www.inverseproblem.co.nz/OPTI/index.php/Probs/SNLE

% Ex 1
% System of Nonlinear Equations
nleq = @(x) [ 2*x(1) - x(2) - exp(-x(1));
            -x(1) + 2*x(2) - exp(-x(2))];

% Starting Guess
x0 = [-5;5];
% Create OPTI Object
Opt = opti('nleq',nleq,'x0',x0)

% Solve the SNLE problem
[x,fval,exitflag,info] = solve(Opt)
plot(Opt,[],1)

optiSolver('SNLE')

% Ex2
% System of Nonlinear Equations
nleq = @(x) [10*(x(2) - x(1)^2)
            sqrt(90)*(x(4) - x(3)^2)
            sqrt(10)*(x(2) + x(4) - 2)
            (1/sqrt(10))*(x(2) - x(4))];

% Nonlinear Equations Jacobian
nlJac = @(x) sparse([-20*x(1),10,0,0
                     0,0,-6*10^(1/2)*x(3),3*10^(1/2)
                     0,10^(1/2),0,10^(1/2)
                     0,10^(1/2)/10,0,-10^(1/2)/10]);

% Jacobian Sparsity Pattern
nlJacstr = @() sparse([1 1 0 0
                       0 0 1 1
                       0 1 0 1
                       0 1 0 1]);

% Starting Guess
x0 = [-30;-10;-30;-10];

% Sparse SNLE OPTI Problem
Opt = opti('nleq',nleq,'nlJac',nlJac,'nlJacstr',nlJacstr,'x0',x0)

% Solve
[x,fval,exitflag,info] = solve(Opt)

%% SCNLE
% https://www.inverseproblem.co.nz/OPTI/index.php/Probs/SCNLE

% Ex1
% System of Nonlinear Equations
nleq = @(x) [ 2*x(1) - x(2) - exp(-x(1));
            -x(1) + 2*x(2) - exp(-x(2))];

% Bounds
lb = [0.6;0];
ub = [1;1];

% Starting Guess
x0 = [-5;5];
% Create OPTI Object
Opt = opti('nleq',nleq,'bounds',lb,ub,'x0',x0)

% Solve the SCNLE problem
[x,fval,exitflag,info] = solve(Opt)
plot(Opt,0.75,1)

%% NLS
% https://www.inverseproblem.co.nz/OPTI/index.php/Probs/NLS

% Ex1
% Objective (Fitting) Function
fun = @(x) [100*(x(2)-x(1)^2); 1 - x(1)];

% Fitting Data
ydata = [0;0];

% Starting Guess
x0 = [-1.2;1];
% Create OPTI Object
Opt = opti('fun',fun,'ydata',ydata,'x0',x0)

% Solve the NLS problem
[x,fval,exitflag,info] = solve(Opt)
plot(Opt,[],1) %tell OPTI to take the log of the objective for detail

% Ex2
% Objective (Fitting) Function
fun = @(x) [100*(x(2)-x(1)^2); 1 - x(1)];

% Fitting Data
ydata = [0;0];

% Bounds
lb = [-2;-2];
ub = [0.5;0.5];

% Starting Guess
x0 = [-1.2;-2];

% Create OPTI Object
Opt = opti('fun',fun,'ydata',ydata,'bounds',lb,ub,'x0',x0)

% Solve using MKLTRNLS (auto-selected)
[x,fval,exitflag,info] = solve(Opt)

% Ex3
% Objective (Fitting) Function
fun = @(x,xdata) x(1)*exp(x(2)*xdata);

% Fitting Data
xdata = [0.9 1.5 13.8 19.8 24.1 28.2 35.2 60.3 74.6 81.3]';
ydata = [455.2 428.6 124.1 67.3 43.2 28.1 13.1 -0.4 -1.3 -1.5]';

% Setup Options
opts = optiset('solver','lmder','display','iter');

% Starting Guess
x0 = [100; -1];

% Create OPTI Object
Opt = opti('fun',fun,'data',xdata,ydata,'x0',x0,'options',opts)

% Solve
[x,fval,exitflag,info] = solve(Opt)
plot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ex3nls']);
end

% Ex 4
% Objective (Fitting) Function
i = (1:40)';
fun = @(x) x(1)*exp(-x(2)*i) + x(3);

% Fitting Data
ydata=[5.8728, 5.4948, 5.0081, 4.5929, 4.3574, 4.1198, 3.6843, 3.3642, 2.9742,...
       3.0237, 2.7002, 2.8781, 2.5144, 2.4432, 2.2894, 2.0938, 1.9265, 2.1271,...
       1.8387, 1.7791, 1.6686, 1.6232, 1.571, 1.6057,1.3825, 1.5087, 1.3624,...
       1.4206, 1.2097, 1.3129, 1.131, 1.306, 1.2008, 1.3469, 1.1837, 1.2102,...
       0.96518, 1.2129, 1.2003, 1.0743];;

% Weighting Vector
wts = ones(size(ydata)); wts(end) = 1e3;

% Starting Guess
x0 = [1.0; 0.0; 0.0];

% Create OPTI Objects for both Weighted and Un-weighted Cases
OptW = opti('fun',fun,'ydata',ydata,'weights',wts,'x0',x0);
Opt = opti('fun',fun,'ydata',ydata,'x0',x0);

% Solve Each Case
xw = solve(OptW)
x = solve(Opt)

% Plot Comparison
plot(i,ydata,'ko',i(end),ydata(end),'ksq',i,fun(xw),'r*-',i,fun(x),'m*-')
xlim([length(i)*0.45 length(i)*1.01]); xlabel('i'); ylabel('y');
legend('Original Data','Target Point','Weighted Fit','Standard Fit');
title('NLS Curve Fit - Comparison of Weighted and Un-Weighted');
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ex4nlswt']);
end

%Ex 5
% Objective (Fitting) Function
fun = @(x) [100*(x(2)-x(1)^2); 1 - x(1)];

% Objective Gradient (Matrix in NLS case)
grad = @(x) [-200*x(1),100; -1,0];

% Fitting Data
ydata = [0;0];

% Starting Guess
x0 = [-1.2;1];
% Create OPTI Object
Opt = opti('fun',fun,'grad',grad,'ydata',ydata,'x0',x0)

% Solve the NLS problem
[x,fval,exitflag,info] = solve(Opt)

% Ex6
% Fitting Function
fun = @(x,xdata) x(1)*exp(x(2)*xdata);

% Fitting Data
xdata = [0.9 1.5 13.8 19.8 24.1 28.2 35.2 60.3 74.6 81.3]';
ydata = [455.2 428.6 124.1 67.3 43.2 28.1 13.1 -0.4 -1.3 -1.5]';

% Setup Options
opts = optiset('solver','nomad','display','iter');

% Starting Guess
x0 = [100; -1];

% Create OPTI Object
Opt = opti('fun',fun,'data',xdata,ydata,'x0',x0,'options',opts)

% Solve
[x,fval,exitflag,info] = solve(Opt)

%Ex7
% Fitting Function
Rxn_rate = @(theta,p) theta(1)*p./(1+theta(2)*p);

% Fitting Data
p = [20,30,35,40,50,55,60]'; % Pressure
r = [0.068,0.0858,0.0939,0.0999,0.1130,0.1162,0.1190]'; % Reaction rate

% Starting Guess
x0 = [5e-3; 2e-2];

% Create OPTI Object
Opt = opti('fun',Rxn_rate,'data',p,r,'x0',x0)

% Solve
[x,fval,exitflag,info] = solve(Opt)

% Calculate fit statistics
fitStats(Opt)

% Plot solution with statistics
plot(Opt)
h = legend;
set(h,'location','northwest');
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_fitstats']);
end

%% DNLS
% https://www.inverseproblem.co.nz/OPTI/index.php/Dynamic/DynamicSystemParameterEstimation

%Ex1
% ODE System
ode = @(t,z,p) [-p(1)*z(1) + 4;
                2*z(1) - p(1)*z(2) + 5;
                -4*z(1) - 2*z(2)*z(3) - p(2)];

% Initial Conditions
z0 = [-1.5;1.25;1];

% True Parameter Values
p = [2.345;1.1];

% Generate Fitting Data
tm  = 0:0.1:2;                 %measurement times
odeInt = @(t,z) ode(t,z,p);    %ODE function for ODE45
[~,zm] = ode45(odeInt,tm,z0);  %Solve ODEs
% Starting Guess
theta0 = [1;0.5];

% Create OPTI Object
Opt = opti('ode',ode,'data',tm,zm,'z0',z0,'theta0',theta0)

% Solve
[theta,fval,exitflag,info] = solve(Opt)

% Plot the Solution
plot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ex1dnls']);
end

%Ex2
% Indicate Initial Conditions to Solve for Using NaNs
z0 = [-1.5;NaN;NaN];
% Starting Guess [p;z0]
theta0 = [1;0.5;0.5;0.5];

% Create OPTI Object
Opt = opti('ode',ode,'data',tm,zm,'z0',z0,'theta0',theta0)

% Solve
[theta,fval,exitflag,info] = solve(Opt)

% Plot the Solution
plot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ex2dnls']);
end

%Ex3
% Add Bounds
lb = [1.5;0;0.1;0.1];
ub = [3.5;2;1.5;1.5];

% Create OPTI Object
Opt = opti('ode',ode,'data',tm,zm,'bounds',lb,ub,'z0',z0,'theta0',theta0)

% Solve
[theta,fval,exitflag,info] = solve(Opt)

%Ex4
% Set Dynamic Options (specifying states of interest)
dopts = optidynset('stateIndex',[2 3]);

% Add to General OPTI Options
opts = optiset('display','iter','dynamicOpts',dopts);

% Index Measured Data
zm23 = zm(:,[2 3]);
% Create OPTI Object
Opt = opti('ode',ode,'data',tm,zm23,'z0',z0,'theta0',theta0,'options',opts)

% Solve
[theta,fval,exitflag,info] = solve(Opt)

% Plot the Solution
plot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ex3dnls']);
end

%Ex5
% Initial Conditions (re-initialize)
z0 = [-1.5;1.25;1];

% Measurement Times for each State
tm2  = 0:0.1:2;                %state 2
tm3  = 0.2:0.2:2;              %state 3

% Solve ODEs and index Measurement Data
[~,zm2] = ode45(odeInt,tm2,z0); zm2 = zm2(:,2);
% Note 0 is required below just to match initial condition in this example
[~,zm3] = ode45(odeInt,[0 tm3],z0); zm3 = zm3(2:end,3); %drop first point

% Group measurements and time stamps in cell arrays
tm_multi = {tm2;tm3};
zm_multi = {zm2;zm3};
% Return z0 to include NaNs of estimated initial conditions
z0 = [-1.5;NaN;NaN];

% Create OPTI Object
Opt = opti('ode',ode,'data',tm_multi,zm_multi,'z0',z0,'theta0',theta0,...
           'options',opts)

% Solve
[theta,fval,exitflag,info] = solve(Opt)

% Plot the Solution
plot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ex4dnls']);
end

%Ex6
% Initial Conditions (re-initialize)
z0 = [-1.5;1.25;1];

% Measurement Times for each State
tm1  = 0.5:0.1:2;              %state 1
tm2  = 1:0.1:2;                %state 2
tm3  = 0.2:0.2:2;              %state 3

% Solve ODEs and index Measurement Data
% Note 0 is required below just to match initial condition in this example
[~,zm1] = ode45(odeInt,[0 tm1],z0); zm1 = zm1((2:end),1);
[~,zm2] = ode45(odeInt,[0 tm2],z0); zm2 = zm2((2:end),2);
[~,zm3] = ode45(odeInt,[0 tm3],z0); zm3 = zm3((2:end),3);

% Group measurements and time stamps in cell arrays
tm_multi = {tm1;tm2;tm3};
zm_multi = {zm1;zm2;zm3};
% We will need to estimate all initial conditions in this problem
z0 = [NaN;NaN;NaN];

% New Initial Guess Vector [p;z0];
theta0 = [1;0.5;0.5;0.5;0.5];

% Tell OPTI we want to solve from t = 0
dopts = optidynset('initialT',0);
opts = optiset('display','iter','dynamicOpts',dopts);

% Create OPTI Object
Opt = opti('ode',ode,'data',tm_multi,zm_multi,'z0',z0,'theta0',theta0,...
           'options',opts)

% Solve
[theta,fval,exitflag,info] = solve(Opt)

% Plot the Solution
plot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ex6tdnls']);
end

%Ex7
% Initial Conditions (re-initialize)
z0 = [-1.5;1.25;1];

% New ODE with modified parameters (representing a different run)
odeIntB = @(t,z) ode(t,z,p*0.85);

% Measurement Times for each State
tm1  = 0.5:0.1:2;              %state 1
tm1b = 1:0.25:2;               %state 1 2nd run
tm2  = 1:0.1:2;                %state 2
tm3  = 0.2:0.2:2;              %state 3

% Solve ODEs and index Measurement Data
% Note 0 is required below just to match initial condition in this example
[~,zm1]  = ode45(odeInt, [0 tm1], z0);  zm1  = zm1((2:end),1);
[~,zm1b] = ode45(odeIntB,[0 tm1b],z0);  zm1b = zm1b((2:end),1); %2nd run
[~,zm2]  = ode45(odeInt, [0 tm2], z0);  zm2  = zm2((2:end),2);
[~,zm3]  = ode45(odeInt, [0 tm3], z0);  zm3  = zm3((2:end),3);
[~,zm3b] = ode45(odeInt, [0 tm3], z0*0.75); zm3b = zm3b((2:end),3); %2nd run

% Group measurements and time stamps in cell arrays
tm_multi = {[tm1 tm1b];tm2;[tm3 tm3]}; %concatenate repeated points
zm_multi = {[zm1;zm1b];zm2;[zm3;zm3b]};
% We will need to estimate all initial conditions in this problem
z0 = [NaN;NaN;NaN];

% New Initial Guess Vector [p;z0];
theta0 = [1;0.5;0.5;0.5;0.5];

% Tell OPTI we want to solve from t = 0
dopts = optidynset('initialT',0);
opts = optiset('display','iter','dynamicOpts',dopts);

% Create OPTI Object
Opt = opti('ode',ode,'data',tm_multi,zm_multi,'z0',z0,'theta0',theta0,...
           'options',opts)

% Solve
[theta,fval,exitflag,info] = solve(Opt)

% Plot the Solution
plot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ex7dnls']);
end

%Ex8
if (exist('syms.m'))
    % Declare Symbolic Variables
    syms p1 p2 z1 z2 z3

    % Symbolic ODE RHS
    ODE = [-p1*z1 + 4;
           2*z1 - p1*z2 + 5;
           -4*z1 - 2*z2*z3 - p2];

    % Solve Jacobians
    dfdz_sym = jacobian(ODE,[z1 z2 z3])
    dfdp_sym = jacobian(ODE,[p1 p2])
    % ODE System
     ode = @(t,z,p) [-p(1)*z(1) + 4;
                     2*z(1) - p(1)*z(2) + 5;
                     -4*z(1) - 2*z(2)*z(3) - p(2)];

    % Simple Symbolic + String Parsing Derivative Generation
    [dfdz,dfdp] = symDynJac(ode)
    % Analytical Derivative Expressions
    dfdz = @(t,z,p) [-p(1) 0,       0;
                     2,    -p(1),   0;
                     -4,   -2*z(3), -2*z(2)];
    dfdp = @(t,z,p) [-z(1), 0;
                     -z(2), 0;
                     0,    -1];

    % Set Dynamic Options
    dopts = optidynset('dfdz',dfdz,'dfdp',dfdp,'initialT',0);

    % General OPTI Options
    opts = optiset('display','iter','derivCheck','on','dynamicOpts',dopts);

    % Create OPTI Object
     Opt = opti('ode',ode,'data',tm_multi,zm_multi,'z0',z0,'theta0',theta0,...
                'options',opts)

    % Solve
    [theta,fval,exitflag,info] = solve(Opt)

    % Plot the Solution
    plot(Opt)
end

% Ex9
% Flame ODE System
ode = @(t,z,p) p(1)*z(1)^2 - z(1)^3;

% Initial Condition (Controls Stiffness)
z0 = 0.001;

% True Parameter
p = 1.5;

% Generate Fitting Data
tm  = [0 65:70 80:0.1:90 100]*10;  %measurement times
odeInt = @(t,z) ode(t,z,p);        %ODE function for ODE15S
[~,zm] = ode15s(odeInt,tm,z0);     %Solve ODE
% Starting Guess
theta0 = 1;

% Set Options (use ode15s)
dopts = optidynset('sensitivity','none');
opts1 = optiset('display','iter','iterfun',@optiplotlogfval,'dynamicOpts',dopts);
opts2 = optiset('display','iter','iterfun',@optiplotlogfval);

% Create OPTI Objects
OptNoDer = opti('ode',ode,'data',tm,zm,'z0',z0,'theta0',theta0,'options',opts1)
OptWDer = opti('ode',ode,'data',tm,zm,'z0',z0,'theta0',theta0,'options',opts2)

% Solve
[theta,fval,exitflag,info] = solve(OptNoDer)
[theta,fval,exitflag,info] = solve(OptWDer)

% Plot the Solution
subplot(121); plot(OptNoDer); title('No Sensitivity');
subplot(122); plot(OptWDer); title('With Sensitivity');
clf %NOT WORKING IN 2014B - well, working too well...

clc
% Partial Derivatives
dfdz = @(t,z,p) 2*p(1)*z(1) - 3*z(1)^2;
dfdp = @(t,z,p) z(1)^2;

% Set Dynamic Options
dopts = optidynset('dfdz',dfdz,'dfdp',dfdp,'integrator','ode15s',...
                   'sensitivity','User');

% General OPTI Options
opts = optiset('display','iter','derivCheck','on','dynamicOpts',dopts);

% Create OPTI Object
Opt = opti('ode',ode,'data',tm,zm,'z0',z0,'theta0',theta0,'options',opts)

% Solve
[theta,fval,exitflag,info] = solve(Opt)

% Set Dynamic Options
dopts = optidynset('integrator','ode15s','sensitivity','None');

% General OPTI Options
opts = optiset('solver','nomad','display','iter','dynamicOpts',dopts);

% Create OPTI Object (always set finite bounds for derivative free)
Opt = opti('ode',ode,'data',tm,zm,'bounds',0.5,2.5,'z0',z0,...
           'theta0',theta0,'options',opts)

% Solve
[theta,fval,exitflag,info] = solve(Opt)

%% NLP
% https://www.inverseproblem.co.nz/OPTI/index.php/Probs/NLP

%Ex1
% Objective
fun = @(x) log(1 + x(1)^2) - x(2);    %Objective Function Vector (min f(x))

% Nonlinear Constraints
nlcon = @(x) (1 + x(1)^2)^2 + x(2)^2; %Nonlinear Equality Constraint
nlrhs = 4;
nle = 0;                              %Constraint type: -1 <=, 0 ==, 1 >=

% Create OPTI Object
Opt = opti('fun',fun,'nlmix',nlcon,nlrhs,nle,'ndec',2)

% Solve the NLP problem
x0 = [2;2] %Initial Guess
[x,fval,exitflag,info] = solve(Opt,x0)

plot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_exnlp']);
end

%Ex2
% Objective
fun = @(x) x(1)*x(4)*(x(1) + x(2) + x(3)) + x(3);

% Nonlinear Constraints (cl <= nlcon(x) <= cu)
nlcon = @(x) [ x(1)*x(2)*x(3)*x(4);
               x(1)^2 + x(2)^2 + x(3)^2 + x(4)^2 ];
cl = [25;40];
cu = [Inf;40];

% Bounds (lb <= x <= ub)
lb = ones(4,1);
ub = 5*ones(4,1);

% Initial Guess
x0 = [1 5 5 1]';

% Options
opts = optiset('solver','ipopt','display','iter');

% Build OPTI Problem
Opt = opti('fun',fun,'nl',nlcon,cl,cu,'bounds',lb,ub,'x0',x0,'options',opts)

% Solve NLP
[x,fval,exitflag,info] = solve(Opt)

%Ex3
% Objective
fun = @(x) (x(1) - x(2))^2 + (x(2) + x(3) - 2)^2 + (x(4) - 1)^2 + (x(5) - 1)^2;

% Linear Equality Constraints
Aeq = [1 3 0 0 0;
       0 0 1 1 -2;
       0 1 0 0 -1];
beq = [4;0;0];

% Starting Guess
x0 = [ 2.5 0.5 2 -1 0.5 ];

% Options
opts = optiset('solver','ipopt');

% Create OPTI Object
Opt = opti('fun',fun,'eq',Aeq,beq,'options',opts)

% Solve using IPOPT
[x,fval,exitflag,info] = solve(Opt,x0)

%Ex4
% Objective
fun = @(x) 100*(x(2) - x(1)^2)^2 + (1 - x(1))^2;

% Starting Guess
x0 = [0;0];

% Create OPTI Object
Opt = opti('fun',fun,'x0',x0)

% Solve
[x,fval,exitflag,info] = solve(Opt)

%Ex5
% Objective
fun = @(x) log(1 + x(1)^2) - x(2);

% Objective Gradient (row vector)
grad = @(x) [2*x(1)/(x(1)^2+1) -1];

% Nonlinear Constraints
nlcon = @(x) (1 + x(1)^2)^2 + x(2)^2;
nlrhs = 4;
nle = 0;

% Constraint Jacobian (matrix, one row per constraint)
jac = @(x) [4*x(1)*(x(1)^2+1), 2*x(2)];
% Create OPTI Object
Opt = opti('fun',fun,'grad',grad,'nlmix',nlcon,nlrhs,nle,'jac',jac,'ndec',2)

% Solve the NLP problem
x0 = [2;2] %Initial Guess
[x,fval,exitflag,info] = solve(Opt,x0)

% Ex6
% Objective
fun = @RiemannND;

% Bounds
lb = 0.5;
ub = 2;

% Starting Guess
x0 = 0.5;

% Options
opts = optiset('solver','ipopt');

% Create OPTI Object
Opt = opti('fun',fun,'bounds',lb,ub,'options',opts)

% Attempt to Solve
% [x,fval,exitflag,info] = solve(Opt,x0)

clf;
opti_wikiplot('riemann');
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ex2nlpa']);
end
clf;

% Ex6b

% Fitting Functions
ffun = @(x) [x(1) - sin(2*x(1) + 3*x(2)) - cos(3*x(1) - 5*x(2));
             x(2) - sin(x(1) - 2*x(2)) + cos(x(1) + 3*x(2))];
% Objective
fun = @(x) norm(ffun(x));
% Bounds
lb = [-4;-4];
ub = [4;4];

% Starting Guess
x0 = [0;-3];

% Options
opts = optiset('solver','ipopt');

% Create OPTI Object
Opt = opti('fun',fun,'bounds',lb,ub,'options',opts)

% Attempt to Solve
[x,fval,exitflag,info] = solve(Opt,x0)
clf;
opti_wikiplot('wolfram');
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ex2nlpb']);
end
clf;

%% GNLP
% https://www.inverseproblem.co.nz/OPTI/index.php/Probs/GNLP

%Ex1
% Objective
fun = @(x) norm([x(1) - sin(2*x(1) + 3*x(2)) - cos(3*x(1) - 5*x(2));
                 x(2) - sin(x(1) - 2*x(2)) + cos(x(1) + 3*x(2))]);

% Bounds
lb = [-4;-4];
ub = [4;4];

% Initial Solution
x0 = [-4;-4];

% Build optiprob structure (intermediate structure)
prob = optiprob('fun',fun,'bounds',lb,ub,'x0',x0);

% Setup solver options
opts1 = optiset('solver','nomad');
opts2 = optiset('solver','pswarm');
opts3 = optiset('solver','nlopt','solverOpts',nloptset('algorithm','GN_DIRECT'));
opts4 = optiset('solver','ipopt','warnings','off');

% Build OPTI objects
Opt1 = opti(prob,opts1);
Opt2 = opti(prob,opts2);
Opt3 = opti(prob,opts3);
Opt4 = opti(prob,opts4);

% Solve the GNLP problems
[x1,fval1] = solve(Opt1,x0);
[x2,fval2] = solve(Opt2,x0);
[x3,fval3] = solve(Opt3,x0);
[x4,fval4] = solve(Opt4,x0);

%Ex2
% Objective
fun = @(x) x^6 - 2.08*x^5 + 0.4875*x^4 + 7.1*x^3 - 3.95*x^2 - x + 0.1;

% Bounds
lb = -1.5;
ub = 1.5;

% Initial Solution
x0 = 0;

% Options
opts = optiset('solver','scip');

% Create OPTI Object
Opt = opti('fun',fun,'bounds',lb,ub,'options',opts)

% Solve using SCIP
[x,fval,exitflag,info] = solve(Opt,x0)

% Plot Solution within Problem Bounds
plot(Opt,[lb ub])
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ex_gnlp_poly']);
end

%% MINLP
% https://www.inverseproblem.co.nz/OPTI/index.php/Probs/MINLP

%Ex1
% Objective
fun = @(x) -x(1) - x(2) - x(3);

% Linear Constraints
A = [1 -1 0 0;
     1  0 1 1];
b = [0;2];

% Nonlinear Constraint
nlcon = @(x) (x(2) - 0.5)^2 + (x(3) - 0.5)^2;
nlrhs = 0.25;
nle = -1; % -1 for <=, 0 for ==, +1 >=

% Bounds
lb = [0;0;0;0];
ub = [1;Inf;Inf;5];

% Integer Constraints
xtype = 'BCCI';

%Initial Guess
x0 = [0;0;0;0];
% Create OPTI Object
Opt = opti('fun',fun,'nlmix',nlcon,nlrhs,nle,'ineq',A,b,'bounds',lb,ub,...
           'xtype',xtype)

% Solve the MINLP problem
[x,fval,exitflag,info] = solve(Opt,x0)

% Ex2
% Objective
fun = @(x) 20 + x(1)^2 + x(2)^2 - 10*(cos(2*pi*x(1)) + cos(2*pi*x(2)))

% Bounds
lb = [5*pi;-20*pi];
ub = [20*pi;-4*pi];

% Integer Constraints
xtype = 'IC';

%Initial Guess
x0 = [16;0];
% Options
opts = optiset('solver','nomad','display','iter')

% Create OPTI Object
Opt = opti('fun',fun,'bounds',lb,ub,'xtype',xtype,'options',opts)

% Solve the MINLP problem
[x,fval,exitflag,info] = solve(Opt,x0)
clf;
opti_wikiplot('rastrigin');
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'plot_ex2minlp']);
end
clf;

%% OPTIFIT
% https://www.inverseproblem.co.nz/OPTI/index.php/Probs/ModelFit

%Ex 1
% Fitting Data
xdata = (1:40)';
ydata = [5.8728, 5.4948, 5.0081, 4.5929, 4.3574, 4.1198, 3.6843, 3.3642, 2.9742, 3.0237,...
         2.7002,2.8781, 2.5144, 2.4432, 2.2894, 2.0938, 1.9265, 2.1271, 1.8387, 1.7791,...
         1.6686, 1.6232, 1.571, 1.6057,1.3825, 1.5087, 1.3624, 1.4206, 1.2097, 1.3129,...
         1.131, 1.306, 1.2008, 1.3469, 1.1837, 1.2102,0.96518, 1.2129, 1.2003, 1.0743]';

% Automatically identify model structure and solve optimal parameters
ofit = optifit(xdata,ydata,'auto')

% Plot the Result
plot(ofit)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ofit_ex1']);
end

% Ex2
% Amount of Substrate
n = [0.26,0.3,0.48,0.5,0.54,0.64,0.82,1.14,1.28,1.38,1.8,2.3,2.44,2.48]';
% Reaction Rate
r = [124.7,126.9,135.9,137.6,139.6,141.1,142.8,147.6,149.8,149.4,153.9,152.5,154.5,154.7]';

% Automatically identify model structure and solve optimal parameters
ofit = optifit(n,r,'auto')

% Plot the Result
plot(ofit)
h = legend;
set(h,'Location','northwest');
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ofit_ex2']);
end

% Ex3
% Fitting Data
p = [20,30,35,40,50,55,60]'; % Pressure
r = [0.068,0.0858,0.0939,0.0999,0.1130,0.1162,0.1190]'; % Reaction rate

% Model
Rxn = @(theta,xdata) theta(1)*xdata./(1+theta(2)*xdata);

% Fit Model Parameters
ofit = optifit(p,r,Rxn,[5e-3 2e-2])

% Plot the Result
plot(ofit)
h = legend;
set(h,'Location','northwest');
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ofit_ex3']);
end

%% Plot
% https://www.inverseproblem.co.nz/OPTI/index.php/Advanced/Plots

%Ex1
% Objective (supplied with OPTI)
fun = @RiemannND;
% Bounds
lb = 0.5; ub = 2;
% Starting Guess
x0 = 1;

% Options
opts = optiset('solver','nomad');
% Create OPTI Object
Opt = opti('fun',fun,'bounds',lb,ub,'x0',x0,'options',opts)

% Plot Problem
plot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ex_plot_1d1']);
end

% Plot Problem within Selected Bounds
plot(Opt,[lb ub])
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ex_plot_1d2']);
end

% Plot Problem within Selected Bounds, and increased detail
plot(Opt,[lb ub],[],1000)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ex_plot_1d3']);
end

% Solve the problem from improved initial guess
[x,fval] = solve(Opt,1.4)

% Plot the Problem again, this time include solution
plot(Opt,[lb,ub],[],1000)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ex_plot_1d4']);
end

% 2D
% Objective
fun = @(x) 100*(x(2) - x(1)^2)^2 + (1 - x(1))^2;
% Constraints
lb = [-5;-5]; ub = [5;5];
% Initial Starting Guess
x0 = [0;0];

% Setup Options
opts = optiset('solver','lbfgsb');
% Create OPTI Object
Opt = opti('fun',fun,'x0',x0,'bounds',lb,ub,'options',opts)

% Plot
plot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ex_plot_2d1']);
end

% Plot Problem +- 7 from x0
plot(Opt,7)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ex_plot_2d2']);
end

% Plot Problem +- 7 from x0, and log(obj)
plot(Opt,7,true)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ex_plot_2d3']);
end

% 3D
% QP Objective
H = eye(3);
f = -[2 3 1]';
% Linear Constraints
A = [1 1 1;3 -2 -3; 1 -3 2];
b = [1;1;1];
% Integer Constraints
xtype = 'CIC';

%Build & Solve
Opt = opti('qp',H,f,'ineq',A,b,'xtype',xtype)
try
    [x,fval,exitflag,info] = solve(Opt)
    % Plot Problem
    plot(Opt)
    set(gcf,'position',[510   344   688   558]); %BIGGER for higher D
    if(~isempty(figDir))
        print('-dpng','-r0',[figDir filesep 'ex_plot_3d1']);
    end
catch
end

% 5D
%Objective & Gradient
obj = @(x) x(1)*x(4)*sum(x(1:3)) + x(3);
grad = @(x) [ x(1)*x(4) + x(4)*sum(x(1:3));
              x(1)*x(4);
              x(1)*x(4) + 1;
              x(1)*sum(x(1:3)) ];
%Linear Constraints
lb = ones(4,1);
ub = 5*ones(4,1);
%Nonlinear Constraints
nlcon = @(x) [ prod(x);
               sum(x.^2)];
nljac = @(x) [ prod(x)./x';
                2*x' ];
nlrhs = [25 40]';
nle = [1 0]'; % (>=, ==)
%Setup Options
opts = optiset('solver','ipopt','warnings','all','display','iter','derivCheck','on');
%Build & Solve
Opt = opti('obj',obj,'grad',grad,'nlmix',nlcon,nlrhs,nle,'nljac',nljac,'bounds',lb,ub,'options',opts)
x0 = [1 5 5 1]';
[x,fval,exitflag,info]= solve(Opt,x0)
plot(Opt,2)
set(gcf,'position',[362   188   872   700]); %BIGGER for higher D
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ex_plot_3d2']);
end
clf
set(gcf,'position',stdsize); %return to normal

% multi
% Objective
obj = @(x) (1-x(1))^2 + 100 *(x(2)-x(1)^2)^2;
% Linear Constraints
A = [-1 1];  b = -1;
Aeq = [1.1 1]; beq = 5;
lb = [0;0]; ub = [4;4];
% Initial Guess
x0 = [2;2];

%Build & Solve using multiplot
Opt = opti('obj',obj,'bounds',lb,ub,'ineq',A,b,'eq',Aeq,beq)
[x,fval,ef,info] = multisolve(Opt,x0)

% Plot Problem using multiplot and take log(obj)
multiplot(Opt,1)
set(gcf,'position',[542   402   650   532]); %BIGGER for multi
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ex_plot_m2d']);
end
set(gcf,'position',stdsize); %return to normal

%% Multi solve
% https://www.inverseproblem.co.nz/OPTI/index.php/Advanced/MultiSolve

%Ex 1
% QP Objective
H = sparse([0 -1; -1 0]);
f = [0;0];
% Linear Constraints
lb = [-0.5;-0.5];
ub = [1;1];

% Options
opts = optiset('solver','clp','display','final');
% Build OPTI Object
Opt = opti('qp',H,f,'bounds',lb,ub,'options',opts)

% Solve Problem using MultiSolve
[x,fval,exitflag,info] = multisolve(Opt)

% Plot Problem + Search Area
multiplot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ex1_multi1']);
end

% Ex2
% Solve Problem using MultiSolve and search 30^2 points
[x,fval,exitflag,info] = multisolve(Opt,[],30)

% Plot Problem + Search Area
multiplot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ex1_multi2']);
end

% Ex3
% Solve Problem using MultiSolve [5x Phase 1, 5x Phase 2]
[x,fval,exitflag,info] = multisolve(Opt,[],[5 5])

% Plot Problem + Search Area
multiplot(Opt)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ex1_multi3']);
end

% Ex4
% Objective
obj = @(x) (1-x(1))^2 + 100 *(x(2)-x(1)^2)^2;
% Linear Constraints
A = [-1 1];  b = -1;
Aeq = [1.1 1]; beq = 5;
lb = [0;0]; ub = [4;4];
% Initial Guess
x0 = [2;2];

% Options
opts = optiset('display','final');
% Build OPTI Object
Opt = opti('obj',obj,'ineq',A,b,'eq',Aeq,beq,'bounds',lb,ub,'options',opts)

% Solve Problem using MultiSolve and Lowered Penalty
[x,fval,exitflag,info] = multisolve(Opt,x0,[],100)

% Plot Problem + Search Area
multiplot(Opt,1)
if(~isempty(figDir))
    print('-dpng','-r0',[figDir filesep 'ex4_multi1']);
end

%% SymBuilder
if (exist('syms.m','file'))
    % https://www.inverseproblem.co.nz/OPTI/index.php/Advanced/SymBuilder
    % Create SymBuilder Object
    B = SymBuilder();
    % Create SymBuilder Object with suppressed command line output
    Bs = SymBuilder(false);

    % Add as a String (scalar expression only)
    B.AddObj('-6*x1 -5*x2')

    % Add as a Symbolic Expression
    x = sym('x',[2 1]); %define symbolic variables
    Bs.AddObj(-[6;5]'*x)

    % Add as strings
    B.AddCon('x1 + 4*x2 <= 16');
    B.AddCon('6*x1 + 4*x2 <= 28')

    % Add as Symbolic Expressions with specified cl, cu
    Bs.AddCon(x(1) + 4*x(2),-Inf,16);
    Bs.AddCon(6*x(1) + 4*x(2),-Inf,28)

    % Method 1) Individually as Strings
    B.AddBound('0 <= x1 <= 10');
    B.AddBound('0 <= x2 <= 10')

    % Method 2) Vectorized, 'x' is recognised as belonging to all 'xn' variables
    B.AddBound('0 <= x <= 10');

    % Method 3) As a symbolic variable vector with numerical bounds
    Bs.AddBounds(x,[0;0],[10;10])

    % Build Optimization Problem
    Build(B)
    % Solve SymBuilder Optimization Problem
    [x,fval,ef,info] = Solve(B)

    % New SymBuilder Object
    B = SymBuilder();

    % Add Quadratic Objective
    B.AddObj('0.5*x1^2 + 0.5*x2^2 + 0.5*x3^2 - 2*x1 - 3*x2 - x3');

    % Add Linear Constraints
    B.AddCon('x1 + x2 + x3 <= 1');
    B.AddCon('3*x1 - 2*x2 - 3*x3 <= 1');
    B.AddCon('x1 - 3*x2 + 2*x2 <= 1');

    % Add Integer Constraint (also possible with Symbolic Variables)
    B.AddInteger('x2 = I');

    % Build Object
    Build(B)

    % Solve Problem
    try
        [x,fval,ef,info] = Solve(B)
    catch
    end

    % New SymBuilder Object
    B = SymBuilder();

    % Add Nonlinear Objective with 2 Constants
    B.AddObj('sin(pi*x1/a1)*cos(pi*x2/a2)');

    % Add Linear Constraints
    B.AddCon('-x1 + 2.5*x2 <= 1');
    B.AddCon('x1 + 2.5*x2 <= -15');

    % Add Integer Constraint (note also vectorized)
    B.AddInteger('x = I');

    % Declare Constants with Numerical Values
    B.AddConstant('a1',12);
    B.AddConstant('a2',16);

    % Build It
    Build(B)

    % Inspect resulting equations
    B.sobj
    % New SymBuilder Object
    B = SymBuilder();

    % Add Nonlinear Objective with 2 Intermediate Expressions
    B.AddObj('sin(e1)*cos(e2)');

    % Add Linear Constraints
    B.AddCon('-x1 + 2.5*x2 <= 1');
    B.AddCon('x1 + 2.5*x2 <= -15');

    % Add Integer Constraint
    B.AddInteger('x = I');

    % Add Intemediate Variable Expressions (with Constants for this example)
    B.AddExpression('e1 = pi*x1/a1');
    B.AddExpression('e2 = pi*x2/a2');

    % Define Constants
    B.AddConstant('a1',12);
    B.AddConstant('a2',16);

    % Add Now Build It
    Build(B)

    % New SymBuilder Object (verbose=false)
    B = SymBuilder(false);

    % Add Quadratic Objective
    B.AddObj('(x1-x2)^2 + (x2+x3-2)^2 + (x4-1)^2 + (x5-1)^2');

    % Add Linear Constraints
    B.AddCon('x1 + 3*x2 = 5');
    B.AddCon('x3 + x4 - 2*x5 = 0');
    B.AddCon('x2 - x5 = 0');

    % Add Result Groups (the letter is arbitrary, any group name can be used)
    B.AddResultGroup('A','Fuel Usage [l]');
    B.AddResultGroup('B','Distance [km]');

    % Add Result Expressions (Group:Name, Variable or Expression)
    B.AddResultExp('A:Truck 1','x1');
    B.AddResultExp('A:Truck 2','x2');
    B.AddResultExp('B:Route 1','x3');
    B.AddResultExp('B:Route 2','x4');
    B.AddResultExp('B:Route 3','x5-x3'); %expressions with variables OK too

    % Build Object
    Build(B);

    % Solve
    Solve(B,[ 2.5 0.5 2 -1 0.5 ]);

    % Enter Problem
    B = SymBuilder();
    B.AddObj('(x1-x2)^2 + (x2+x3-2)^2 + (x4-1)^2 + (x5-1)^2');
    B.AddCon('x1^2 + 3*x2 = 4');
    B.AddCon('x3 + x4 - 2*x5 = 0');
    B.AddCon('x2 - x5 = 0');

    % Draft Model
    Draft(B)

    % Initial Guess
    x0 = [ 2.5 0.5 2 -1 0.5 ];

    % Generate C-Code Model and Solve Problem
    [x,fval,ef,info] = Solve(B,x0,symbset('cbmode','ccode'))

    % Generate C++ Code Model with CppAD and Solve Problem
    [x,fval,ef,info] = Solve(B,x0,symbset('cbmode','cppad'))

    % New SymBuilder Object
    B = SymBuilder(false);

    % Add Nonlinear Objective
    B.AddObj('sin(pi*x1/12)*cos(pi*x2/16)');

    % Add Linear Constraints
    B.AddCon('-x1 + 2.5*x2 <= 1');
    B.AddCon('x1 + 2.5*x2 <= -15');

    % Build Object
    Build(B);

    % Get Nonlinear Problem Data
    nlprob = GetNLProb(B)

    % Objective Function (min fun(x))
    fun = @(x) x(1)*x(4)*sum(x(1:3)) + x(3);

    % Nonlinear Constraint Function (cl <= con(x) <= cu)
    con = @(x) [ prod(x);
                 sum(x.^2)];
    cl = [25;40];
    cu = [Inf;40];

    % Bounds + x0
    lb = ones(4,1);
    ub = 5*ones(4,1);
    x0 = [1 5 5 1]';

    % Build OPTI Object
    Opt = optisym(fun,x0,lb,ub,con,cl,cu)

    % Solve
    [x,fval,exitflag,info] = solve(Opt)

    B = SymBuilder();

    % Enter Objective
    B.AddObj('(x1-x2)^2 + (x2+x3-2)^2 + (x4-1)^2 + (x5-1)^2');

    % Add Constraints
    B.AddCon('x1^2 + 3*x2 = 4');
    B.AddCon('x3 + x4 - 2*x5 = 0');
    B.AddCon('x2 - x5 = 0');

    Draft(B)
    Build(B)

    % Enter Problem
    B = SymBuilder();
    B.AddObj('(x1-x2)^2 + (x2+x3-2)^2 + (x4-1)^2 + (x5-1)^2');
    B.AddCon('x1^2 + 3*x2 = 4');
    B.AddCon('x3 + x4 - 2*x5 = 0');
    B.AddCon('x2 - x5 = 0');
    % Draft
    Draft(B)

    % Solve
    x0 = [ 2.5 0.5 2 -1 0.5 ];
    [x,fval,ef,info] = Solve(B,x0)

    % Solve without generating 2nd derivative callback
    [x,fval,ef,info] = Solve(B,x0,symbset('use2ndDerivs','no'))

    rehash
    clear symb_ccb
    clear symcb
    try
        delete('symb_ccb.mexw64')
    catch
    end
    try
        delete('symb_ccb.mexw32')
    catch
    end
    try
       delete('symb_cb.m')
    catch
    end
end

%% Two Cons
% https://www.inverseproblem.co.nz/OPTI/index.php/Advanced/Cons

% Objective (f'x)
f = -[1 2 3]';

% Inequality Constraints (Ax <= b)
A = [-1  1  1;
      1 -3  1];
b = [20;30];

% Equality Constraints (Aeqx = beq)
Aeq = [1 1 1];
beq = 40;

% Bounds (lb <= x <= ub)
lb = [0;0;0];
ub = [40;Inf;Inf];

% Build OPTI Object
Opt = opti('f',f,'ineq',A,b,'eq',Aeq,beq,'bounds',lb,ub)

% Solve Problem
[x,fval] = solve(Opt)

% Objective (f'x)
f = -[1 2 3]';

% Row Constraints (rl <= A*x <= ru)
A = [-1  1  1;
      1 -3  1;
      1  1  1];
rl = [-Inf;-Inf;40];
ru = [20;30;40];

% Bounds (lb <= x <= ub)
lb = [0;0;0];
ub = [40;Inf;Inf];

% Build OPTI Object
Opt = opti('f',f,'lin',A,rl,ru,'bounds',lb,ub)

% Solve Problem
[x,fval] = solve(Opt)

% Objective (fun(x))
fun = @(x) x(1)*x(4)*sum(x(1:3)) + x(3);

% Mixed Nonlinear Constraints
nlcon = @(x) [ prod(x); sum(x.^2) ];
nlrhs = [25;40];
nle = [1;0];      % [>=, =]

% Bounds (lb <= x <= ub)
lb = ones(4,1);
ub = 5*ones(4,1);

x0 = [1 5 5 1]';

% Build OPTI Object
Opt = opti('fun',fun,'nlmix',nlcon,nlrhs,nle,'bounds',lb,ub)

% Solve Problem
[x,fval] = solve(Opt,x0)

% Objective (fun(x))
fun = @(x) x(1)*x(4)*sum(x(1:3)) + x(3);

% Row Nonlinear Constraints
nlcon = @(x) [ prod(x); sum(x.^2) ];
cl = [25;40];
cu = [Inf;40];

% Bounds (lb <= x <= ub)
lb = ones(4,1);
ub = 5*ones(4,1);

x0 = [1 5 5 1]';

% Build OPTI Object
Opt = opti('fun',fun,'nl',nlcon,cl,cu,'bounds',lb,ub)

% Solve Problem
[x,fval] = solve(Opt,x0)

%% Low Level
% https://www.inverseproblem.co.nz/OPTI/index.php/Advanced/LowLevel

% Ex1
% Load Large LP Test Problem
prob = coinRead('maros-r7.mps');

% Solve using OPTI Class
tic
solve(opti(prob,optiset('solver','clp')));
toc

% Solve using MATLAB Wrapper
tic
opti_clp([],prob.f,prob.A,prob.rl,prob.ru,prob.lb,prob.ub);
toc

% Solve using MEX Interface only
tic
clp([],prob.f,prob.A,prob.rl,prob.ru,prob.lb,prob.ub);
toc

% Ex2
% Fitting Function
fun = @(x) [100*(x(2)-x(1)^2); 1 - x(1)];

% Fitting Data
ydata = [0;0];

% Starting Guess
x0 = [-1.2;1];

% Call Low Level Interface
[x,fval] = opti_mkltrnls(fun,[],x0,ydata)

% Ex3
% Objective & Gradient
fun = @(x) log(1+x(1)^2) - x(2);
grad = @(x)[(2*x(1))/(x(1)^2+1), -1];

% Nonlinear Constraint, Jacobian & Structure
nlcon = @(x) (1 + x(1)^2)^2 + x(2)^2 - 4;
cl = 0; cu = 0;
nljac = @(x) sparse([4*x(1)*(x(1)^2+1),2*x(2)]);
jacstr = @() sparse([1 1]);

% Starting Guess
x0 = [2;2];

% Build Function Structure
funcs.objective = fun;
funcs.gradient = grad;
funcs.constraints = nlcon;
funcs.jacobian = nljac;
funcs.jacobianstructure = jacstr;

% Build Options Structure
opts.lb = -1*Inf(2,1);
opts.ub = Inf(2,1);
opts.cl = cl;
opts.cu = cu;
opts.ipopt.hessian_approximation = 'limited-memory';

% Call IPOPT
[x,output] = ipopt(x0,funcs,opts)

% Build OPTI Object
Opt = opti('fun',fun,'nl',nlcon,cl,cu,'x0',x0)

% Solve
[x,fval] = solve(Opt)

%% 1st Ders
% https://www.inverseproblem.co.nz/OPTI/index.php/Advanced/Deriv1

% Objective
fun = @(x) x(1)*x(4)*(x(1) + x(2) + x(3)) + x(3);
% Initial Point
x0 = [1;2;3;4];

% Numerically Differentiate
df = mklJac(fun,x0)

% Automatic Differentiation
dfa = autoJac(fun,x0)

% Complex Step Differentiation
dfc = cstepJac(fun,x0)

% Symbolic Differentiation
if (exist('syms.m','file'))
    grad = symJac(fun)

    % Evaluate
    dfs = grad(x0)
end

% NLP Ex
% Objective
fun = @(x) x(1)*x(4)*(x(1) + x(2) + x(3)) + x(3);

% Nonlinear Constraints
nlcon = @(x) [ x(1)*x(2)*x(3)*x(4);
               x(1)^2 + x(2)^2 + x(3)^2 + x(4)^2 ];
cl = [25;40];
cu = [Inf;40];

% Bounds (lb <= x <= ub)
lb = ones(4,1);
ub = 5*ones(4,1);

% Initial Guess
x0 = [1 5 5 1]';

% Gradient
grad = @(x) mklJac(fun,x);

% Jacobian
jac = @(x) mklJac(nlcon,x);

% Build OPTI Problem
Opt = opti('fun',fun,'grad',grad,'nl',nlcon,cl,cu,'jac',jac,...
            'bounds',lb,ub,'x0',x0)

% Solve NLP
[x,fval,exitflag,info] = solve(Opt)

% Gradient
grad = @(x) autoJac(fun,x);

% Jacobian
jac = @(x) autoJac(nlcon,x);

% Build OPTI Problem
Opt = opti('fun',fun,'grad',grad,'nl',nlcon,cl,cu,'jac',jac,...
            'bounds',lb,ub,'x0',x0)

% Solve NLP
[x,fval,exitflag,info] = solve(Opt)

% Gradient
grad = @(x) cstepJac(fun,x);

% Jacobian
jac = @(x) cstepJac(nlcon,x);

% Build OPTI Problem
Opt = opti('fun',fun,'grad',grad,'nl',nlcon,cl,cu,'jac',jac,...
            'bounds',lb,ub,'x0',x0)

% Solve NLP
[x,fval,exitflag,info] = solve(Opt)

% Gradient
grad = symJac(fun);

% Jacobian
jac = symJac(nlcon);

% Build OPTI Problem
Opt = opti('fun',fun,'grad',grad,'nl',nlcon,cl,cu,'jac',jac,...
            'bounds',lb,ub,'x0',x0)

% Solve NLP
[x,fval,exitflag,info] = solve(Opt)

% Gradient
grad = @(x) [x(1)*x(4) + x(4)*sum(x(1:3)), x(1)*x(4),...
             x(1)*x(4) + 1,  x(1)*sum(x(1:3))];

% Jacobian
jac = @(x) [prod(x')./x';
            2.*x'];

% Build OPTI Problem
Opt = opti('fun',fun,'grad',grad,'nl',nlcon,cl,cu,'jac',jac,...
            'bounds',lb,ub,'x0',x0)

% Solve NLP
[x,fval,exitflag,info] = solve(Opt)

% Sparsity
% Jacobian
jac = @(x) sparse([prod(x')./x';
                   2.*x']);
% Jacobian Structure
jacstr = @() sparse(ones(2,4));

% Objective
fun = @(x) x(1)*x(4)*(x(1) + x(2) + x(3)) + x(3);

% Gradient
grad = @(x) [x(1)*x(4) + x(4)*sum(x(1:3)), x(1)*x(4),...
             x(1)*x(4) + 1,  x(1)*sum(x(1:3))];

% Nonlinear Constraints
nlcon = @(x) [ x(1)*x(2)*x(3)*x(4);
               x(1)^2 + x(2)^2 + x(3)^2 + x(4)^2 ];
cl = [25;40];
cu = [Inf;40];

% Jacobian
jac = @(x) sparse([prod(x')./x';
                   2.*x']);

% Jacobian Structure
jacstr = @() sparse(ones(2,4));

% Bounds (lb <= x <= ub)
lb = ones(4,1);
ub = 5*ones(4,1);

% Initial Guess
x0 = [1 5 5 1]';

% Options
opts = optiset('solver','ipopt','display','iter');

% Build OPTI Problem
Opt = opti('fun',fun,'grad',grad,'nl',nlcon,cl,cu,'jac',jac,'jacstr',jacstr,...
            'bounds',lb,ub,'x0',x0,'options',opts)

% Solve NLP
[x,fval,exitflag,info] = solve(Opt)

% Options
opts = optiset('solver','ipopt','display','iter','derivCheck','on');

% Build OPTI Problem
Opt = opti('fun',fun,'grad',grad,'nl',nlcon,cl,cu,'jac',jac,'jacstr',jacstr,...
           'bounds',lb,ub,'x0',x0,'options',opts)

% Solve NLP
[x,fval,exitflag,info] = solve(Opt)

%% 2nd Ders
% https://www.inverseproblem.co.nz/OPTI/index.php/Advanced/Deriv2

% Objective
fun = @(x) x(1)*x(4)*(x(1) + x(2) + x(3)) + x(3);

% Gradient
grad = @(x) [x(1)*x(4) + x(4)*sum(x(1:3)), x(1)*x(4),...
             x(1)*x(4) + 1,  x(1)*sum(x(1:3))];

% Nonlinear Constraints
nlcon = @(x) [ x(1)*x(2)*x(3)*x(4);
               x(1)^2 + x(2)^2 + x(3)^2 + x(4)^2 ];
cl = [25;40];
cu = [Inf;40];

% Jacobian
jac = @(x) sparse([prod(x')./x';
                   2.*x']);

% Jacobian Structure
jacstr = @() sparse(ones(2,4));

% Hessian
H = @(x,sigma,lambda) sparse(sigma*[ 2*x(4)             0      0   0;
                                     x(4)               0      0   0;
                                     x(4)               0      0   0;
                                     2*x(1)+x(2)+x(3)  x(1)  x(1)  0 ] + ...
                     lambda(1)*[   0          0         0         0;
                                x(3)*x(4)     0         0         0;
                                x(2)*x(4) x(1)*x(4)     0         0;
                                x(2)*x(3) x(1)*x(3) x(1)*x(2)     0  ] + ...
                     lambda(2)*diag([2 2 2 2]));

% Hessian Structure
Hstr = @() sparse(tril(ones(4)));

% Bounds (lb <= x <= ub)
lb = ones(4,1);
ub = 5*ones(4,1);

% Initial Guess
x0 = [1 5 5 1]';

% Options
opts = optiset('solver','ipopt','display','iter');

% Build OPTI Problem
Opt = opti('fun',fun,'grad',grad,'nl',nlcon,cl,cu,'jac',jac,'jacstr',jacstr,...
            'hess',H,'hstr',Hstr,'bounds',lb,ub,'x0',x0,'options',opts)

% Solve NLP
[x,fval,exitflag,info] = solve(Opt)

% Options
opts = optiset('solver','ipopt','display','iter','derivCheck','on');

% Build OPTI Problem
Opt = opti('fun',fun,'grad',grad,'nl',nlcon,cl,cu,'jac',jac,'jacstr',jacstr,...
            'hess',H,'hstr',Hstr,'bounds',lb,ub,'x0',x0,'options',opts)

% Solve NLP
[x,fval,exitflag,info] = solve(Opt)

%% MPS
% https://www.inverseproblem.co.nz/OPTI/index.php/File/MPS

prob = coinRead('testLP.mps')
 % Build an OPTI object of the returned problem
OptMPS = opti(prob)

% Solve the resulting OPTI object
[x,fval] = solve(OptMPS)

probq = coinRead('testQP2','qps',1)
Opt = opti(coinRead('testSOS2.mps'))

%% AMPL

prob = amplRead('diet.nl')
% Build an OPTI object of the returned problem
Opt = opti(prob)

% Solve the resulting OPTI object
[x,fval] = solve(Opt)

% Load an AMPL NLP
prob = amplRead('ch3.nl')

% Build an OPTI object of the returned problem
Opt = opti(prob)

% Solve the resulting OPTI object
[x,fval] = solve(Opt)

% Close ASL interface
asl('close')

 % Load an AMPL MILP
prob = amplRead('multmip1.nl')

% Build an OPTI object of the returned problem
Opt = opti(prob)

% Solve the resulting OPTI object
[x,fval] = solve(Opt)

try
    % Load an AMPL MIQCQP from Model File (but read as MINLP)
    prob = amplRead('trimlon.mod','trimlon2.dat',[],1)

    % Build an OPTI object of the returned problem
    Opt = opti(prob)

    % Solve the resulting OPTI object
    [x,fval] = solve(Opt)

    % Load an AMPL MIQCQP from Model File
    prob = amplRead('trimlon.mod','trimlon2.dat')

    % Set SCIP as the solver
    opts = optiset('solver','scip','display','iter');

    % Build an OPTI object of the returned problem
    Opt = opti(prob,opts)

    % Solve the resulting OPTI object
    [x,fval] = solve(Opt)
catch
end

% Load an AMPL NLP from Model File
prob = amplRead('hs100.nl')

% Examine constraint linearity
prob.conlin

%% SDPA
% https://www.inverseproblem.co.nz/OPTI/index.php/File/SDPA

prob = sdpRead('arch0.dat-s')
% Build an OPTI object of the returned problem
OptSDPA = opti(prob)

% Solve the resulting OPTI object
[x,fval] = solve(OptSDPA)

probd = sdpRead('sdpademo','SDPA',1)
prob = sdpRead('sdp_arch0.mat')
% Build an OPTI object of the returned problem
OptSDMI = opti(prob)

% Solve the resulting OPTI object
[x,fval] = solve(OptSDMI)

%% WhiteBox Solvers
% https://www.inverseproblem.co.nz/OPTI/index.php/Advanced/WhiteBox
clc

% SCIP variable vector
x = scipvar(2,1);
% Test Function
fun = @(x) log(1 + x(1)^2) - x(2);

%Evaluate Function using SCIP variables
fun(x)

% Objective
fun = @(x) 100*(x(2)-x(1)^2)^2 + (1-x(1))^2;    %Objective Function Vector (min f(x))

% Nonlinear Constraints
nlcon = @(x) [x(1) + x(2)^2;                    %cl <= nlcon(x) <= cu
              x(1)^2 + x(2);
              x(1)^2 + x(2)^2 - 1];
cl = [0;0;0];
cu = [Inf;Inf;Inf];

% Bounds
lb = [-0.5;-inf];                               %lb <= x <= ub
ub = [0.5;inf];

% Create OPTI Object
opts = optiset('solver','scip','display','iter');
Opt = opti('fun',fun,'nl',nlcon,cl,cu,'bounds',lb,ub,'opts',opts)

% Solve the NLP problem
x0 = [-2;1] %Initial Guess
[x,fval,exitflag,info] = solve(Opt,x0)

% Objective
fun = @(x) log(1 + x(1)^2) - x(2);    %Objective Function Vector (min f(x))

% Nonlinear Constraints
nlcon = @(x) (1 + x(1)^2)^2 + x(2)^2; %Nonlinear Equality Constraint
cl = 4;
cu = 4;

% Create SCIP Options
sopts = scipset('scipopts',{'limits/solutions',1});

% Create OPTI Object
opts = optiset('solver','scip','display','iter','solverOpts',sopts);
Opt = opti('fun',fun,'nl',nlcon,cl,cu,'ndec',2,'opts',opts)

% Solve the NLP problem
x0 = [2;2] %Initial Guess
[x,fval,exitflag,info] = solve(Opt,x0)

% Objective
fun = @(x) 100*(x(2)-x(1)^2)^2 + (1-x(1))^2;    %Objective Function Vector (min f(x))

% Linear Constraints
A = [-1 1; 1 1];                                %rl <= A*x <= ru
rl = [-inf;5];
ru = [-1;5];

% Bounds
lb = [0;0];                                     %lb <= x <= ub
ub = [4;4];

% Integer Constraints
xtype = 'IC';

% Create OPTI Object
opts = optiset('solver','scip','display','iter');
Opt = opti('fun',fun,'lin',A,rl,ru,'bounds',lb,ub,'xtype',xtype,'opts',opts)

% Solve the NLP problem
x0 = [2;2] %Initial Guess
[x,fval,exitflag,info] = solve(Opt,x0)

% BARON variable vector
if (exist('barvec.m','file'))
    x = barvec(2,1);
    % Test Function
    fun = @(x) log(1 + x(1)^2) - x(2);

    %Evaluate Function using BARON variables
    fun(x)

    % Objective
    fun = @(x) 100*(x(2)-x(1)^2)^2 + (1-x(1))^2;    %Objective Function Vector (min f(x))

    % Nonlinear Constraints
    nlcon = @(x) [x(1) + x(2)^2;                    %cl <= nlcon(x) <= cu
                  x(1)^2 + x(2);
                  x(1)^2 + x(2)^2 - 1];
    cl = [0;0;0];
    cu = [Inf;Inf;Inf];

    % Bounds
    lb = [-0.5;-inf];                               %lb <= x <= ub
    ub = [0.5;inf];

    % Create OPTI Object
    opts = optiset('solver','baron','display','iter');
    Opt = opti('fun',fun,'nl',nlcon,cl,cu,'bounds',lb,ub,'opts',opts)

    % Solve the NLP problem
    x0 = [-2;1] %Initial Guess
    [x,fval,exitflag,info] = solve(Opt,x0)

    % Objective
    fun = @(x) log(1 + x(1)^2) - x(2);    %Objective Function Vector (min f(x))

    % Nonlinear Constraints
    nlcon = @(x) (1 + x(1)^2)^2 + x(2)^2; %Nonlinear Equality Constraint
    cl = 4;
    cu = 4;

    % Create OPTI Object
    opts = optiset('solver','baron','display','iter');
    Opt = opti('fun',fun,'nl',nlcon,cl,cu,'ndec',2,'opts',opts)

    % Solve the NLP problem
    x0 = [2;2] %Initial Guess
    [x,fval,exitflag,info] = solve(Opt,x0)
end

%%
clc
fprintf('Done!\n');


function variance = normal_truncated_ab_variance ( mu, s, a, b )

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

  alpha_pdf = normal_01_pdf ( alpha );
  beta_pdf = normal_01_pdf ( beta );

  alpha_cdf = normal_01_cdf ( alpha );
  beta_cdf = normal_01_cdf ( beta );

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

  return
end


function [x, y, z]=splat(r, theta, phi)
% % mapping, delaunay, flat projection
% %
% % Syntax;
% %
% % [x, y, z]=splat(r, theta, phi);
% %
% % ***********************************************************
% %
% % Description
% %
% % Program maps the spherical coordinates r, theta, and phi from a
% % sphere to a flat plane to aid in triangularization of hemispherical
% % coordinates.
% %
% % ***********************************************************
% %
% % Input Variables
% %
% % r, theta, phi, are matrices of spherical coordinates.
% %
% % ***********************************************************
% %
% % Output Variables
% %
% % x, y, and z, are matrices of rectangular coordinates.
% %
% % ***********************************************************
% %
% Example
%
% phi=pi/4:pi/320:pi/2;
% theta=0:(pi/16):(5*pi);
% r=ones(size(phi));
% [x, y, z]=spherical_to_rectangular(r, theta, phi);
% [x10, y10, z]=splat(r, theta, phi);
% TRI = delaunay(x10, y10);
%
% figure(1);
% h=trisurf(TRI,x,y,z, 'FaceColor', [1 1 1], 'EdgeColor', 0.5*[1 1 1],...
% 'LineWidth', 1 );
% hold on;
% plot3(x,y,z, '-r', 'Linewidth', 3 );
%
% TRI2 = delaunay(x, y);
%
% figure(2);
% h=trisurf(TRI2,x,y,z, 'FaceColor', [1 1 1], 'EdgeColor', 0.5*[1 1 1],...
% 'LineWidth', 1 );
% hold on;
% plot3(x,y,z, '-r', 'Linewidth', 3 );
%
% % ***********************************************************
% %
% % This program was written by Edward L. Zechmann
% %
% %     date     January 2007
% %
% % modified 11   March   2008  added comments
% %
% % ***********************************************************
% %
% % Feel free to modify this code.
% %

x=r.*phi.*cos(theta);
y=r.*phi.*sin(theta);
z=r.*cos(phi);


function [pdf]=gsp_erdos_renyi_density_normalized(y,N,p)
%GSP_ERDOS_RENYI_DENSITY_NORMALIZED  The asymptotic density function of the normalized graph Laplacian
%eigenalues of an Erdos-Renyi random graph
%   Usage:  pdf=gsp_erdos_renyi_density_normalized(y,N,p);
%
%   Input parameters:
%         y               : A vector of values at which the density will be evaluated.
%         N               : Number of vertices in the graph.
%         p               : Edge probability.
%   Output parameters:
%         pdf             : The values of the density function at the points y.
%
%   'gsp_erdos_renyi_density_normalized(y,N,p)' computes the asymptotic density
%   function (for large $N$) of the normalized graph Laplacian
%   eigenvalues of an Erdos-Renyi random graph with $N$ vertices and edge
%   probability $p$. This is a semicircular density function.
%

%   AUTHOR : David I Shuman.
%   TESTING:
%   REFERENCE:

pdf=sqrt((p*N)/(1-p))*(1/(2*pi))*real((y>1-2*sqrt((1-p)/(p*N))).*(y<1+2*sqrt((1-p)/(p*N))).*sqrt(4-p*N/(1-p)*(1-y).^2));


function [ xtab, weight ] = legendre_compute ( norder )

%*****************************************************************************80
%
%% LEGENDRE_COMPUTE computes a Gauss-Legendre quadrature rule.
%
%  Discussion:
%
%    The integration interval is [ -1, 1 ].
%
%    The weight function is w(x) = 1.0.
%
%    The integral to approximate:
%
%      Integral ( -1 <= X <= 1 ) F(X) dX
%
%    The quadrature rule:
%
%      Sum ( 1 <= I <= NORDER ) WEIGHT(I) * F ( XTAB(I) )
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    15 October 2005
%
%  Author:
%
%    Original FORTRAN77 version by Philip Davis, Philip Rabinowitz
%    MATLAB version by John Burkardt
%
%  Reference:
%
%    Philip Davis, Philip Rabinowitz,
%    Methods of Numerical Integration,
%    Second Edition,
%    Dover, 2007,
%    ISBN: 0486453391,
%    LC: QA299.3.D28.
%
%  Parameters:
%
%    Input, integer NORDER, the order of the rule.
%    NORDER must be greater than 0.
%
%    Output, real XTAB(NORDER), the abscissas of the rule.
%
%    Output, real WEIGHT(NORDER), the weights of the rule.
%    The weights are positive, symmetric, and should sum to 2.
%
  if ( norder < 1 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'LEGENDRE_COMPUTE - Fatal error!\n' );
    fprintf ( 1, '  Illegal value of NORDER = %d\n', norder );
    error ( 'LEGENDRE_COM - Fatal error!' );
  end

  e1 = norder * ( norder + 1 );

  m = floor ( ( norder + 1 ) / 2 );

  for i = 1 : floor ( ( norder + 1 ) / 2 )

    mp1mi = m + 1 - i;

    t = ( 4 * i - 1 ) * pi / ( 4 * norder + 2 );

    x0 = cos(t) * ( 1.0 - ( 1.0 - 1.0 / ( norder ) ) / ( 8 * norder * norder ) );

    pkm1 = 1.0;
    pk = x0;

    for k = 2 : norder
      pkp1 = 2.0 * x0 * pk - pkm1 - ( x0 * pk - pkm1 ) / k;
      pkm1 = pk;
      pk = pkp1;
    end

    d1 = norder * ( pkm1 - x0 * pk );

    dpn = d1 / ( 1.0 - x0 * x0 );

    d2pn = ( 2.0 * x0 * dpn - e1 * pk ) / ( 1.0 - x0 * x0 );

    d3pn = ( 4.0 * x0 * d2pn + ( 2.0 - e1 ) * dpn ) / ( 1.0 - x0 * x0 );

    d4pn = ( 6.0 * x0 * d3pn + ( 6.0 - e1 ) * d2pn ) / ( 1.0 - x0 * x0 );

    u = pk / dpn;
    v = d2pn / dpn;
%
%  Initial approximation H:
%
    h = - u * ( 1.0 + 0.5 * u * ( v + u * ( v * v - d3pn / ( 3.0 * dpn ) ) ) );
%
%  Refine H using one step of Newton's method:
%
    p = pk + h * ( dpn + 0.5 * h * ( d2pn + h / 3.0 ...
      * ( d3pn + 0.25 * h * d4pn ) ) );

    dp = dpn + h * ( d2pn + 0.5 * h * ( d3pn + h * d4pn / 3.0 ) );

    h = h - p / dp;

    xtemp = x0 + h;

    xtab(mp1mi) = xtemp;

    fx = d1 - h * e1 * ( pk + 0.5 * h * ( dpn + h / 3.0 ...
      * ( d2pn + 0.25 * h * ( d3pn + 0.2 * h * d4pn ) ) ) );

    weight(mp1mi) = 2.0 * ( 1.0 - xtemp * xtemp ) / fx / fx;

  end

  if ( mod ( norder, 2 ) == 1 )
    xtab(1) = 0.0;
  end
%
%  Shift the data up.
%
  nmove = floor ( ( norder + 1 ) / 2 );
  ncopy = norder - nmove;

  for i = 1 : nmove
    iback = norder + 1 - i;
    xtab(iback) = xtab(iback-ncopy);
    weight(iback) = weight(iback-ncopy);
  end
%
%  Reflect values for the negative abscissas.
%
  for i = 1 : norder - nmove
    xtab(i) = - xtab(norder+1-i);
    weight(i) = weight(norder+1-i);
  end

  return
end


function [ score ] = compute_cosine_score( feature1, feature2 )
% compute_cosine_score Summary of this function goes here
%   This function is to compute the cosine similarity between two vectors
%
    score = feature1'*feature2/norm(feature1)/norm(feature2);

end


function [mel,mr] = frq2mel(frq)
%FRQ2ERB  Convert Hertz to Mel frequency scale MEL=(FRQ)
%	[mel,mr] = frq2mel(frq) converts a vector of frequencies (in Hz)
%	to the corresponding values on the Mel scale which corresponds
%	to the perceived pitch of a tone.
%   mr gives the corresponding gradients in Hz/mel.

%	The relationship between mel and frq is given by:
%
%	m = ln(1 + f/700) * 1000 / ln(1+1000/700)
%
%  	This means that m(1000) = 1000
%
%	References:
%
%	  [1] S. S. Stevens & J. Volkman "The relation of pitch to
%		frequency", American J of Psychology, V 53, p329 1940
%	  [2] C. G. M. Fant, "Acoustic description & classification
%		of phonetic units", Ericsson Tchnics, No 1 1959
%		(reprinted in "Speech Sounds & Features", MIT Press 1973)
%	  [3] S. B. Davis & P. Mermelstein, "Comparison of parametric
%		representations for monosyllabic word recognition in
%		continuously spoken sentences", IEEE ASSP, V 28,
%		pp 357-366 Aug 1980
%	  [4] J. R. Deller Jr, J. G. Proakis, J. H. L. Hansen,
%		"Discrete-Time Processing of Speech Signals", p380,
%		Macmillan 1993
%	  [5] HTK Reference Manual p73
%

%      Copyright (C) Mike Brookes 1998
%      Version: $Id: frq2mel.m,v 1.7 2010/08/01 08:41:57 dmb Exp $
%
%   VOICEBOX is a MATLAB toolbox for speech processing.
%   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   This program is free software; you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation; either version 2 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You can obtain a copy of the GNU General Public License from
%   http://www.gnu.org/copyleft/gpl.html or by writing to
%   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
persistent k
if isempty(k)
    k=1127.01048;
end
af=abs(frq);
mel = sign(frq).*log(1+af/700)*k;
mr=(700+af)/k;
if ~nargout
    plot(frq,mel,'-x');
    xlabel(['Frequency (' xticksi 'Hz)']);
    ylabel(['Frequency (' yticksi 'Mel)']);
end


function [bestEpsilon bestF1] = selectThreshold(yval, pval)
%SELECTTHRESHOLD Find the best threshold (epsilon) to use for selecting
%outliers
%   [bestEpsilon bestF1] = SELECTTHRESHOLD(yval, pval) finds the best
%   threshold to use for selecting outliers based on the results from a
%   validation set (pval) and the ground truth (yval).
%

bestEpsilon = 0;
bestF1 = 0;
F1 = 0;

stepsize = (max(pval) - min(pval)) / 1000;
for epsilon = min(pval):stepsize:max(pval)

    % ====================== YOUR CODE HERE ======================
    % Instructions: Compute the F1 score of choosing epsilon as the
    %               threshold and place the value in F1. The code at the
    %               end of the loop will compare the F1 score for this
    %               choice of epsilon and set it to be the best epsilon if
    %               it is better than the current choice of epsilon.
    %
    % Note: You can use predictions = (pval < epsilon) to get a binary vector
    %       of 0's and 1's of the outlier predictions

    predictions = (pval < epsilon);

    fp = sum((predictions == 1) & (yval == 0));
    fn = sum((predictions == 0) & (yval == 1));
    tp = sum((predictions == 1) & (yval == 1));

    prec = tp / (tp + fp);
    rec = tp / (tp + fn);

    F1 = 2 * prec * rec / (prec + rec);

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

    if F1 > bestF1
       bestF1 = F1;
       bestEpsilon = epsilon;
    end
end

end

github-repos/MATLAB/Borye-machine-learning-coursera-1/machine-learning-coursera-1-033fdc2e6da393eeb1179a09aafe92362021effb/Week 9 Assignments/Anomaly Detection and Recommender Systems/mlclass-ex8/selectThreshold.m


function value = cos_deg ( angle )

%*****************************************************************************80
%
%% COS_DEG returns the cosine of an angle given in degrees.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    22 May 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real ANGLE, the angle, in degrees.
%
%    Output, real COS_DEG, the cosine of the angle.
%
  angle_rad = pi * angle / 180.0;

  value = cos ( angle_rad );

  return
end


%% Transient Behavior and Location of Characteristic Roots in the Complex Plane
% Copyright 2011 The MathWorks, Inc.
%% Initial Value Problem
%
% Consider the system described by the following second-order,
% ordinary differential equation and associated initial conditions:
%
% $$\frac{d^2x}{dt^2} + 2\zeta\omega_n\frac{dx}{dt} + \omega_n^2x = 0; x(0)=x0,\frac{dx}{dt}(0)=0 $$
%
% We would like to examine the behavior of the free response of the
% system as the damping ratio changes.  This will be done first by solving
% the initial value problem for various damping ratios and plotting the
% results.  Then, we will explore changes in the damping ratio affect the
% characteristic roots.  (Recall that the characteristic roots dictate the
% free-response behavior.)

%% Set physical and derived parameters.
%
% To enable numerical solution of the differential equation, we will set
% specific values for the mass and (linear) spring rate.  We will then use
% these to derive the (circular) natural frequency.
%
param.m = 1;                            % Mass [kg]
param.k = 1;                            % Spring rate [N/m]
param.wn = sqrt(param.k/param.m);       % (Circular) natural frequency [rad/s]

%% Set initial conditions.
%
% To solve our 2nd order differential equation, we need two initial
% conditions: one on position, the other on velocity.  Moreover, recall
% from the accompanying PowerPoint slides that we have represented our
% 2nd order linear ODE into a system of 1st order ODE's amenable to
% solution using MATLAB. Having defined position and velocity as our
% system states, we must define an initial state vector.

x0 = 1;              % Position [m]
x0_dot = 0;          % Velocity [m/s]
z0 = [x0 ; x0_dot];  % Initial condition on state vector

%% Set simulation parameters.
%
% We will define the duration of our simulation to be approximately 4
% periods.  To accommodate changes in physical parameters, we will
% parameterize the duration by the natural frequency.  We then define the
% associated time step and vector of simulation time.  Note that the time
% step dt serves to define the times at which output will be provided, not
% the solver time step.

tend = 4*round((2*pi)/param.wn);    % Simulate for approximately 4 periods [s]
dt = round((2*pi)/param.wn)/1000;   % Time step [s]
tsim = 0:dt:tend;                   % Vector of simulation times [s]

%% Undamped system.
%
% We first consider an undamped system, characterized by a damping ratio of
% zero.  Physically, this represents a system with zero dissipation of
% energy.  We will plot the free response to confirm the expected behavior.
%
% To solve the system of 1st order ODE's, we will use the baseline ode45
% solver.  The solver requires a vector of state derivatives; in this
% case, we call upon a function to define them.

param.zeta = 0;     % Damping ratio

[t,z] = ode45(@(t,z) odesys( t,z,param ),tsim,z0);
x(:,1) = z(:,1);    % Save solution for future plotting.

plot(t,x(:,1),'linewidth',2);grid on;hold all

    ylim([-1 1])
    xlabel('Time [s]');
    ylabel('Position [m]')
    title('Free Response: Undamped 2nd Order System');

%% Consider several damping ratios.
%
% Now we will consider four distinct values of the damping ratio
% corresponding to four distinct types of system behavior: undamped,
% underdamped, critically damped, and overdamped.  These terms refer to the
% behavior of the system as it returns to its equilibrium state.  We will
% plot and compare the free responses for these cases.

zetavals = [0 1/sqrt(2) 1 1.5]; % Damping ratios to consider.

case1 = 'Undamped: zeta = 0' ;
case2 = 'Underdamped: zeta = 0.707' ;
case3 = 'Critically Damped: zeta = 1' ;
case4 = 'Overdamped: zeta = 1.5' ;

for i = 2: length(zetavals)

    param.zeta = zetavals(i); % Set current damping ratio.
    [t,z] = ode45(@(t,z) odesys( t,z,param ),tsim,z0); % Compute free response.
    x(:,i) = z(:,1); % Save solution for future plotting.

end;

figure      % Plot results

    plot(t,x,'linewidth',2);grid on
    xlabel('Time [s]');
    ylabel('Position [m]')
    title('Free Response of 2nd Order System for Various Damping Ratios');
    legend(case1,case2,case3,case4,0)

%% Track characteristic roots as damping ratio increases.
%
% Recalling that the free response of a system is governed by its
% characteristic roots, we will examine the changes in these roots as the
% damping ratio changes over a more finely spaced set of values.  Since the
% roots may have real and imaginary parts, we will plot them in the complex
% plane.  For each value of the damping ratio, we will compute the
% characteristic roots as the eigenvalues of the associated state matrix.

zeta_range = 0:0.01:1.5;          % Damping ratio: undamped to overdamped.
S = zeros(2,length(zeta_range));  % Initialize characteristic roots array.

for i = 1:length(zeta_range)

    S(:,i) = eig([0 1; -param.wn^2 -2*zeta_range(i)*param.wn]); % Characteristic roots.

end;

figure      % Plot characteristic roots in complex plane.

    plot(S,'bx','linewidth',2,'markersize',5); grid on;
    set(gca,'YAxisLocation','right')
    xlabel('Real Axis','Position',[-1.5 -0.1 1])
    ylabel('Imaginary Axis')
    title('Loci of Characteristic Roots in Complex Plane for Various Damping Ratios')

%% Show the "odesys" function.
%
% Here we record the function used to define the state matrix
% corresponding to our system of ordinary differential equations.

type odesys.m


function [ x, w ] = gen_hermite_dr_compute ( n, alpha )

%*****************************************************************************80
%
%% GEN_HERMITE_DR_COMPUTE computes a generalized Gauss-Hermite rule.
%
%  Discussion:
%
%    The integral to be approximated has the form:
%
%      Integral ( -oo < x < +oo ) |x|^ALPHA exp(-x^2) f(x) dx
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    13 February 2010
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Philip Davis, Philip Rabinowitz,
%    Methods of Numerical Integration,
%    Second Edition,
%    Dover, 2007,
%    ISBN: 0486453391,
%    LC: QA299.3.D28.
%
%  Parameters:
%
%    Input, integer N, the order.
%
%    Input, real ALPHA, the parameter.
%
%    Output, real X(N), the abscissas.
%
%    Output, real W(N), the weights.
%
  x = zeros ( n, 1 );
  w = zeros ( n, 1 );

  if ( n == 1 )
    arg = ( alpha + 1.0 ) / 2.0;
    x(1) = 0.0;
    w(1) = gamma ( arg );
    return
  end

  if ( mod ( n, 2 ) == 0 )
    n_laguerre = floor ( n / 2 );
    alpha_laguerre = ( alpha - 1.0 ) / 2.0;
  elseif ( mod ( n, 2 ) == 1 )
    n_laguerre = floor ( n - 1 ) / 2;
    alpha_laguerre = ( alpha + 1.0 ) / 2.0;
  end

  [ x_laguerre, w_laguerre ] = gen_laguerre_ss_compute ( n_laguerre,  alpha_laguerre );

  if ( mod ( n, 2 ) == 0 )

    x(1:n_laguerre) = - sqrt ( x_laguerre(n_laguerre:-1:1) );
    x(n_laguerre+1:n_laguerre+n_laguerre) = sqrt ( x_laguerre(1:n_laguerre) );

    w(1:n_laguerre) = 0.5 * w_laguerre(n_laguerre:-1:1);
    w(n_laguerre+1:n_laguerre+n_laguerre) = 0.5 * w_laguerre(1:n_laguerre);

  elseif ( mod ( n, 2 ) == 1 )

    x(1:n_laguerre) = - sqrt ( x_laguerre(n_laguerre:-1:1) );
    x(n_laguerre+1) = 0.0;
    x(n_laguerre+2:n_laguerre+n_laguerre+1) = sqrt ( x_laguerre(1:n_laguerre) );

    w(1:n_laguerre) = 0.5 * w_laguerre(n_laguerre:-1:1) ...
                             ./ x_laguerre(n_laguerre:-1:1);

    arg = ( alpha + 1.0 ) / 2.0;
    w(n_laguerre+1) = gamma ( arg ) ...
      - sum ( w_laguerre(1:n_laguerre) ./ x_laguerre(1:n_laguerre) );

    w(n_laguerre+2:n_laguerre+n_laguerre+1) = 0.5 * w_laguerre(1:n_laguerre) ...
                                                             ./ x_laguerre(1:n_laguerre);

  end

  return
end


function fx = p37_fun ( n, x )

%*****************************************************************************80
%
%% P37_FUN evaluates the integrand for problem 37.
%
%  Discussion:
%
%    The problem has a parameter ALPHA that can be set by calling
%    P37_PARAM_SET.  It had a default value of 5.0.
%
%    The integrand has a peak of height 4^ALPHA at X = PI/4.
%
%    Suggested values of ALPHA include 0 through 20.
%
%  Interval:
%
%    0 <= x <= 1
%
%  Integrand:
%
%    4^(-ALPHA) / ( ( x - PI/4 )^2 + 16^(-ALPHA) )
%
%  Exact Integral:
%
%    atan ( ( 4 - PI ) * 4^(ALPHA-1) ) + atan ( PI * 4^(ALPHA-1) )
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 November 2009
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Robert Piessens, Elise de Doncker-Kapenga,
%    Christian Ueberhuber, David Kahaner,
%    QUADPACK: A Subroutine Package for Automatic Integration,
%    Springer, 1983, page 83.
%
%  Parameters:
%
%    Input, integer N, the number of evaluation points.
%
%    Input, real X(N), the evaluation points.
%
%    Output, real FX(N), the integrand values.
%
  alpha = p37_param_get ( );

  fx = 4.0^( -alpha ) ./ ( ( x - 0.25 * pi ).^2 + 16.0^(-alpha) );

  return
end


function timemetric
tic; [x,n,bco,bcn,gco,gcn,cs1,cs2]=metr(@elipsod,1); toc

function [x,n,bco,bcn,gco,gcn,cs1,cs2]=metr(func,method)
% [x,n,bco,bcn,gco,gcn,cs1,cs2]=metr(func,method)

% This function computes base vectors, metric tensor
% components, and Christoffel symbols for a general
% curvilinear coordinate system
% func     - handle of a function which returns the
%            cartesian radius vector x as a function
%            of the curvilinear coordinate variables,
%            and a vector containing the names of the
%            coordinate variables used to define x. In
%            spherical coordinates, for example, names
%            might be 'r, theta, phi'.
% method   - Use 1 to compute the Christoffel symbols by
%            differentiating the metric tensor components.
%            Use 2 to compute the Christoffel symbols by
%            by differentiating vector x.
% x        - cartesian components of the radius vector
%            expressed in terms of the curvilinear
%            coordinate variables
% n          a vector containing the names of the
%            curvilinear coordinate variables
% bco, bcn - cartesian components of the covariant and
%            contravariant base vectors. The i'th column
%            of each array contains components of the
%            i'th base vector.
% gco, gcn - covariant and contravariant components of
%            the metric tensor.
% cs1, cs2 - Christoffel symbols or the first and second
%            kinds. The symbol for index i,j,k is in
%            row i, column j, and layer k of each array.

if nargin<2, method=1; end
if nargin==0, func=@sphr; end
[x,n]=feval(func); x=simple(x(:));

% Differentiate the radius vector to get the
% contravariant base vectors.
% bco=[diff(x,n(1)),diff(x,n(2)),diff(x,n(3))]
bco=jacobian(x,n(:).');

% Use orthogonality to compute the contravariant
% base vectors.
bcn=simple(inv(bco.'));

% Obtain the metric tensor components as dot products of
% the base vectors
gco=simple(bco.'*bco); gcn=simple(bcn.'*bcn);

% If Christoffel symbols are not required, then exit
if nargout<6, return, end

% Compute the Christoffel symbols.
cs1=sym(zeros(3,3,3)); cs2=cs1;
if method==1
  % Obtain symbols of the first kind by differentiating
  % the covariant metric tensor components.
  for k=1:3
    for i=1:3, for j=1:i
      cs1(i,j,k)=1/2*(diff(gco(j,k),n(i))+...
             diff(gco(i,k),n(j))-diff(gco(i,j),n(k)));
      if j~=i, cs1(j,i,k)=cs1(i,j,k); end
    end, end
  end
else % method==2
  % Obtain symbols of the first kind using derivatives
  % of vector x.
  h=sym(zeros(3,3,3));
  for k=1:3, h(:,:,k)=simple(diff(bco(:,:),n(k))); end

  for k=1:3
    cs1(:,:,k)=squeeze(h(1,:,:)*bco(1,k)+h(2,:,:)*bco(2,k)+...
               h(3,:,:)*bco(3,k));
  end
%   for k=1:3, for i=1:3, for j=1:3
%     cs1(i,j,k)=h(1,i,j)*bco(1,k)+h(2,i,j)*bco(2,k)+...
%                h(3,i,j)*bco(3,k);
%   end,end,end
  cs1=simple(cs1);
end

% Obtain Christoffel symbols of the second kind by
% using the contravariant metric tensor components to
% raise the third index.
for k=1:3
  cs2(:,:,k)=cs1(:,:,1)*gcn(1,k)+cs1(:,:,2)*gcn(2,k)+...
             cs1(:,:,3)*gcn(3,k);
end
x=simple(x); bco=simple(bco); bcn=simple(bcn);
gco=simple(gco); gcn=simple(gcn);
cs1=simple(cs1); cs2=simple(cs2);

function [X,names]=elipsod
% [X,names]=elipsod defines ellipsoidal
% coordinates with 0 < lm < b,
% b < t < c, and c < e <infinity
syms e t lm real
names=[lm,t,e];
b=1; c=2*b; b2=b^2; c2=c^2; cb=c2-b2;
x=e*t*lm/(b*c);
y=sqrt((e^2-b2)*(t^2-b2)*...
    (b2-lm^2)/(b2*cb));
z=sqrt((e^2-c2)*(c2-t^2)*...
     (c2-lm^2)/(c2*cb));
X=[x;y;z];


%KNAPSACK Solves the 0-1 knapsack problem for positive integer weights
%
%  [BEST AMOUNT] = KNAPSACK(WEIGHTS, VALUES, CONSTRAINT)
%
%       WEIGHTS    : The weight of every item (1-by-N)
%       VALUES     : The value of every item (1-by-N)
%       CONSTRAINT : The weight constraint of the knapsack (scalar)
%
%       BEST       : Value of best possible knapsack (scalar)
%       AMOUNT     : 1-by-N vector specifying the amount to use of each item (0 or 1)
%
%
%	EXAMPLE :
%
%		weights = [1 1 1 1 2 2 3];
%		values  = [1 1 2 3 1 3 5];
%		[best amount] = KNAPSACK(weights, values, 7)
%
%		best =
%
%	    	13
%
%
%		amount =
%
%	    	 0     0     1     1     0     1     1
%
%
%   See Knapsack problem on Wikipedia.
%
%   Copyright 2009 Petter Strandmark
%   petter.strandmark@gmail.com
function [best amount] = knapsack(weights, values, W)
    if ~all(is_positive_integer(weights)) || ...
       ~is_positive_integer(W)
        error('Weights must be positive integers');
    end
    %We work in one dimension
    [M N] = size(weights);
    weights = weights(:);
    values = values(:);
    if numel(weights) ~= numel(values)
        error('The size of weights must match the size of values');
    end
    if numel(W) > 1
        error('Only one constraint allowed');
    end

    % Solve the problem

    % Note that A would ideally be indexed from A(0..N,0..W) but MATLAB
    % does not allow this.
    A = zeros(length(weights)+1,W+1);
    % A(j+1,Y+1) means the value of the best knapsack with capacity Y using
    % the first j items.
    for j = 1:length(weights)
        for Y = 1:W
            if weights(j) > Y
                A(j+1,Y+1) = A(j,Y+1);
            else
                A(j+1,Y+1) = ...
                    max( A(j,Y+1), values(j) + A(j,Y-weights(j)+1));
            end
        end
    end

   best = A(end,end);

   %Now backtrack
   amount = zeros(length(weights),1);
   a = best;
   j = length(weights);
   Y = W;
   while a > 0
       while A(j+1,Y+1) == a
           j = j - 1;
       end
       j = j + 1; %This item has to be in the knapsack
       amount(j) = 1;
       Y = Y - weights(j);
       j = j - 1;
       a = A(j+1,Y+1);
   end

    amount = reshape(amount,M,N);
end

function yn = is_positive_integer(X)
    yn = X>0 & floor(X)==X;
end


function program_03 ( )

%*****************************************************************************80
%
%% PROGRAM_03 demonstrates barycentric coordinates.
%
%  Discussion:
%
%    The program
%    * reads a triangle T (defined by three points),
%    * computes and prints the area;
%    * computes and prints the angles;
%    * reads a point P
%    * computes the signed areas of the subtriangles;
%    * computes the barycentric coordinates.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    01 February 2007
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'PROGRAM_03 - Barycentric Coordinates\n' );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Define a triangle T:\n' );

  t_v1 = input ( '  Enter [ T.v1.x, T.v1.y]: ' );
  t_v2 = input ( '  Enter [ T.v2.x, T.v2.y]: ' );
  t_v3 = input ( '  Enter [ T.v3.x, T.v3.y]: ' );
%
%  Compute the area.
%
  t_area = 0.5 * ( t_v1(1) * ( t_v2(2) - t_v3(2) ) ...
                 + t_v2(1) * ( t_v3(2) - t_v1(2) ) ...
                 + t_v3(1) * ( t_v1(2) - t_v2(2) ) );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Triangle area = %f\n', t_area );
%
%  Check various points.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Now we compute barycentric coordinates for points.\n' );
  fprintf ( 1, '\n' );

  while ( 1 )

    p = [];
    fprintf ( 1, '\n' );
    p = input ( '  Enter a point [ P.x, P.y], or RETURN to quit: ' );

    if ( isempty ( p ) )
      break
    end
%
%  Compute the areas of the three subtriangles.
%
    tpbc_area = 0.5 * ( p(1)    * ( t_v2(2) - t_v3(2) ) ...
                      + t_v2(1) * ( t_v3(2) - p(2)    ) ...
                      + t_v3(1) * ( p(2)    - t_v2(2) ) );

    tapc_area = 0.5 * ( t_v1(1) * ( p(2)    - t_v3(2) ) ...
                      + p(1)    * ( t_v3(2) - t_v1(2) ) ...
                      + t_v3(1) * ( t_v1(2) - p(2)    ) );

    tabp_area = 0.5 * ( t_v1(1) * ( t_v2(2) - p(2)    ) ...
                      + t_v2(1) * ( p(2)    - t_v1(2) ) ...
                      + p(1)    * ( t_v1(2) - t_v2(2) ) );

    xi1 = tpbc_area / t_area;
    xi2 = tapc_area / t_area;
    xi3 = tabp_area / t_area;

    fprintf ( 1, '\n' );
    fprintf ( 1, '  PBC = %8.4f  XI1 = %8.4f\n', tpbc_area, xi1 );
    fprintf ( 1, '  APC = %8.4f  XI2 = %8.4f\n', tapc_area, xi2 );
    fprintf ( 1, '  APB = %8.4f  XI3 = %8.4f\n', tabp_area, xi3 );
    sum1 = tpbc_area + tapc_area + tabp_area;
    sum2 = xi1 + xi2 + xi3;
    fprintf ( 1, '  Sum = %8.4f  Sum = %8.4f\n', sum1, sum2 );

  end

  fprintf ( 1, '\n' );
  fprintf ( 1, 'PROGRAM_03\n' );
  fprintf ( 1, '  Normal end of execution.\n' );

  return
end


function F = spm_ncFcdf(x,df,d)
% Cumulative Distribution Function (CDF) of non-central F-distribution
% FORMAT f = spm_ncFcdf(x,df,d)
% x  - F-variate (F has range [0,Inf) )
% df - degrees of freedom, df = [v,w] with v>0 and w>0
% d  - non-centrality parameter
% F  - CDF of non-central F-distribution with [v,w] d.f. at points x
%
% Reference:
% https://en.wikipedia.org/wiki/Noncentral_F-distribution
%__________________________________________________________________________
% Copyright (C) 2018 Wellcome Trust Centre for Neuroimaging

% Guillaume Flandin
% $Id: spm_ncFcdf.m 7354 2018-06-22 10:44:22Z guillaume $

%-Format arguments, note & check sizes
%--------------------------------------------------------------------------
%-Unpack degrees of freedom v & w from single df parameter (df)
if numel(df) == 2
    v = df(1);
    w = df(2);
elseif size(df,2) == 2
    v = df(:,1);
    w = df(:,2);
else
    error('Cannot unpack degrees of freedom.');
end

%-Check argument sizes
ad = [ndims(x);ndims(v);ndims(w);ndims(d)];
rd = max(ad);
as = [[size(x),ones(1,rd-ad(1))];...
      [size(v),ones(1,rd-ad(2))];...
      [size(w),ones(1,rd-ad(3))];...
      [size(d),ones(1,rd-ad(4))];];
rs = max(as);
xa = prod(as,2)>1;
if all(xa) && any(any(diff(as(xa,:)),1))
    error('Non-scalar arguments must match in size.');
end

%-Computation
%--------------------------------------------------------------------------
%-Initialise result to zeros
F = zeros(rs);

%-Only defined for v>0, w>0 and d>=0. Return NaN if undefined.
md = true(size(F)) & v>0 & w>0 & d>=0;
if any(~md(:))
    F(~md) = NaN;
    warning('Returning NaN for out of range arguments');
end

%-Compute where defined
if ~any(md(:)), return, end
Q = md;
if xa(1), Qx=Q; else Qx=1; end
if xa(2), Qv=Q; else Qv=1; end
if xa(3), Qw=Q; else Qw=1; end
if xa(4), Qd=Q; else Qd=1; end

a = exp(-d(Qd)/2);
x = v(Qv) .* x(Qx) ./ (w(Qw) + v(Qv) .* x(Qx));
F(Q) = a .* betainc(x(Qx), v(Qv)/2, w(Qw)/2);
for i=1:1024
    a = a .* d(Qd) / (2 * i);
    % could use recursion with:
    % Ix(a+1,b)=Ix(a,b)-G(a+b)/(G(a+1)*G(b))*x^a*(1-x)^b and G(a+1)=a*G(a)
    e = a .* betainc(x(Qx), v(Qv)/2+i, w(Qw)/2);
    if max(e) < 1e-12, break; end
    F = F + e;
end


% Minimize sidelobe level of a uniform linear array via spectral factorization
% "FIR Filter Design via Spectral Factorization and Convex Optimization" example
% by S.-P. Wu, S. Boyd, and L. Vandenberghe
% (figures are generated)
%
% Designs a uniform linear antenna array using spectral factorization method where:
% - it minimizes sidelobe level outside the beamwidth of the pattern
% - it has a constraint on the maximum ripple around unit gain in the beamwidth
%
%   minimize   max |y(theta)|                   for theta in the stop-beamwidth
%       s.t.   1/delta <= |y(theta)| <= delta   for theta in the pass-beamwidth
%
% We first replace the look-angle variable theta with the "frequency"
% variable omega, defined by omega = -2*pi*d/lambda*cos(theta).
% This transforms the antenna pattern y(theta) into a standard discrete
% Fourier transform of array weights w. Then we apply another change of
% variables: we replace w with its auto-correlation coefficients r.
%
% Now the problem can be solved via spectral factorization approach:
%
%   minimize   max R(omega)                        for omega in the stopband
%       s.t.   (1/delta)^2 <= R(omega) <= delta^2  for omega in the passband
%              R(omega) >= 0                       for all omega
%
% where R(omega) is the squared magnitude of the y(theta) array response
% (and the Fourier transform of the autocorrelation coefficients r).
% Variables are coefficients r. delta is the allowed passband ripple.
% This is a convex problem (can be formulated as an LP after sampling).
%
% Written for CVX by Almir Mutapcic 02/02/06

%********************************************************************
% problem specs: a uniform line array with inter-element spacing d
%                antenna element locations are at d*[0:n-1]
%                (the array pattern will be symmetric around origin)
%********************************************************************
n = 20;               % number of antenna elements
lambda = 1;           % wavelength
d = 0.45*lambda;      % inter-element spacing

% passband direction from 30 to 60 degrees (30 degrees bandwidth)
% transition band is 15 degrees on both sides of the passband
theta_pass = 40;
theta_stop = 50;

% passband max allowed ripple
ripple = 0.1; % in dB (+/- around the unit gain)

%********************************************************************
% construct optimization data
%********************************************************************
% number of frequency samples
m = 30*n;

% convert passband and stopband angles into omega frequencies
omega_zero = -2*pi*d/lambda;
omega_pass = -2*pi*d/lambda*cos(theta_pass*pi/180);
omega_stop = -2*pi*d/lambda*cos(theta_stop*pi/180);
omega_pi   = +2*pi*d/lambda;

% build matrix A that relates R(omega) and r, ie, R = A*r
omega = linspace(-pi,pi,m)';
A = exp( -j*omega(:)*[1-n:n-1] );

% passband constraint matrix
Ap = A(omega >= omega_zero & omega <= omega_pass,:);

% stopband constraint matrix
As = A(omega >= omega_stop & omega <= omega_pi,:);

%********************************************************************
% formulate and solve the magnitude design problem
%********************************************************************
cvx_begin
  variable r(2*n-1,1) complex
  % minimize stopband attenuation
  minimize( max( real( As*r ) ) )
  subject to
    % passband ripple constraints
    (10^(-ripple/20))^2 <= real( Ap*r ) <= (10^(+ripple/20))^2;
    % nonnegative-real constraint for all frequencies
    % a bit redundant: the passband frequencies are already constrained
    real( A*r ) >= 0;
    % auto-correlation symmetry constraints
    imag(r(n)) == 0;
    r(n-1:-1:1) == conj(r(n+1:end));
cvx_end

% check if problem was successfully solved
if ~strfind(cvx_status,'Solved')
    return
end

% find antenna weights by computing the spectral factorization
w = spectral_fact(r);

% divided by 2 since this is in PSD domain
min_sidelobe_level = 10*log10( cvx_optval );
fprintf(1,'The minimum sidelobe level is %3.2f dB.\n\n',...
          min_sidelobe_level);

%********************************************************************
% plots
%********************************************************************
% build matrix G that relates y(theta) and w, ie, y = G*w
theta = [-180:180]';
G = kron( cos(pi*theta/180), [0:n-1] );
G = exp(2*pi*i*d/lambda*G);
y = G*w;

% plot array pattern
figure(1), clf
ymin = -40; ymax = 5;
plot([-180:180], 20*log10(abs(y)), ...
     [theta_stop theta_stop],[ymin ymax],'r--',...
     [-theta_pass -theta_pass],[ymin ymax],'r--',...
     [-theta_stop -theta_stop],[ymin ymax],'r--',...
     [theta_pass theta_pass],[ymin ymax],'r--');
xlabel('look angle'), ylabel('mag y(theta) in dB');
axis([-180 180 ymin ymax]);

% polar plot
figure(2), clf
zerodB = 50;
dBY = 20*log10(abs(y)) + zerodB;
plot(dBY.*cos(pi*theta/180), dBY.*sin(pi*theta/180), '-');
axis([-zerodB zerodB -zerodB zerodB]), axis('off'), axis('square')
hold on
plot(zerodB*cos(pi*theta/180),zerodB*sin(pi*theta/180),'k:') % 0 dB
plot( (min_sidelobe_level + zerodB)*cos(pi*theta/180), ...
      (min_sidelobe_level + zerodB)*sin(pi*theta/180),'k:')  % min level
text(-zerodB,0,'0 dB')
text(-(min_sidelobe_level + zerodB),0,sprintf('%0.1f dB',min_sidelobe_level));
plot([0 60*cos(theta_pass*pi/180)], [0 60*sin(theta_pass*pi/180)], 'k:')
plot([0 60*cos(-theta_pass*pi/180)],[0 60*sin(-theta_pass*pi/180)],'k:')
plot([0 60*cos(theta_stop*pi/180)], [0 60*sin(theta_stop*pi/180)], 'k:')
plot([0 60*cos(-theta_stop*pi/180)],[0 60*sin(-theta_stop*pi/180)],'k:')
hold off


function [ cluster, cluster_center, cluster_energy ] = ...
  cluster_energy_compute ( dim_num, point_num, cluster_num, point, ...
  cluster_center )

%*****************************************************************************80
%
%% CLUSTER_ENERGY_COMPUTE computes the energy of the clusters.
%
%  Discussion:
%
%    The cluster energy is defined as the sum of the distance
%    squared from each point to its cluster center.  It is the goal
%    of the H-means and K-means algorithms to find, for a fixed number
%    of clusters, a clustering that minimizes this energy
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 October 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer DIM_NUM, the number of spatial dimensions.
%
%    Input, integer POINT_NUM, the number of data points.
%
%    Input, integer CLUSTER_NUM, the number of clusters.
%
%    Input, real  POINT(DIM_NUM,POINT_NUM), the data points.
%
%    Input, integer CLUSTER(POINT_NUM), the cluster to which each
%    data point belongs.
%
%    Input, real CLUSTER_CENTER(DIM_NUM,CLUSTER_NUM), the centers.
%
%    Output, real CLUSTER_ENERGY(CLUSTER_NUM), the energy
%    associated with each cluster.
%
  cluster_energy(1:cluster_num) = 0.0;

  for i = 1 : point_num

    j = cluster(i);

    point_energy = sum ( ...
      ( point(1:dim_num,i) - cluster_center(1:dim_num,j) ).^2 );

    cluster_energy(j) = cluster_energy(j) + point_energy;

  end

  return
end


function y = pmean(x,p)
%Calculates generalized mean
% x = vector subject to generalized mean calculations. Can be also matrix.
% p = parameter for generalized mean.
% y = generalized mean value.
y = (sum(x.^p,1)/size(x,1)).^(1/p);