What is the recommended way to pass long list of parameters between main workspace and function?

4 views (last 30 days)
Karol P. on 24 May 2022
Edited: dpb on 25 May 2022
In my work I encountered a problem with passing variables betwen main script and function. Of course I can do it manually:
a1=1;a2=2;a3=3;a4=4;a5=5; %The list is much longer in my project, here just example
sum=calcvalues(a1,a2,a3,a4,a5);
function sum=calcvalues(a1,a2,a3,a4,a5)
sum=0;
b=[1,2,3];
for i=1:3
sum_tmp=sum_support(a1,a2,a3,a4,a5,b(i));
sum=sum+sum_tmp;
end
end
function sum_support = sum_support(a1,a2,a3,a4,a5,b)
sum_support=a1*a2+a3^b+a4*a5;
end
But I have to retype all values every time, and after any modification in list of function inputs there is no option to sync with other executions. Additionally, the list is very long, and take space in every function, making the code less readable. My intention was to override this with
function sum=calcvalues(varargin)
But this doesn't preserve file names. The output is just a 1x5 cell with anonymouse numbers. So far I managed to use eval to assign names dyanmicaly but this does not looks like a good practise. What is the recommended way to restore/preserve the names?
EDIT to clarify:
Here is the closest solution to what I expected. However this requires to use save command to unpack the structure. Is it possible to do this in more elegant way?
a1=1;a2=2;a3=3;a4=4;a5=5; %The list is much longer in my project, here just example
value_holder=struct('a1',a1,'a2',a2,'a3',a3,'a4',a4,'a5',a5);
sum=calcvalues(value_holder)
function sum=calcvalues(value_holder)
sum=0;
b=[1,2,3];
for i=1:3
sum_tmp=sum_support(value_holder,b(i));
sum=sum+sum_tmp;
end
end
function sum_support = sum_support(value_holder,b)
save('temp.mat','-struct','value_holder')
sum_support=a1*a2+a3^b+a4*a5;
end
Stephen23 on 24 May 2022
"Does any of ODE solvers support nested function?"
There is nothing preventing you from using nested functions as the objective function in an ODE solver.

dpb on 24 May 2022
If the variables are such as your example of a sequence of number variables with same root name, that implies they're related/same thing, just different instances. In that case I'd use an array and indexing -- "A" instead.
Alternatively, if they are actually different variables, take those that are related and create a structure to pass for succinctness and then reference the component variables in the struct.
Alternatively, if there are a lot of disparate variables, consider putting them into a table and pass the table.
Would need a lot more information about the actual variables and their use to have specifics, but design the data structure around the problem and then implement it, don't just create variables willy-nilly with no overall structure.
Matt J on 24 May 2022
Alright, I'm mentioning this against my better judgement, but you can unpack the variables in the implicit manner that you want by doing,
eval(structvars(s)')
This might be a compromise in performance between load/save and my suggestion. However, eval() has at least the same programming hazards as load(), so take great heed of the discussion here,

Steven Lord on 24 May 2022
If all your variables are related and so should remain together, I would pack them into a struct array.
s = struct('a1',1,'a2',2)
s = struct with fields:
a1: 1 a2: 2
s.a3 = 3;
s.a4 = 4;
s.a5 = 5
s = struct with fields:
a1: 1 a2: 2 a3: 3 a4: 4 a5: 5
Now you can pass s into and out of your function and use the values in its fields in your function. Functions that need some but not all of the fields in the struct can ignore the ones they don't need, and you can add fields to the struct without affecting existing code.
dpb on 25 May 2022
For something that looks likes OP's example of a bunch of constants to retrieve, I think I'd do as you suggest and retrieve in the individual ODE functions the ones needed for the function --
s=struct('coeff',[1:5]); % put all the coefficients in array instead of many (unuseful anyway) names
Then in each ODE function can write something like
IDX=[1,3,4]; % the needed coefficients for this ODE
S=sum_support(s,IDX); % call the function with needed index array
function sum_support = sum_support(s,b)
sum_support=sum(s.coeff(b))
end
At command line to show syntax works as expected...
>> s = struct('coeff',[1:5]);
>> IDX=[1 3];
>> sum(s.coeff(IDX))
ans =
4.00
>>
One could make things more simple for using for the ODE functions by creating either a struct array of an element of the coefficients for the given ODE and even have a name to ensure use right array element or if it's not too complicated, use a 2D array where each row contains the coefficents for the given ODE so the very long 1D string is given some structure associated with its use.
The disadvantage is that they are then position dependent so Steven's solution is better in that regards.

Matt J on 24 May 2022
Edited: Matt J on 24 May 2022
In the case of your posted example, the appropriate re-implementation would be,
a=1:5;
result=calcvalues(a);
function accum=calcvalues(a)
accum=0;
b=[1,2,3];
for i=1:3
accum=accum+sum_support(a,b(i));
end
end
function sum_support = sum_support(a,b)
sum_support=a(1)*a(2)+a(3)^b+a(4)*a(5);
end
Matt J on 24 May 2022
I said "if" they are, not that I know that for a fact. If they aren't the same length, you can still possibly use a cell array.
The point though is that you should go through your variables to see which ones are similar in size and type, and which can be grouped into arrays.

Catalytic on 24 May 2022
Edited: Catalytic on 24 May 2022
Do not use load/save to introduce undeclared variables in your workspace. This can have unexpected effects as described in this doc page -
which also mentions recommended alternatives.
Karol P. on 24 May 2022
The project is very complicated, and no, the values cannot be grouped like you suggest. If it would be that simple I would not bother to ask. Anyway, thank you for your suggestions, in more generalised case, you're right of course.

R2022a

Community Treasure Hunt

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

Start Hunting!