I would like to make numerical simulations of n-species sharing the common resource in Matlab. My system is of the form;
dx_n/dt=x_n(2 - x_{n-1} - x_n),
dx_{n-1}/dt=x_{n-1}(3 - x_{n-2} - x_{n-1} - x_n).
I have written a code for "n=5" as follows;
dx = #(t,x) [
x(1); x(1)*(2-x(1)-x(2));
x(2); x(2)*(3-x(2)-x(2)-x(3));
x(3); x(3)*(3-x(2)-x(3)-x(4));
x(4); x(4)*(3-x(3)-x(4)-x(5));
x(5); x(5)*(2-x(4)-x(5))];
tspan=[0 15];
x0=[0 2 0 3 0 4 0 6 0 8]
[t,x]=ode45(#(t,x) dx(t,x), tspan, x0);
figure(1)
plot(t,x)
My question is, "Is there an easier way in which I can write a general code for any 'n'?". Can someone please help me. I'm new to Matlab.
Seems very tricky, if not impossible, to code the differential in an anonymous function as you did for n=5.
So you have to put the math into an explicit (not anonymous) function
function dx = spdiff(t,x)
n = len(x);
dx(1) = x(1);
dx(2) = x(1) .* (2 - x(1) - x(2));
for k = 2:(n-1)
dx(2*k-1) = x(k);
dx(2*k) = x(k) .* (3 - x(k-1) - x(k) - x(k+1));
end
dx(2*n-1) = x(n);
dx(2*n) = x(n) .* (2 - x(n-1) - x(n));
And then to solve it
[t,x]=ode45(#spdiff, tspan, x0);
Addressing the comment...
Let's use the set of ODE in original question, I have written out the complete code above.
To get the derivative of the original system in one line use
dx = #(t,x) x.*conv(1-x, [1 1 1], 'same')
1-x produces the vector with entries 1-x(k), convolution with [1 1 1] produces the array
[ 1-x(1), 2-x(1)-x(2), 3-x(1)-x(2)-x(3), 3-x(2)-x(3)-x(4),...
..., 3-x(n-2)-x(n-1)-x(n), 2-x(n-1)-x(n), 1-x(n)]
The option shape='same' reduces that to the central part, that is, cuts away the first and last element. Then with elementwise multiplication you get exactly the right side of the formula.
One integration with the initial values from the question divided by 10 looks like
In gnu-octave, which is similar to matlab, the following code produces a similar graph
dx = #(x,t) x.*conv(1-x, [1 1 1], 'same')
tspan = 0:0.1:10;
x0=[0.2, 0.3, 0.4, 0.6, 0.8];
sol = lsode(dx, x0, tspan );
plot(tspan, sol)
Related
Here is the equation in WolframAlpha returning me the correct answer.
In MATLAB, I've written the following:
mu = 305; %as a temporary example since it's greater than c, which is 300
syms x
eqn = ((1 + (x/(mu + 300)))^((1/2) + (150/mu)))*((1 - (x/(mu - 300)))^((1/2) - (150/mu))) - 0.2 == 0 %matlab shows the answer is -605
solve(eqn,x)
It's the same equation, except MATLAB substitutes for mu for me. MATLAB is returning the following:
eqn = logical 0
ans = x
Am I typing the equation in wrong somehow? Is that why it's showing me a logical zero when I'm not suppressing the equation? How do I get it to result in the same values as WolframAlpha?
I also want to note that Maple seems to hang on this same equation as well.
Unless you have a specific reason for using symbolic expressions, you can solve the equation that you have using fsolve as follows:
%Define your value of mu
mu = 305;
% Define the equation as an anonymous function
fn = #(x) ((1 + (x/(mu + 300)))^((1/2) + (150/mu)))*((1 - (x/(mu - 300)))^((1/2) - (150/mu))) - 0.2;
% Define the initial value for x so that fsolve can find the root nearest to that
x0 = 1;
root_x = fsolve(fn, x0);
This leads to the output root_x = 5.0000 + 0.0000i
You can also change the initial value of x0
x0 = 400;
root_x = fsolve(fn, x0);
This will return the output root_x = -4.9005e+02 - 2.6326e-05i
This method can be used to solve any of the equations that you might have.
I have based my solution off the example provided by Matlab - solving a third order differential equation.
My problem is that I have to solve the third order differential equation, y'''+3y''+2y'+y=4u, by using the ode23 solver and plot the step response.
Here is what I have so far.
function dy = diffuy( t, y )
%Split uy into variables in equation
%y'''+3y''+2y'+y=4u
%Have to take third order equation and convert to 1st order
%y0 = y
%y1 = y0'
%y2 = y1'
%y3 = y2'
%y0' = y1
%y1' = y2
%y2' = y3
%y3' = y''' = -3*y2-2*y1-y0+4*u
%Assume that y(0)= 0, y'(0)=0, y''(0)=0, no initial conditions
u = #(t) heaviside(t);
dy = zeros(4,1);
dy(1) = y(2);
dy(2) = y(3);
dy(3) = y(4);
dy(4) = -3*y(3)-2*y(2)-y(1)+4*u(t);
end
In my main file, I have the code:
[T, Y]=ode23(#diffuy,[0 20],[0 0 0 0]);
figure(1)
plot(T,Y(:,1))
A=[0 1 0;0 0 1; -1 -2 -3]
B=[0;0;4]
C=[1 0 0]
D=[0]
sys4=ss(A,B,C,D)
figure(2)
step(sys4)
The problem I am having is that the step response produced from using the state-space representation commands in MATLAB do not match the step response produced by the ode23, so I assumed that I solved the differential equation incorrectly. Any tips or comments would be very helpful.
Step Response from ss commands:
Step Response from using ode23:
I'm not sure how the linked question got the correct answer because you're actually solving a fourth-order equation using their methodology.
The right hand-side vector given to the ODE suite should only have n entries for an n-order problem.
In your case, the change of variables
results in the third order system
with the initial conditions
.
Changing diffuy to
function dy = diffuy( t, y )
dy = zeros(3,1);
dy(1) = y(2);
dy(2) = y(3);
dy(3) = -3*y(3)-2*y(2)-y(1)+4*u(t);
end
gives a solution that matches the state-space model.
How can I use matlab to solve the following Ordinary Differential Equations?
x''/y = y''/x = -( x''y + 2x'y' + xy'')
with two known points, such as t=0: x(0)= x0, y(0) = y0; t=1: x(1) = x1, y(1) = y1 ?
It doesn't need to be a complete formula if it is difficult. A numerical solution is ok, which means, given a specific t, I can get the value of x(t) and y(t).
If matlab is hard to do this, mathematica is also OK. But as I am not familiar with mathematica, so I would prefer matlab if possible.
Looking forward to help, thanks!
I asked the same question on stackexchange, but haven't get good answer yet.
https://math.stackexchange.com/questions/812985/matlab-or-mathematica-solve-ordinary-differential-equations
Hope I can get problem solved here!
What I have tried is:
---------MATLAB
syms t
>> [x, y] = dsolve('(D2x)/y = -(y*D2x + 2Dx*Dy + x*D2y)', '(D2y)/x = -(y*D2x + 2Dx*Dy + x*D2y)','t')
Error using sym>convertExpression (line 2246)
Conversion to 'sym' returned the MuPAD error: Error: Unexpected 'identifier'.
[line 1, col 31]
Error in sym>convertChar (line 2157)
s = convertExpression(x);
Error in sym>convertCharWithOption (line 2140)
s = convertChar(x);
Error in sym>tomupad (line 1871)
S = convertCharWithOption(x,a);
Error in sym (line 104)
S.s = tomupad(x,'');
Error in dsolve>mupadDsolve (line 324)
sys = [sys_sym sym(sys_str)];
Error in dsolve (line 186)
sol = mupadDsolve(args, options);
--------MATLAB
Also, I tried to add conditions, such as x(0) = 2, y(0)=8, x(1) = 7, y(1) = 18, and the errors are still similar. So what I think is that this cannot be solve by dsolve function.
So, again, the key problem is, given two known points, such as when t=0: x(0)= x0, y(0) = y0; t=1: x(1) = x1, y(1) = y1 , how I get the value of x(t) and y(t)?
Update:
I tried ode45 functions. First, in order to turn the 2-order equations into 1-order, I set x1 = x, x2=y, x3=x', x4=y'. After some calculation, the equation becomes:
x(1)' = x(3) (1)
x(2)' = x(4) (2)
x(3)' = x(2)/x(1)*(-2*x(1)*x(3)*x(4)/(1+x(1)^2+x(2)^2)) (3)
x(4)' = -2*x(1)*x(3)*x(4)/(1+x(1)^2+x(2)^2) (4)
So the matlab code I wrote is:
myOdes.m
function xdot = myOdes(t,x)
xdot = [x(3); x(4); x(2)/x(1)*(-2*x(1)*x(3)*x(4)/(1+x(1)^2+x(2)^2)); -2*x(1)*x(3)*x(4)/(1+x(1)^2+x(2)^2)]
end
main.m
t0 = 0;
tf = 1;
x0 = [2 3 5 7]';
[t,x] = ode45('myOdes',[t0,tf],x0);
plot(t,x)
It can work. However, actually this is not right. Because, what I know is that when t=0, the value of x and y, which is x(1) and x(2); and when t=1, the value of x and y. But the ode functions need the initial value: x0, I just wrote the condition x0 = [2 3 5 7]' randomly to help this code work. So how to solve this problem?
UPDATE:
I tried to use the function bvp4c after I realized that it is a boundary value problem and the following is my code (Suppose the two boundry value conditions are: when t=0: x=1, y=3; when t=1, x=6, y=9. x is x(1), y is x(2) ):
1. bc.m
function res = bc(ya,yb)
res = [ ya(1)-1; ya(2)-3; yb(1) - 6; yb(2)-9];
end
2. ode.m
function dydx = ode(t,x)
dydx = [x(3); x(4); x(2)/x(1)*(-2*x(1)*x(3)*x(4)/(1+x(1)^2+x(2)^2)); -2*x(1)*x(3)*x(4)/(1+x(1)^2+x(2)^2)];
end
3. mainBVP.m
solinit = bvpinit(linspace(0,6,10),[1 0 -1 0]);
sol = bvp4c(#ode,#bc,solinit);
t = linspace(0,6);
x = deval(sol,t);
plot(t,x(1,:));
hold on
plot(t,x(2,:));
plot(t,x(3,:));
plot(t,x(4,:));
x(1,:)
x(2,:)
It can work, but I don't know whether it is right. I will check it again to make sure it is the right code.
As mentioned, this isn't a math site, so try to give code or something showing some effort.
However, the first step you need to do is turn the DE into normal form (i.e., no 2nd derivatives). You do this by making a separate variable equal to the derivative. Then, you use
syms x y % or any variable instead of x or y
to define variables as symbolic. Use matlabfunction to create a symbolic function based on these variables. Finally, you can use the ode45 function to solve the symbolic function while passing variable values. I recommend you look up the full documentation in matlab in order to understand it better, but here is a very basic syntax:
MyFun= matlabFunction(eq,'vars',{x,y});
[xout,yout]=ode45(#(x,Y) MyFun(variables),[variable values],Options);
Hopefully this puts you in the right direction, so try messing around with it and provide code if you need more help.
EDIT:
This is how I would solve the problem. Note: I don't really like the matlabFunction creator but this is simply a personal preference for various reasons I won't go into.
% Seperate function of the first order state equations
function dz = firstOrderEqns(t,z)
dz(4,1) = 0;
dz(1) = -2.*z(3).*z(1).*z(4)./(1 + z(4).^2 + z(2).^2);
dz(2) = z(1);
dz(3) = -2.*z(2).*z(3).*z(1)./(1 + z(4).^2 + z(2).^2);
dz(4) = z(3);
end
% runfirstOrderEqns
%% Initial conditions i.e. # t=0
z1 = 5; % dy/dt = 5 (you didn't specify these initial conditions,
% these will depend on the system which you didn't really specify
z2 = 0; % y = 0
z3 = 5; % dx/dt = 5 (The same as for z1)
z4 = 0; % x = 0
IC = [z1, z2, z3, z4];
%% Run simulation
% Time vector: i.e closed interval [0,20]
t = [0,20]; % This is where you have to know about your system
% i.e what is it's time domain.
% Note: when a system has unstable poles at
% certain places the solver can crash you need
% to understand these.
% using default settings (See documentation ode45 for 'options')
[T,Y] = ode45(#firstOrderEqns,t,IC);
%% Plot function
plot(T,Y(:,1),'-',T,Y(:,2),'-.',T,Y(:,3),':',T,Y(:,4),'.');
legend('dy/dt','y','dx/dt','x')
As in my comments I have made a lot of assumtions that you need to fix for example, you didn't specify what the initial conditions for the first derivatives of the states are i.e. (z1, z3) which is important for the response of the system. Also you didn't specify the time interval your interested for the simulation etc.
Note: The second m file can be used with any state function in the correct format
The following is the answer we finally get #Chriso: use matlab bvp4c function to solve this boundary value problem (Suppose the two boundry value conditions are: when t=0: x=1, y=3; when t=1, x=6, y=9. x is x(1), y is x(2) ):
1. bc.m
function res = bc(ya,yb)
res = [ ya(1)-1; ya(2)-3; yb(1) - 6; yb(2)-9];
end
2. ode.m
function dydx = ode(t,x)
dydx = [x(3); x(4); x(2)/x(1)*(-2*x(1)*x(3)*x(4)/(1+x(1)^2+x(2)^2)); -2*x(1)*x(3)*x(4)/(1+x(1)^2+x(2)^2)];
end
3. mainBVP.m
solinit = bvpinit(linspace(0,6,10),[1 0 -1 0]);
sol = bvp4c(#ode,#bc,solinit);
t = linspace(0,6);
x = deval(sol,t);
plot(t,x(1,:));
hold on
plot(t,x(2,:));
plot(t,x(3,:));
plot(t,x(4,:));
x(1,:)
x(2,:)
If I have an ode and wrote it in two ways, like here:
function re=rabdab()
x=linspace(0,2000,2000)';
tic;
[T,Y] = ode45(#fun,[x],[0 1 1]);
[T,Y] = ode45(#fun,[x],[0 1 1]);
[T,Y] = ode45(#fun,[x],[0 1 1]);
toc;
tic;
[A,B] = ode45(#fun2,[x],[0 1 1]);
[A,B] = ode45(#fun2,[x],[0 1 1]);
[A,B] = ode45(#fun2,[x],[0 1 1]);
toc;
function dy = fun(t,y)
dy = zeros(3,1); % a column vector
dy = [y(2) * y(3);...
-y(1) * y(3);...
-0.51 * y(1) * y(2);];
function dy = fun2(t,y)
dy = zeros(3,1); % a column vector
dy(1) = y(2) * y(3);
dy(2) = -y(1) * y(3);
dy(3) = -0.51 * y(1) * y(2);
There is almost no difference in time. One takes just as long as the other. But I thought that fun is the vectorized version of fun2. Or am I mistaken here?
The purpose is to speed up my code a little. The example is taken from the matlab webpage.
I think I haven't really understood what "vectorized" means.
If this is already vectorized, what would a non-vectorized code look like?
Vectorization is a concept which is closely related to functional programming. In MATLAB it means performing operations on arrays (vectors or matrices) without implicitly writing a loop.
For example, if you were to compute the function f(x) = 2x for every integer x between 1 and 100, you could write:
for x = 1:100
f(x) = 2 * x;
end
which is not vectorized code. The vectorized version is:
x = 1:100; %// Declare a vector of integer values from 1 to 100
f = 2 * x; %// Vectorized operation "*"
or even shorter:
f = 2 * (1:100);
MATLAB is an interpreted language, so obviously the interpreter translates this into some kind of loop "under the hood", but it's optimized and is usually much faster than actually interpreting a loop (read this question for reference). Well, sort of -- it's been like that until the recent releases of MATLAB, where JIT acceleration has been integrated (read here).
Now getting back to your code: what you have here is two vectorized versions of your code: one that concatenates vertically three values and one that directly assigns these values into a column vector. That's basically the same thing. Should you have done it with an explicit for loop, this would not have been "vectorized". Regarding the actual performance gain from "vectorizing" a loop (that is, converting a for loop into a vectorized operation), this depends on the how fast the for loop actually was due to JIT acceleration in the first place.
It doesn't seem that there's much to be done to speed up your code. Your functions are pretty basic, so it boils down to the internal implementation of ode45, which you cannot modify.
If you're interested in further reading about vectorization and writing faster MATLAB code in general, here's an interesting article: Loren on the Art of MATLAB: "Speeding Up MATLAB Applications".
Happy coding!
While the previous answer is correct in general terms, vectorized in the context of ODEs means something more specific. In short, a function f(t,y) is vectorized iff f(t,[y1 y2 ...]) returns [f(t,y1) f(t,y2) ...], for y1,y2 column vectors. As per the documentation [1], "this allows the solver to reduce the number of function evaluations required to compute all the columns of the Jacobian matrix."
Functions fun3 and fun4 below are properly vectorized in the ODE sense:
function re=rabdab()
x=linspace(0,20000,20000)';
opts=odeset('Vectorized','on');
tic;
[T,Y] = ode45(#fun,[x],[0 1 1]);
[T,Y] = ode45(#fun,[x],[0 1 1]);
[T,Y] = ode45(#fun,[x],[0 1 1]);
toc;
tic;
[A,B] = ode45(#fun2,[x],[0 1 1]);
[A,B] = ode45(#fun2,[x],[0 1 1]);
[A,B] = ode45(#fun2,[x],[0 1 1]);
toc;
tic;
[A,B] = ode45(#fun3,[x],[0 1 1],opts);
[A,B] = ode45(#fun3,[x],[0 1 1],opts);
[A,B] = ode45(#fun3,[x],[0 1 1],opts);
toc;
tic;
[A,B] = ode45(#fun4,[x],[0 1 1],opts);
[A,B] = ode45(#fun4,[x],[0 1 1],opts);
[A,B] = ode45(#fun4,[x],[0 1 1],opts);
toc;
function dy = fun(t,y)
dy = zeros(3,1); % a column vector
dy = [y(2) * y(3);...
-y(1) * y(3);...
-0.51 * y(1) * y(2);];
function dy = fun2(t,y)
dy = zeros(3,1); % a column vector
dy(1) = y(2) * y(3);
dy(2) = -y(1) * y(3);
dy(3) = -0.51 * y(1) * y(2);
function dy = fun3(t,y)
dy = zeros(size(y)); % a matrix with arbitrarily many columns, rather than a column vector
dy = [y(2,:) .* y(3,:);...
-y(1,:) .* y(3,:);...
-0.51 .* y(1,:) .* y(2,:);];
function dy = fun4(t,y)
dy = [y(2,:) .* y(3,:);... % same as fun3()
-y(1,:) .* y(3,:);...
-0.51 .* y(1,:) .* y(2,:);];
(As a side remark: omitting the unnecessary memory allocation with zeros lets fun4 run slightly faster than fun3.)
Q: What about vectorizing with respect to the first argument?
A: For the ODE solvers, the ODE function is vectorized only with respect to the second argument. The boundary value problem solver bvp4c, however, does require vectorization with respect to the first and second arguments. [1]
The official documentation [1] provides further details on ODE-specific vectorization (see section "Description of Jacobian Properties").
[1] https://www.mathworks.com/help/releases/R2015b/matlab/ref/odeset.html
I want to use Gurobi solver in Matlab, but I don't know how to calculate the required matrices (qrow and qcol).
For your reference I am copying the example provided in documentation.
0.5 x^2 - xy + y^2 - 2x - 6y
subject to
x + y <= 2
-x + 2y <= 2, 2x + y <= 3, x >= 0, y >= 0
c = [-2 -6]; % objective linear term
objtype = 1; % minimization
A = sparse([1 1; -1 2; 2 1]); % constraint coefficients
b = [2; 2; 3]; % constraint right-hand side
lb = []; % [ ] means 0 lower bound
ub = []; % [ ] means inf upper bound
contypes = '$<<
vtypes = [ ]; % [ ] means all variables are continuous
QP.qrow = int32([0 0 1]); % indices of x, x, y as in (0.5 x^2 - xy + y^2); use int64 if sizeof(int) is 8 for you system
QP.qcol = int32([0 1 1]); % indices of x, y, y as in (0.5 x^2 - xy + y^2); use int64 if sizeof(int) is 8 for you system
QP.qval = [0.5 -1 1]; % coefficients of (0.5 x^2 - xy + y^2)
Does it mean that if I have 4 decision variables than i should use 0,1,2,3 as indices for my decision variables x_1, x_2, x_3, x_4.?
Thanks
Note: I tried to use mathurl.com but I don't get how to write in proper format show that it will appear as latex text. Sorry for the notation.
This seems to be your reference. However your question seems to relate different example. You may need to show that one.
Anyway according Gurobi documentation:
The quadratic terms in the objective function should be specified by opts.QP.qrow, opts.QP.qcol, and opts.QP.qval, which correspond to the input arguments qrow, qcol, and qval of function GRBaddqpterms. They are all 1D arrays. The first two arguments, qrow and qcol, specify the row and column indices (starting from 0) of 2nd-order terms such as and . The third argument, qval, gives their coefficients.
So the answer is yes use indicies [0 1 2 3] for your decision variables x0, x1, x2, x3.