MATLAB: How to solve high dimensional nonlinear ODE? - matlab

I have an ODE:
x' = -x + f(x)
Looks simple enough, but x is 100 dimensional i.e.
x = [x1, ... , x100]
Furthermore,
fi(x) = ln(xi)/(ln(x1)+...+ln(x100))
where i is between 1 and 100 and f(x) = [f1(x), ... , f100(x)]
On MATLAB's website, it says I should first create a function as:
But how can I do this? I have 100 variables, and all my variables are coupled through that highly nonlinear function.
Any help is greatly appreciated!

The function can leverage the vectorization capabilities of MATLAB since, from the ode45 documentation, the "function dydt = odefun(t,y), for a scalar t and a column vector y, must return a column vector dydt". So your odefun can be expressed simply as
function dxdt = odefun(~,x)
logX = log(x);
dxdt = -x + logX/sum(logX);
end
and let ode45, or another appropriate integrator, handle the rest.

Related

Solve a non-linear system of equations with differentiation in Matlab

I would like to solve a system of non-linear equations in Matlab with fsolve, but I also have to differentiate the functions with respect to two variables. Here is the problem in steps:
Step 1: I define the system of non-linear functions F:
function F = root2d(x)
F(1) = (exp(-x(1)+2)/(1+exp(-x(1)+2)+exp(-x(2)+1)));
F(2) = (exp(-x(2)+1)/(1+exp(-x(1)+2)+exp(-x(2)+1)));
end
Step 2: I want to find the derivative of F(1) with respect to x(1) and the derivative of F(2) with respect to x(2) such that:
function F = root2d(x)
F(1) = (exp(-x(1)+2)/(1+exp(-x(1)+2)+exp(-x(2)+1)));
F(2) = (exp(-x(2)+1)/(1+exp(-x(1)+2)+exp(-x(2)+1)));
f1_d=diff(F(1),x(1))
f1_d=diff(F(2),x(2))
end
Step 3: I want my function to be the original one plus the derivative:
function F = root2d(x)
F(1) = (exp(-x(1)+2)/(1+exp(-x(1)+2)+exp(-x(2)+1)));
F(2) = (exp(-x(2)+1)/(1+exp(-x(1)+2)+exp(-x(2)+1)));
f1_d=diff(F(1),x(1));
f1_d=diff(F(2),x(2));
F(1)=F(1)+f1_d;
F(2)=F(2)+f2_d;
end
Step 4: In the main file I would use this function with fsolve to solve the system of non-linear equations for x(1) and x(2):
syms x
fun = #root2d;
x0 = [0,0];
x = fsolve(fun,x0);
root2d(x)
function F = root2d(x)
F(1) = (exp(-x(1)+2)/(1+exp(-x(1)+2)+exp(-x(2)+1)));
F(2) = (exp(-x(2)+1)/(1+exp(-x(1)+2)+exp(-x(2)+1)));
f1_d=diff(F(1),x(1));
f1_d=diff(F(2),x(2));
F(1)=F(1)+f1_d;
F(2)=F(2)+f2_d;
end
Can you please help me, how can a rewrite my code in order to solve the derivatives and then calculate and solve the system? Calculation of the derivates by hand is not an option because later I have to develop this program and I will have about 100 equations instead of 2.
A fundamental problem that you're making is that you're solving this system numerically with fsolve but then mixing in symbolic math.
Since your functions, F don't seem to vary, their derivatives shouldn't either, so you can create them as symbolic functions and calculate their derivatives symbolically once:
syms x [1 2] real; % Create 1-by-2 symbolic vector
F = exp(-x+2)/(1+exp(-x(1)+2)+exp(-x(2)+1));
F_d(1) = diff(F(1),x(1));
F_d(2) = diff(F(2),x(2));
F = F+F_d; % Add derivatives to original functions
Then you can convert these to a numerical form and solve with fsolve:
root2d = matlabFunction(F,'Vars',{x}); % Convert symbolic function to vectorized numeric function
x0 = [0 0];
x = fsolve(root2d,x0)
root2d(x)
Note that fsolve only finds a single root (if it succeeds) for a given initial guess. It's strongly suggested that you plot your function to understand it's behavior and how many roots it may have. From my limited plotting it doesn't look like this function, as defined above, has any zeros. Separately, you should also look into the tolerance options for fsolve.
You can look into purely numerical (non-symbolic) methods to solve this, but you'll need properly calculate the derivative numerically. You might look into this approach for that.

how to plot a graph with different equations depending on the 'x' value

dx = 0.1
x = 0:dx:30:
for x<5, f(x)= 0.1*(x^4)-5.6*(x^3)+3.6*(x^2)–16.2*(x^3)+6.2*(x^2)+11.5*(x)-9.8
for 5<=x<20, f(x)= 0.4*(x^3)+1.2(x^2)+9.7*(x)–89.6
for 20<=x, f(x)= 0.8*(x^2)+8.9*(x)-8.2
I have tried using a for loop with if and elseif statements but cant make it work, if someone could help that would be great
A piecewise function that uses a symbolic variable syms x might suffice in this case. The piecewise function allows you to plot multiple functions over only a distinct bounds/regions. It is also possible with anonymous functions and different x vectors as input.
syms x
f1=0.1*(x^4)-5.6*(x^3)+3.6*(x^2)-16.2*(x^3)+6.2*(x^2)+11.5*(x)-9.8;
f2=0.4*(x^3)+1.2*(x^2)+9.7*(x)-89.6;
f3=0.8*(x^2)+8.9*(x)-8.2;
Bounds_1 = x<5;
Bounds_2 = 5<=x<20;
Bounds_3 = 20<=x;
y = piecewise(Bounds_1,f1,Bounds_2,f2,Bounds_3,f3);
fplot(y);
xlim([-5 50]);

Evaluating a complex integral in MATLAB

Hello I'm trying to integrate the following function in MATLAB
And this is my attempt at evaluating it at a given (x,y)
fun = #(t,x,y) exp(1i.*(t.^4+x.*t.^2+y.*t));
P = #(x,y) integral(#(t)fun(t,x,y),-Inf,Inf);
P(1,1)
According to WolframAlpha the answer is 1.20759 + 0.601534 i for P(1,1)
but MATLAB returns -6.459688464052636e+07 - 8.821747942103466e+07i
I am wondering how to enter an integral like this correctly.
I have now also tried evaluating this symbolically and using a taylor series to approximate but still no luck.
syms x y t
x=1
y=1
f = exp(1i*(t^4+x*t^2+y*t));
fApprox = taylor(f, t, 'ExpansionPoint', 0, 'Order', 10)
sol=int(fApprox,t,[-inf inf])
Any additional suggestions
Many thanks in advance.

Fitting data in least square sense to nonlinear equation

I need help fitting data in a least square sense to a nonlinear function. Given data, how do I proceed when I have following equation?
f(x) = 20 + ax + b*e^(c*2x)
So I want to find a,b and c. If it was products, I would linearize the function by takin the natural logaritm all over the function but I can not seem to do that in this case.
Thanks
You can use the nlinfit tool, which doesn't require the Curve Fitting Toolbox (I don't think...)
Something like
f = #(b,x)(20 + b(1)*x + b(2)*exp(b(3)*2*x));
beta0 = [1, 1, 1];
beta = nlinfit(x, Y, f, beta0);
When MATLAB solves this least-squares problem, it passes the coefficients into the anonymous function f in the vector b. nlinfit returns the final values of these coefficients in the beta vector. beta0 is an initial guess of the values of b(1), b(2), and b(3). x and Y are the vectors with the data that you want to fit.
Alternatively, you can define the function in its own file, if it is a little more complicated. For this case, you would have something like (in the file my_function.m)
function y = my_function(b,x)
y = 20 + b(1)*x + b(2)*exp(b(3)*2*x);
end
and the rest of the code would look like
beta0 = [1, 1, 1];
beta = nlinfit(x, Y, #my_function, beta0);
See also: Using nlinfit in Matlab?
You can try the cftool which is an interactive tool for fitting data. The second part I don't quite understand. It may help if you describe it in more detail.

Create a symbolic function of different length vectors in MATLAB Symbolic Toolbox

My overall goal is to use the MATLAB symbolic toolbox to simplify the process of formulating and solving for the sensitivities of solutions to ordinary differential equations with respect to the parameters in the equations. In my case I have an ODE with 2 states and 10 parameters. A smaller, but representative, example would look like
X = sym('X', [2 1]) % Vector representing state variables
p = sym('p', [3 1]) % Vector representing parameters
% Fitzhugh Nagumo Equations
rhs_1 = symfun(p(3)*(X(1) - X(1)^3/3 + X(2)), [X; p])
rhs_2 = symfun(-(X(1) - p(1) + p(2)*X(2))/p(3), [X; p])
I can then get the partial derivatives, which are used to solve for the sensitivities, of the RHS of the ODE wrt to the parameters using a command like 'gradient(rhs_1, p)'. But then I would like to convert this gradient to a matlab function that is a function of the vectors X and p, not a function of the elements of these vectors. I need these functions to be of this form because otherwise I cannot use the CVODES solver in the sundialsTB toolbox. Is this possible? Is there an easier way to accomplish what I am trying to do?
Recognizing that a comma-separated list of function inputs is really just a cell array, you can do this by converting your vector inputs to a cell arrays of scalar using mat2cell:
x=1:2;
p=1:3;
v = mat2cell([x(:);p(:)],ones(numel(x)+numel(p),1),1);
y1 = rhs_1(v{:})
y2 = rhs_2(v{:})