Use symbolic matlab for flexible number of arguments and functions - matlab

I have a function F which takes as an input a vector a. Both the output of the function and a are vectors of length N, where N is arbitrary. Each component Fn is of the form g(a(n),a(n-k)), where g is the same for each component.
I want to implement this function in matlab using its symbolic functionality and calculate its Jacobian (and then store both the function and its jacobian as a regular .m file using matlabFunction). I know how to do this for a function where each input is a scalar that can be handled manually. But here I want a script that is capable of producing these files for any N. Is there a nice way to do this?
One solution I came up with is to generate an array of strings "a0","a1", ..., "aN" and define each component of the output using eval. But this is messy and I was wondering if there is a better way.
Thank you!
[EDIT]
Here is a minimal working example of my current solution:
function F = F_symbolically(N)
%generate symbols
for n = 1:N
syms(['a',num2str(n)]);
end
%define output
F(1) = a1;
for n = 2:N
F(n) = eval(sprintf('a%i + a%i',n,n-1));
end

Try this:
function F = F_symbolically(N)
a = sym('a',[1 N]);
F = a(1);
for i=2:N
F(i) = a(i) + a(i-1);
end
end
Note the use of sym function (not syms) to create an array of symbolic variables.

Related

Write a function that takes as input `n` and returns the matrix C, Cij= 0 if i/j<2 , Cij =ij^2 otherwise in MATLAB

Consider the nxn matrix C with elements
Cij = 0 if i/j < 2
Cij = ij^2 otherwise
with 1 <= i,j <= n
Write a Matlab function matSetup that takes as input n and returns the matrix C. Use your function to create C for n = 6. function [Cij]= matSetup(n)
I have written this but it seems not to be correct
function Cij=matSetup(n)
for n=1:n
% whatever you write here is done with i=1, then i=2, then i=3, etc.
Cij(3,j)=i+7;
if (i/j)<2
Cij=0
else
Cij=i*(j)^2
end
end
end
Unfortunately, you can't just write something math-like and have a computer understand it. Things like 1<=i<=n have to be written instead with something like an explicit loop. For Matlab, here's one way to write a loop:
for i=1:n
% whatever you write here is done with i=1, then i=2, then i=3, etc.
end
To assign a value to an element of an array in Matlab, do something like this:
Cij(3,j)=i+7;
To test for a condition in Matlab, do this:
if i+3>2*j
% What you write here is done if the condition is true
else
% What you write here is done if the condition is false
end
If you put all of those things together correctly, you should be able to write your desired function.
Like the other answer, you should first learn to use loops to write a naive program to achieve your goal. When you are comfortable enough, you can try vectorizing your program with functions like meshgrid. Below is an example:
n = 20;
eps = 1/(n+1);
[x, y] = meshgrid(1:n, 1:n);
r = y./x;
z = heaviside(r - 2 + eps) .* y .* x.^2;

How can vector elements with indexing be used in a MATLAB symbolic expression?

I would like to create a MATLAB function with vector inputs. The problem is that the inputs of a function created by matlabFunction() has only scalar inputs.
x = sym('x',[2 1]);
y = sym('y',[2 1]);
f=x(1)+x(2)+y(1)+y(2);
matlabFunction(f,'file','testFunction.m');
matlabFunction(f,'file','testFunction.m','vars',[x,y]); % tried with different options but doesn't work
This is the result (with x1,x2,y1,y2 inputs instead of x,y):
function f = testFunction(x1,x2,y1,y2)
%TESTFUNCTION
% F = TESTFUNCTION(X1,X2,Y1,Y2)
% This function was generated by the Symbolic Math Toolbox version 8.2.
% 10-Apr-2019 21:28:40
f = x1+x2+y1+y2;
Is there a solution to this problem within MATLAB? Or do I need to write a program opening the file as txt and replacing the words...
Update: I managed to solve the problem. For me, the best solution is the odeToVectorField() function.
Manually it is more difficult to give vector inputs to a function created by matlabFunction(). One way is the following:
syms y;
f=str2sym('y(1)+y(2)');
matlabFunction(f,'File','fFunction','Vars',y);
With this method, you need to manipulate the equation as a string (which is possible but not practical...), then re-convert it to symbolic expression.
If you check the result of f=x(1)+x(2)+y(1)+y(2) you will see that it is also scalar. Do simple test:
x = sym('x',[2 1]);
y = sym('y',[2 1]);
f=x(1)+x(2)+y(1)+y(2);
disp(f)
The results is x1 + x2 + y1 + y2. So there's nothing wrong with your matlabFunction expression, it just save what you give. If you need it to be stored in the form x(1)+x(2)+y(1)+y(2) you need to rewrite your f expression so it will be stored in vector form, until passing it to matlabFunction. Or alternatively you can create your file structure manualy using fprintf, look docs.

Input matrix to function file of ode45

I have a code(which requires a lot input be given by the user) which will give me a n x n matrix(say A), which I have to use to solve a system of ODEs X'=AX. How do I include this matrix A in the function file(.m file) of ode45. If I include the code in the function file as below:
function xp=g_test(t,x);
k=input('something');
A=some manipulation of inputs;
xp=A*x;
end
Matlab asks for input at each timestep(typically my problem has 30k timesteps). So how do I include/ pass the matrix A to the function?
You can create a function that returns a function handle:
function odeFcn = makeODE(a,b,c)
A = some_function(a, b, c);
odeFcn = #(t,x) A*x;
end
Now you can call ode45 with input matrices a, b, c:
outputVector = ode45(makeODE(a,b,c), [t0, t1], x0);
The inspiration is taken from gnovice's answer here.

How can i create a multivariable function in matlab out of matrix data?

but i want to make a program in which i can generate a function of multiple variables that depend on the number of rows of a matrix.
for k = 1:sizel;
f(k)=(alpha(k,1)+(beta(k,1)*p(k))+(gamma(k,1)*p(k)^2));
end
cost=(sum(f))
this is for the purpose of optimization so i need that at the end the variables are declares as p(1),p(2),p(3)... these will be the input for my function.
Note: i dont want to assign values to the variables because this will be done be the optimization algorithm in the optimization toolbox.
here is the complete code
function cost = cost(p) ;
clc
clear
costfunctionconstantsmatrix;
sizel=size(CostFormulaconstants);
alpha=CostFormulaconstants(:,1);
beta=CostFormulaconstants(:,2);
gamma=CostFormulaconstants(:,3);
for k = 1:sizel;
f(k)=(alpha(k,1)+(beta(k,1)*p(k))+(gamma(k,1)*p(k)^2));
end
cost=(sum(f))
end
i used the symbolic approach and i got the correct answer for the cost indeed, i got something like this: (53*p(1))/10 + (11*p(2))/2 + (29*p(3))/5 + p(1)^2/250 + (3*p(2)^2)/500 + (9*p(3)^2)/1000 + 1100. But when i try to specify my function to be optimized in the optimization toolbox it tells me that the variables p are sym and cannot be converted to double. the trouble is how to convert this expression to double so that the optimization algorithm can input values for the variable p(1), p(2) and p(3)
Can you pass the matrix as an argument to the function?
function cost = fcn(my_mat)
[m,n] = size(my_mat);
f = zeros(m,1);
for k = 1:m % for example
f(k)=(alpha(k,1)+(beta(k,1)*p(k))+(gamma(k,1)*p(k)^2));
end
cost = sum(f);
end
Your problem is not entirely clear to me but I believe you wish to generate a series of functions in which the variables alpha, beta, gamma are constants with different values for each function, and the vector p is an argument.
What confuses me in your question is that you use the index k for both the constants and the arguments, which I think is not what you intended to write. Assuming I understand your goal, a solution may make use of function handles.
The notation f(k) = #(p) p(1)+p(2) for example, generates a function that adds p(1) and p(2). Abbreviating CostFormulaconstants to cf, the following would generate a series of functions, one for each row in cf.
for k = 1 : size(cf, 1)
f{k} = #(p) cf(k,1) + cf(k,2)*p(1) + cf(k,3)*p(2)^2;
end
You can supply individual function handles to callers from the optimization toolbox simply with f{3} for the third function, for example. A call to f{3} would look like
a = f{3}([3,4]);
If your functions are indeed all polynomials, polyval may be worth a look as well.
EDIT: After clarification, the problem seems a bit simpler, no need for function handles. Why not simply
function c = cost(p)
c = 0;
cf = [...]; % your coefficients here.
for k = 1 : size(cf, 1)
c = c + cf(k,1) + cf(k,2)*p(k) + cf(k,3)*p(k)^2;
end

Implementing iterative solution of integral equation in Matlab

We have an equation similar to the Fredholm integral equation of second kind.
To solve this equation we have been given an iterative solution that is guaranteed to converge for our specific equation. Now our only problem consists in implementing this iterative prodedure in MATLAB.
For now, the problematic part of our code looks like this:
function delta = delta(x,a,P,H,E,c,c0,w)
delt = #(x)delta_a(x,a,P,H,E,c0,w);
for i=1:500
delt = #(x)delt(x) - 1/E.*integral(#(xi)((c(1)-c(2)*delt(xi))*ms(xi,x,a,P,H,w)),0,a-0.001);
end
delta=delt;
end
delta_a is a function of x, and represent the initial value of the iteration. ms is a function of x and xi.
As you might see we want delt to depend on both x (before the integral) and xi (inside of the integral) in the iteration. Unfortunately this way of writing the code (with the function handle) does not give us a numerical value, as we wish. We can't either write delt as two different functions, one of x and one of xi, since xi is not defined (until integral defines it). So, how can we make sure that delt depends on xi inside of the integral, and still get a numerical value out of the iteration?
Do any of you have any suggestions to how we might solve this?
Using numerical integration
Explanation of the input parameters: x is a vector of numerical values, all the rest are constants. A problem with my code is that the input parameter x is not being used (I guess this means that x is being treated as a symbol).
It looks like you can do a nesting of anonymous functions in MATLAB:
f =
#(x)2*x
>> ff = #(x) f(f(x))
ff =
#(x)f(f(x))
>> ff(2)
ans =
8
>> f = ff;
>> f(2)
ans =
8
Also it is possible to rebind the pointers to the functions.
Thus, you can set up your iteration like
delta_old = #(x) delta_a(x)
for i=1:500
delta_new = #(x) delta_old(x) - integral(#(xi),delta_old(xi))
delta_old = delta_new
end
plus the inclusion of your parameters...
You may want to consider to solve a discretized version of your problem.
Let K be the matrix which discretizes your Fredholm kernel k(t,s), e.g.
K(i,j) = int_a^b K(x_i, s) l_j(s) ds
where l_j(s) is, for instance, the j-th lagrange interpolant associated to the interpolation nodes (x_i) = x_1,x_2,...,x_n.
Then, solving your Picard iterations is as simple as doing
phi_n+1 = f + K*phi_n
i.e.
for i = 1:N
phi = f + K*phi
end
where phi_n and f are the nodal values of phi and f on the (x_i).