Related
I'm trying to solve the following system of differential equations with Matlab.
The parameters i use are found here
.
The problem i have is that when i run my code i get the same results regardless of the values i set for d1 and d2. Precisely, i get the same results as in the simplified version of the system, where d1,d2 = 0. Since i'm trying to replicate the results of someone else, i know that this should not be the case. Does anyone have any idea why this is happening?
% Define u_1(t,j), u_2(t,i) as:
% u_1(t,1) = x(1)
% u_2(t,1) = x(2)
% u_1(t,2) = x(3)
% u_2(t,2) = x(4)
% So
% x(1)' = x(1)*(epsilon - (epsilon/k1)*x(1) - alpha*x(2)) + d1*(rho1(x(4))*x(3) - rho1(x(2))*x(1))
% x(2)' = x(2)*(gama + beta*x(1) - (gama/k2)*x(2)) + d2*(rho2(x(3))*x(4) - rho2(x(1))*x(2))
% x(3)' = x(3)*(epsilon - (epsilon/k1)*x(3) - alpha*x(4)) + d1*(rho1(x(2))*x(1) - rho1(x(4))*x(3))
% x(4)' = x(4)*(gama + beta*x(3) - (gama/k2)*x(4)) + d2*(rho2(x(1))*x(2) - rho2(x(3))*x(4))
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
epsilon = 3;
alpha = 0.2;
gama = 0.4;
beta = 0.4;
k1 = 2;
k2 = 1;
m1 = 1;
m2 = 1;
d2 = 0.1;
d1 = 17;
% rho1(x(2)) = m1*exp(-x(2)/m1)
% rho1(x(4)) = m1*exp(-x(4)/m1)
% rho2(x(1)) = m2*exp(-x(1)/m2)
% rho2(x(3)) = m2*exp(-x(3)/m2)
g = #(t,x)[
x(1)*(epsilon - (epsilon/k1)*x(1) - alpha*x(2)) + d1*(m1*exp(-x(4)/m1)*x(3) - m1*exp(-x(2)/m1)*x(1));
x(2)*(gama + beta*x(1) - (gama/k2)*x(2)) + d2*(m2*exp(-x(3)/m2)*x(4) - m2*exp(-x(1)/m2)*x(2));
x(3)*(epsilon - (epsilon/k1)*x(3) - alpha*x(4)) + d1*(m1*exp(-x(2)/m1)*x(1) - m1*exp(-x(4)/m1)*x(3));
x(4)*(gama + beta*x(3) - (gama/k2)*x(4)) + d2*(m2*exp(-x(1)/m2)*x(2) - m2*exp(-x(3)/m2)*x(4))];
[t1,xa1] = ode45(#(t,x) g(t,x),[0 20],[4 4 4 4]);
[t2,xa2] = ode45(#(t,x) g(t,x),[0 20],[3 3 3 3]);
[t3,xa3] = ode45(#(t,x) g(t,x),[0 20],[2 2 2 2]);
[t4,xa4] = ode45(#(t,x) g(t,x),[0 20],[0.5 0.5 0.5 0.5]);
figure;
subplot(2,2,1)
plot(t1,xa1(:,1),"r",t1,xa1(:,2),"b")
title('y0 = 4')
xlabel('t')
legend({'Free Jobs','Labour Force'},'Location','southwest')
subplot(2,2,2)
plot(t2,xa2(:,1),"r",t2,xa2(:,2),"b")
title('y0 = 3')
xlabel('t')
legend({'Free Jobs','Labour Force'},'Location','southwest')
subplot(2,2,3)
plot(t3,xa3(:,1),"r",t3,xa3(:,2),"b")
title('y0 = 2')
xlabel('t')
legend({'Free Jobs','Labour Force'},'Location','southwest')
subplot(2,2,4)
plot(t4,xa4(:,1),"r",t4,xa4(:,2),"b")
title('y0 = 0.5')
xlabel('t')
legend({'Free Jobs','Labour Force'},'Location','southwest')
sgtitle('Labour Force and Free Jobs')
figure;
hold on
plot(t1,xa1(:,1),"r",t1,xa1(:,2),"b")
plot(t2,xa2(:,1),"r",t2,xa2(:,2),"b")
plot(t3,xa3(:,1),"r",t3,xa3(:,2),"b")
plot(t4,xa4(:,1),"r",t4,xa4(:,2),"b")
title('Labour Force and Free Jobs')
xlabel('t')
legend({'Free Jobs','Labour Force'},'Location','northeast')
hold off
The issue here is that you are only testing this when all your x values are equal. Look at the first term in g that contains d1
d1*(m1*exp(-x(4)/m1)*x(3) - m1*exp(-x(2)/m1)*x(1))
If all the x values are equal then that equation simplifies to just d1*0. The same is true for all other terms with a d1 or d2 in the function g. As a result, changing these values have no effect on the results. If your values of x vary then the d1 and d2 values will affect the results.
t(1)= 0;
y0= 3;
y(1)= y0;
h=0.1;
for n = 1:11
k1 = 2*y(n)+(t(n))^2;
k2 = 2*(y(n)+h/2*k1)+(t(n)+h/2^2);
k3 = 2*(y(n)+h/2*k2)+(t(n)+h/2)^2;
k4 = 2*(y(n)+h*k3)+(t(n)+h)^2;
t(n+1) = t(n)+h;
y(n+1) = y(n)+h/6*(k1+2*k2+2*k3+k4);
end
t1(1)= 0;
y1(1)= y0;
h1=0.01;
for n = 1:101
k1 = 2*y1(n)+(t1(n))^2;
k2 = 2*(y1(n)+h1/2*k1)+(t1(n)+h1/2^2);
k3 = 2*(y1(n)+h1/2*k2)+(t1(n)+h1/2)^2;
k4 = 2*(y1(n)+h1*k3)+(t1(n)+h1)^2;
t1 (n+1) = t1(n)+h1;
y1 (n+1) = y1(n)+h1/6*(k1+2*k2+2*k3+k4);
end
plot (t,y,t1,y1) will show very similar curves, In this plot MAX difference may be very small, such as 0.001, 0.0001 or whatever. Actually, I want more clearly the difference, and plot (t,y,t1,y1) doesn't work so good. I think long format for k1,..,k4 and y is appropriate. Also, I tried
z (1) = 0;
for j = 2:11
z = [ y (j) - y ( (j-1)*10*1 ) (11) ];
end
What about plotting the difference explicitly. Interpolate to get y at t1:
y_t1 = interp1(t,y,t1);
plot(t1,y_t1-y1)
On an unrelated note, you are growing a vector inside a loop. No doubt mlint has told you this is bad. Rather initialize your vectors like this:
t = zeros(1,11); % i.e. don't do this: t(1)= 0;
I am trying to solve differential equations by using ode45 solver. However, it does not work as expected.
function ydot=Untitledrt(z,y)
ydot = zeros(6,1);
%y(1)=A
%y(2)=B
%y(3)=C
%y(4)=D
%y(5)=P
%y(6)=T
m1 = 6;
m2 = 9;
m3 = 5;
k1 = 6;
k2 = 7;
k3 = 4;
k4 = 1;
c1 = 1;
c2 = 0.2;
c3 = 0.1;
c4 = 2;
F1 = 3;
F2 = 9;
F3 = 12;
ydot(1)=y(2)
ydot(2)=((-((k1+k2)./m1)).*y(1))-(((c1+c2)./m1).*y(2))+((k2./m1).*y(3))+ ((c2./m1).*y(4))+(F1./m1)
ydot(3)=y(4)
ydot(4)=((k2./m2).*y(1))+((c2./m2).*y(2))-(((k2+k3)./m2).*y(3))-(((c2+c3).*m2).*y(4))+((k3/m2).*y(5))+((c3./m2).*y(6))+(F2./m2)
ydot(5)=y(6)
ydot(6)=((k2./m3).*y(3))+((c3./m3).*y(4))-(((k3+k4)./m3).*y(5))-(((c3+c4)./m3).*y(6))+(F3./m3)
MATLAB keeps returning the following error message:
Not enough input arguments.
Error in Untitledrt (line 24)
ydot(1)=y(2)
I understand that the error is due to not defining the y terms. Some other examples of ODE45 solver codes also do not define y terms. Is there something I am missing? Or someone can please suggest something to make this code work without defining y terms. Thank you in advance.
First create an M-file which evaluates the right-hand side of the system f(t,y) for any given t, y1, y2, y3, y4, y5, y6 and name it as you Untitledrt.m.
function ydot=Untitledrt(t,y)
ydot = zeros(6,1);
m1 = 6;
m2 = 9;
m3 = 5;
k1 = 6;
k2 = 7;
k3 = 4;
k4 = 1;
c1 = 1;
c2 = 0.2;
c3 = 0.1;
c4 = 2;
F1 = 3;
F2 = 9;
F3 = 12;
ydot(1)=y(2)
ydot(2)=((-((k1+k2)./m1)).*y(1))-(((c1+c2)./m1).*y(2))+((k2./m1).*y(3))+ ((c2./m1).*y(4))+(F1./m1)
ydot(3)=y(4)
ydot(4)=((k2./m2).*y(1))+((c2./m2).*y(2))-(((k2+k3)./m2).*y(3))-(((c2+c3).*m2).*y(4))+((k3/m2).*y(5))+((c3./m2).*y(6))+(F2./m2)
ydot(5)=y(6)
ydot(6)=((k2./m3).*y(3))+((c3./m3).*y(4))-(((k3+k4)./m3).*y(5))-(((c3+c4)./m3).*y(6))+(F3./m3)
Now type in the following commands in MatLab window line by line or paste it in a new script file
[t,Y]=ode45('Untitledrt',[0 10],[1;-1;0;0;0;0]);
plot(t,Y(:,1),'+',t,Y(:,2),'x',t,Y(:,3),'o',t,Y(:,4),'o',t,Y(:,5),'o',t,Y(:,6),'o')
Plot of the six dependent variables
My following code generates a graph with a looping variable for the x-axis. Specifically, eta_22 varies from 0 to 1, with loop iteration size of 0.01.
The code below the line is the source function file.
My question is: How can I generate a graph with eta_1 varying from 0 to 1, with loop iteration size of 0.01 as well? (I want a plot of AA on the y-axis, and eta_1, eta_2 varying from 0 to 1.)
My attempts: I have tried to create nested "for" loops, but the plot itself is looping. I have tried to put the plot line outside of the "for" loops as well, but that did not work.
Thanks for any help.
global Lambda mu mu_A mu_T beta tau eta_1 eta_2 lambda_T rho_1 rho_2 gamma
alpha = 100;
TIME = 365;
eta_22 = zeros(1,alpha);
AA = zeros(1,alpha);
for m = 1:1:alpha
eta_2 = m./alpha;
eta_22(m) = m./alpha;
Lambda = 531062;
mu = (1/70)/365;
mu_A = 0.25/365;
mu_T = 0.2/365;
beta = 0.187/365;
tau = 4/365;
lambda_T = 0.1;
rho_1 = 1/60;
rho_2 = (rho_1)./(270.*rho_1-1);
gamma = 1e-3;
eta_1 = 0;
S0 = 191564208;
T0 = 131533276;
H0 = 2405659;
C0 = 1805024;
C10 = 1000000;
C20 = 1000000;
CT10 = 500000;
CT20 = 500000;
y0 = [S0, T0, H0, C0, C10, C20, CT10, CT20];
[t,y] = ode45('SimplifiedEqns',[0:1:TIME],y0);
S = y(:,1);
T = y(:,2);
H = y(:,3);
C = y(:,4);
C1 = y(:,5);
C2 = y(:,6);
CT1 = y(:,7);
CT2 = y(:,8);
N = S + T + H + C + C1 + C2 + CT1 + CT2;
HIVinf1=[0:1:TIME];
HIVinf2=[beta.*(S+T).*(C1+C2)./N];
HIVinf=trapz(HIVinf1,HIVinf2);
AA(m) = HIVinf;
end
plot(100.*eta_22,AA./1000)
_____________________________________________________________________________________________________
function ydot = SimplifiedEqns(t,y)
global Lambda mu mu_A mu_T beta tau eta_1 eta_2 lambda_T rho_1 rho_2 gamma
S = y(1);
T = y(2);
H = y(3);
C = y(4);
C1 = y(5);
C2 = y(6);
CT1 = y(7);
CT2 = y(8);
N = S + T + H + C + C1 + C2 + CT1 + CT2;
ydot = zeros(8,1);
ydot(1)=Lambda-mu.*S-beta.*(H+C+C1+C2).*(S./N)-tau.*(T+C).*(S./N);
ydot(2)=tau.*(T+C).*(S./N)-beta.*(H+C+C1+C2).*(T./N)-(mu+mu_T).*T;
ydot(3)=beta.*(H+C+C1+C2).*(S./N)-tau.*(T+C).*(H./N)-(mu+mu_A).*H;
ydot(4)=beta.*(H+C+C1+C2).*(T./N)+tau.*(T+C).*(H./N)-(mu+mu_A+mu_T+lambda_T).*C;
ydot(5)=lambda_T.*C-(mu+mu_A+rho_1+eta_1).*C1;
ydot(6)=rho_1.*C1-(mu+mu_A+rho_2+eta_2).*C2;
ydot(7)=eta_1.*C1-(mu+rho_1+gamma).*CT1;
ydot(8)=eta_2.*C2-(mu+rho_2+gamma.*(rho_1)./(rho_1+rho_2)).*CT2+(rho_1).*CT1;
end
The simplest way:
eta_1=0:1/alpha:1;
eta_2=0:1/alpha:1;
lsize=length(eta_1) % I assume eta_1 and eta_2 are of the same size
for i=1:lsize
%Update your AA(i) here
end
plot(eta_1,AA,eta_2,AA)
I asked a question a few days before but I guess it was a little too complicated and I don't expect to get any answer.
My problem is that I need to use ANN for classification. I've read that much better cost function (or loss function as some books specify) is the cross-entropy, that is J(w) = -1/m * sum_i( yi*ln(hw(xi)) + (1-yi)*ln(1 - hw(xi)) ); i indicates the no. data from training matrix X. I tried to apply it in MATLAB but I find it really difficult. There are couple things I don't know:
should I sum each outputs given all training data (i = 1, ... N, where N is number of inputs for training)
is the gradient calculated correctly
is the numerical gradient (gradAapprox) calculated correctly.
I have following MATLAB codes. I realise I may ask for trivial thing but anyway I hope someone can give me some clues how to find the problem. I suspect the problem is to calculate gradients.
Many thanks.
Main script:
close all
clear all
L = #(x) (1 + exp(-x)).^(-1);
NN = #(x,theta) theta{2}*[ones(1,size(x,1));L(theta{1}*[ones(size(x,1),1) x]')];
% theta = [10 -30 -30];
x = [0 0; 0 1; 1 0; 1 1];
y = [0.9 0.1 0.1 0.1]';
theta0 = 2*rand(9,1)-1;
options = optimset('gradObj','on','Display','iter');
thetaVec = fminunc(#costFunction,theta0,options,x,y);
theta = cell(2,1);
theta{1} = reshape(thetaVec(1:6),[2 3]);
theta{2} = reshape(thetaVec(7:9),[1 3]);
NN(x,theta)'
Cost function:
function [jVal,gradVal,gradApprox] = costFunction(thetaVec,x,y)
persistent index;
% 1 x x
% 1 x x
% 1 x x
% x = 1 x x
% 1 x x
% 1 x x
% 1 x x
m = size(x,1);
if isempty(index) || index > size(x,1)
index = 1;
end
L = #(x) (1 + exp(-x)).^(-1);
NN = #(x,theta) theta{2}*[ones(1,size(x,1));L(theta{1}*[ones(size(x,1),1) x]')];
theta = cell(2,1);
theta{1} = reshape(thetaVec(1:6),[2 3]);
theta{2} = reshape(thetaVec(7:9),[1 3]);
Dew = cell(2,1);
DewApprox = cell(2,1);
% Forward propagation
a0 = x(index,:)';
z1 = theta{1}*[1;a0];
a1 = L(z1);
z2 = theta{2}*[1;a1];
a2 = L(z2);
% Back propagation
d2 = 1/m*(a2 - y(index))*L(z2)*(1-L(z2));
Dew{2} = [1;a1]*d2;
d1 = [1;a1].*(1 - [1;a1]).*theta{2}'*d2;
Dew{1} = [1;a0]*d1(2:end)';
% NNRes = NN(x,theta)';
% jVal = -1/m*sum(NNRes-y)*NNRes*(1-NNRes);
jVal = -1/m*(a2 - y(index))*a2*(1-a2);
gradVal = [Dew{1}(:);Dew{2}(:)];
gradApprox = CalcGradApprox(0.0001);
index = index + 1;
function output = CalcGradApprox(epsilon)
output = zeros(size(gradVal));
for n=1:length(thetaVec)
thetaVecMin = thetaVec;
thetaVecMax = thetaVec;
thetaVecMin(n) = thetaVec(n) - epsilon;
thetaVecMax(n) = thetaVec(n) + epsilon;
thetaMin = cell(2,1);
thetaMax = cell(2,1);
thetaMin{1} = reshape(thetaVecMin(1:6),[2 3]);
thetaMin{2} = reshape(thetaVecMin(7:9),[1 3]);
thetaMax{1} = reshape(thetaVecMax(1:6),[2 3]);
thetaMax{2} = reshape(thetaVecMax(7:9),[1 3]);
a2min = NN(x(index,:),thetaMin)';
a2max = NN(x(index,:),thetaMax)';
jValMin = -1/m*(a2min-y(index))*a2min*(1-a2min);
jValMax = -1/m*(a2max-y(index))*a2max*(1-a2max);
output(n) = (jValMax - jValMin)/2/epsilon;
end
end
end
EDIT:
Below I present the correct version of my costFunction for those who may be interested.
function [jVal,gradVal,gradApprox] = costFunction(thetaVec,x,y)
m = size(x,1);
L = #(x) (1 + exp(-x)).^(-1);
NN = #(x,theta) L(theta{2}*[ones(1,size(x,1));L(theta{1}*[ones(size(x,1),1) x]')]);
theta = cell(2,1);
theta{1} = reshape(thetaVec(1:6),[2 3]);
theta{2} = reshape(thetaVec(7:9),[1 3]);
Delta = cell(2,1);
Delta{1} = zeros(size(theta{1}));
Delta{2} = zeros(size(theta{2}));
D = cell(2,1);
D{1} = zeros(size(theta{1}));
D{2} = zeros(size(theta{2}));
jVal = 0;
for in = 1:size(x,1)
% Forward propagation
a1 = [1;x(in,:)']; % added bias to a0
z2 = theta{1}*a1;
a2 = [1;L(z2)]; % added bias to a1
z3 = theta{2}*a2;
a3 = L(z3);
% Back propagation
d3 = a3 - y(in);
d2 = theta{2}'*d3.*a2.*(1 - a2);
Delta{2} = Delta{2} + d3*a2';
Delta{1} = Delta{1} + d2(2:end)*a1';
jVal = jVal + sum( y(in)*log(a3) + (1-y(in))*log(1-a3) );
end
D{1} = 1/m*Delta{1};
D{2} = 1/m*Delta{2};
jVal = -1/m*jVal;
gradVal = [D{1}(:);D{2}(:)];
gradApprox = CalcGradApprox(x(in,:),0.0001);
% Nested function to calculate gradApprox
function output = CalcGradApprox(x,epsilon)
output = zeros(size(thetaVec));
for n=1:length(thetaVec)
thetaVecMin = thetaVec;
thetaVecMax = thetaVec;
thetaVecMin(n) = thetaVec(n) - epsilon;
thetaVecMax(n) = thetaVec(n) + epsilon;
thetaMin = cell(2,1);
thetaMax = cell(2,1);
thetaMin{1} = reshape(thetaVecMin(1:6),[2 3]);
thetaMin{2} = reshape(thetaVecMin(7:9),[1 3]);
thetaMax{1} = reshape(thetaVecMax(1:6),[2 3]);
thetaMax{2} = reshape(thetaVecMax(7:9),[1 3]);
a3min = NN(x,thetaMin)';
a3max = NN(x,thetaMax)';
jValMin = 0;
jValMax = 0;
for inn=1:size(x,1)
jValMin = jValMin + sum( y(inn)*log(a3min) + (1-y(inn))*log(1-a3min) );
jValMax = jValMax + sum( y(inn)*log(a3max) + (1-y(inn))*log(1-a3max) );
end
jValMin = 1/m*jValMin;
jValMax = 1/m*jValMax;
output(n) = (jValMax - jValMin)/2/epsilon;
end
end
end
I've only had a quick eyeball over your code. Here are some pointers.
Q1
should I sum each outputs given all training data (i = 1, ... N, where
N is number of inputs for training)
If you are talking in relation to the cost function, it is normal to sum and normalise by the number of training examples in order to provide comparison between.
I can't tell from the code whether you have a vectorised implementation which will change the answer. Note that the sum function will only sum up a single dimension at a time - meaning if you have a (M by N) array, sum will result in a 1 by N array.
The cost function should have a scalar output.
Q2
is the gradient calculated correctly
The gradient is not calculated correctly - specifically the deltas look wrong. Try following Andrew Ng's notes [PDF] they are very good.
Q3
is the numerical gradient (gradAapprox) calculated correctly.
This line looks a bit suspect. Does this make more sense?
output(n) = (jValMax - jValMin)/(2*epsilon);
EDIT: I actually can't make heads or tails of your gradient approximation. You should only use forward propagation and small tweaks in the parameters to compute the gradient. Good luck!