Passing a vector as multiple inputs to a function

79 vues (au cours des 30 derniers jours)
Martin O'Connor
Martin O'Connor le 23 Déc 2017
I'm writing a vehicle dynamics model using the symbolic maths toolbox and the ODE15 solver. It all seems to be working as expected but I am just trying to make the function slightly more easy to use.
At the moment I am passing a vector of the systems state and their derivatives (S in the below function) and a vector with all the system parameters I want to change quickly (stuff like inertias and spring rates) in a seperate vector (called vars), along with the symbolic equations of motion (called EoM) and some time varying forces as f and ft.
My problem is that when passing values to the equations of motion I need to enter them seperately as S(1),S(2)... and vars(1),vars(2)... which means that if I add additional parameters to my model I will need to update this function to add the new values. Is there a way to convert a vector of values into seperate function inputs so that this will update automatically?
Thanks
Martin
function DS = EoM_func(t,S,EoM,vars,ft,f)
DS = zeros(14,1);
Acc = interp1(ft,f(1,:),t);
Brk = interp1(ft,f(2,:),t);
Cor = interp1(ft,f(3,:),t);
out = EoM(S(1), S(2), S(3), S(4), S(5), S(6), S(7),...
S(8), S(9), S(10),S(11),S(12),S(13),S(14),...
vars(1),vars(2),vars(3),...
vars(4),vars(5),vars(6),...
vars(7),vars(8),vars(9),...
vars(10),vars(11),vars(12),...
vars(13),vars(14),vars(15),...
vars(16),vars(17),vars(18),...
vars(19),vars(20),vars(21),...
Acc,Brk,Cor);
DS(1) = S(2);
DS(2) = out(1);
DS(3) = S(4);
DS(4) = out(2);
DS(5) = S(6);
DS(6) = out(3);
DS(7) = S(8);
DS(8) = out(4);
DS(9) = S(10);
DS(10) = out(5);
DS(11) = S(12);
DS(12) = out(6);
DS(13) = S(14);
DS(14) = out(7);
end
  3 commentaires
Stephen23
Stephen23 le 24 Déc 2017
"I need to enter them seperately as S(1),S(2)... and vars(1),vars(2)... "
It really would be much simpler to re-write the function to accept vector inputs. Your code could be significantly simplified by taking advantage of vectors more. For example, rather than individually allocate each value individually to the output variable you just need this:
DS = [S(2:2:14);out(1:7)];
DS = DS(:).';
Martin O'Connor
Martin O'Connor le 24 Déc 2017
Vectorising the DS vector assignment is a good shout, thanks. The function is still in the "just make everything work" phase.
I can't re-write it with vector inputs because that function handle is generated by the matlabFunction() function which requires all the symbolic variables in the expression to be added as separate inputs (I think?)

Connectez-vous pour commenter.

Réponse acceptée

Stephen23
Stephen23 le 24 Déc 2017
"Is there a way to convert a vector of values into seperate function inputs so that this will update automatically"
Yes there is (but really you should just rewrite that function to accept a vector input). The trick is to use a comma-separated list:
C = num2cell(S)
D = num2cell(vars);
out = EoM(C{:},D{:},Acc,Brk,Cor);

Plus de réponses (2)

Walter Roberson
Walter Roberson le 24 Déc 2017
You can use matlabFunction with the 'vars' parameter. Pass the option a cell array. Each vector of symbols in the cell array will be bundled together into a single input. Use a row vector of symbols if you want the vectorization to be along the columns, and use a column vector of symbols if you want the vectorization to be along the rows (that is, even with symbols bundled together you can vectorize to process multiple groups of values at the same time.)
Example:
x = sym('x', [1 3]);
y = x(1)^3/3 + x(2)^2 / 2 - x(3);
fr = matlabFunction(y, 'vars', {x}); %use this when the function will be passed a row of values, such as for fminsearch
fc = matlabFunction(y, 'vars', {x.'}); %use this when the function will be passed a column of values, such as for ode45()
  1 commentaire
Priya Natarajan
Priya Natarajan le 25 Mar 2019
Walter Roberson, thank you, thank you, thank you!
I've been trying to find this answer for literally hours and been finding all kinds of weird workarounds involving passing the function to a string and back. Why this isn't the top answer, I have no idea. I searched practically all combinations of the terms 'symbolic', 'function', 'variable vector', 'symbolic vector' trying to find a way to define a function to accept a vector as an input before thinking of searching how to turn a vector into multiple inputs.
For Google's sake, this is the correct way to define a symbolic function to receive a vector input! Hopefully this shows up when some other hapless newbie programmer tries to search for the same terms I was searching.

Connectez-vous pour commenter.


Bruno
Bruno le 2 Nov 2022
So if understand correctly you have a function that takes multiple inputs (x1,x2) and you want to pass a vector [x1, x2] that the function know how to interpret, I managed to come with this solution. Basically create a function that wraps the function you want to use and maps each element of the vector to an input of the function.
The example below is a minimalistic example of calculating the gradient and the hessian of the Rosenbrock function with a=1 and b=100, at the point [1,1].
This works pretty much as a Python function decorator, potentially it can be modified to support a variable number of arguments but I didn't put enough time into researching that.
% Definition of symbolic variable x = [x1, x2]
syms x [1,2];
% Original Symbolic expressio
f_sym = ((1-x(1))^2) + (100*(x(2)-(x(1)^2))^2);
x_0 = [1,1];
% Functions of (x1,x2) created from Symbolic Expressions
fun = matlabFunction(f_sym);
fun_grad = matlabFunction(gradient(f_sym,x),'Vars',x);
fun_hess =matlabFunction(jacobian(gradient(f_sym,x),x),'Vars',x);
% Values calculated from x_0 = [1,1] using the wrapper fv.
val = fv(x_0,fun);
grad = fv(x_0,fun_grad);
hess = fv(x_0,fun_hess);
function r = fv(x,fun)
% fv stands for Function Vectorization
r = fun(x(1),x(2));
end

Catégories

En savoir plus sur Symbolic Math Toolbox dans Help Center et File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by