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

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{:})

Related

Solve complex matrix equation

I have a complex equation involving matrices:
R = expm(X)*A + (expm(X)-I)*inv(X)*B*U;
where R, B and U are known matrices.
I is an identity matrix.
I need to solve for X. Is there any way to solve this in MATLAB?
If your equation is nonlinear and you have access to MATLAB optimization toolbox you can use the fsolve function (You can still use it for a linear equation, but it may not be the most efficient approach). You just need to reformat your equation into the form F(x) = 0, where x is a vector or a matrix. For example, if X is a vector of length 2:
Define your function to solve:
function F = YourComplexEquation(X)
Fmatrix = expm(X)*A + (expm(X)-I)*inv(X)*B*U - R
% This last line is because I think fsolve requires F to be a vector, not a matrix
F = Fmatrix(:);
Then call fsolve with an initial guess:
X = fsolve(#YourComplexEquation,[0;0]);

Using "subs" Function to Evaluate Output of "dsolve" Give Extra Output in Maltab

Introduction
If you want to know the grand scheme... read the introduction. If not, Just skip down to My Problem.
I have a project for my Differential Equations and Linear Algebra course where I have to use a computer algebra system to solve both linear, ordinary differential equations of the first degree with constant coefficients and a non-linear ODE with constant coefficients. I have to show this being done both analytically and numerically. My plan is to have 2 functions that make use of the dsolve function for the analytical part and a function called ODE1 I learned about through this tutorial by Matlab. This function is defined to approximate the solution to the differential equation using Euler's Method. The functions would all use the same input parameters so each input could be defined once and the functions would all understand what inputs to use (maybe nest the functions under one calling function). The goal is to evaluate the analytical solution over the same interval being used to find the numerical approximation and compare the results in both a table and graph. I got the numerical solution to give me a "table" in the form of a row vector and also graph that row vector. I began having an issue with the Analytic solution...
My Problem
To solve a linear ODE of the first order, I generated this function
function [s1] = L_Analytic(eqn,t0,h,numstep,y0)
% eqn is the differential equation to be solved
% t0 is the start of the interval that the resulting equation is to be evaluated at
% h is the stepsize
% numstep is the number of steps
% y0 is the initial condition
syms y(x)
cond = y(0) == y0;
A = dsolve(eqn,cond);
s1 = A;
S1 = s1;
for t = t0 : h : h*(numstep-2)
S1 = [subs(S1); vpa(subs(s1))]
end
end
The list generated by this function L_Analytic(diff(y)==y, 0, 0.1, 5, 1) is
1
1.0
1.105170...
1.221402...
1.349858...
When using the numerical method in a different function in Matlab using the same inputs, I get the list:
1.0000
1.1000
1.2100
1.3310
1.4641
For those who know their way around differential equations or are proficient in calculus, the solution to y' = y is e^x, and when evaluated over the interval 0:0.4 using 5 steps, the list should be
1
1.105...
1.2214...
1.3498...
1.4918...
after some rounding.
So the issue here is that I have an extra entry of 1 in my analytical solutions. I'm confident it has something to do with the subs(S1) part of S1 = [subs(S1); vpa(subs(s1))] in the for loop but I am stumped as to how to fix this.
I kind of understand why I need to use the subs function, in that I am using symbolic variables to use the dsolve function which outputs symbolic variables in its answer. Also, in order for the for loop to iterate and change, the symbolic variables must be substituted for real values of t each time. I did try moving the vpa(subs(s1)) just before the for loop, but this just returned the same value in the vector 5 times. I also tried not using subs(S1) and it gave me
exp(t)
1.0
1.1051709...
1.2214027...
1.3498588...
so I'm positive it's this part of the code.
Side Note: I understand the analytical method outputs a column vector as does the ODE1 shown in the video that's linked. In order to have Matlab plot this as one line, I transposed the column vector to make a row vector and will do the same with the analytical solution once the solution part is fixed.
By changing the internals of the for loop I made it work. My final function code turned out to be this:
function [s1] = L_Analytic3(eqn,t0,h,numstep,y0)
%Differential Equation solver for specific inputs
% eqn is the differential equation
% t0 is start of evaluation interval
% h is stepize
% numstep is the number of steps
% y0 is the initial condition
syms y(x)
cond = y(0) == y0;
A = dsolve(eqn, cond);
s1 = A;
S1 = s1;
for x = t0 : h : h*(numstep)
subs(x);
if x == t0
S1 = subs(s1,x);
else
S1 = [subs(S1), subs(s1,vpa(x))];
end
end
end

MATLAB: How to solve high dimensional nonlinear ODE?

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.

Solving a Second Order Differential with Matrix input

I am trying to solve a second order differential using ODE45 in Matlab with matrix as inputs. I am struck with couple of errors that includes :
"In an assignment A(I) = B, the number of elements in B and
I must be the same."
Double order differential equations given below:
dy(1)= diag(ones(1,100) - 0.5*y(2))*Co;
dy(2)= -1 * Laplacian(y(1)) * y(2);
Main function call is:
[T,Y] = ode45(#rigid,[0.000 100.000],[Co Xo]);
Here, Co is Matrix of size 100x100 and Xo is a column matrix of size 100x1. Laplacian is a pre-defined function to compute matrix laplacian.
I will appreciate any help in this. Should I reshape input matrices and vectors to fall in same dimensions or something?
Your guess is correct. The MATLAB ode suite can solve only vector valued ode, i.e. an ode of the form y'=f(t,y). In your case you should convert y, and dy, back and forth between a matrix and an array by using reshape.
To be more precise, the initial condition will be transformed into the array
y0 = reshape([Co Xo], 100*101, 1);
while y will be obtained with
y_matrix = reshape(y, 100, 101);
y1 = y_matrix(:,1:100);
y2 = y_matrix(:,101);
After having computed the matrices dy1 and dy2 you will have to covert them in an array with
dy = reshape([dy1 dy2], 100*101, 1);
Aside from the limitations of ode45 your code gives that error because, in MATLAB, matrices are not indexed in that way. In fact, if you define A = magic(5), A(11) gives the eleventh element of A i.e. 1.

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.