Automatically change the input arguments of function handles

15 views (last 30 days)
I have a function with four variables (u, v, w and t) and I would like to analyze the influence of different combinations of two of the variables, for specific values of the other two. To do that I define an anonymous function handle.
For example, to analyze the influence of u and v for w = 0, t = 0.
fun = @(u, v) u + v.^2 w + sin(t) + rot(u,v).
where rot is another function handle that depends on u, v and w:
rot = @(u,v) = u.^2 + v + 2.*w.*u;
My question is the following: is it possible to change the input arguments of the function handle automatically? That is, if I want to change, and analyze the influence of v-w for u = 0 and t = 0, instead of writing
fun = @(v,w) u + v.^2 w + sin(t) + rot(v,w)
save the four variables in an array and use something similar to this:
var = [u,v,w,t]
input1 = var(2); input2 = var(3)
fun = @(input1,input2) u + v.^2 w + sin(t) + rot(input1,input2)
In doing so, I was hoping that once the two input arguments (input1,input2) are selected (among u, v, w and t), the input arguments in all the function handles of the script will be automatically changed. This would be of great help, as there are several function handles in the problem I'm trying to solve.
I know that this may be done by using matlabFunction() and changing "Vars" inside. However, I want to avoid the use of matlabFunction() since I am also using some logical conditions that are not supported by it. Is there any way to do that?
Thank you in advance for your help.

Answers (2)

Hassaan
Hassaan on 2 Jan 2024
you can design a higher-order function—a function that returns other functions—to achieve the flexibility you're looking for.
Let's say you have a base function and rot function like this
% Example usage
fixedVars.u = 1; % u is not fixed
fixedVars.v = 2; % v is not fixed
fixedVars.w = 0; % w is fixed to 0
fixedVars.t = 0; % t is fixed to 0
% Generate the function handle for analyzing u and v
fun = generateFunctionHandle(fixedVars, @rot);
% Now fun can be used as a function of u and v, with w and t fixed
result = fun(1, 2); % Example call with u=1, v=2
function result = baseFunction(u, v, w, t, rotFunc)
result = u + v.^2 - w + sin(t) + rotFunc(u, v, w);
end
function r = rot(u, v, w)
% Some operations involving u, v, and w
r = u*v*w;...; % Replace with actual computation
fprintf("rot: %f\n",r);
end
function fun = generateFunctionHandle(fixedVars, rotFunc)
% fixedVars is a struct with fields 'u', 'v', 'w', 't' indicating fixed values or NaN for variables to be used as inputs
fun = @(x, y) baseFunction(...
isnan(fixedVars.u) * x + ~isnan(fixedVars.u) * fixedVars.u, ...
isnan(fixedVars.v) * x + ~isnan(fixedVars.v) * fixedVars.v, ...
isnan(fixedVars.w) * x + ~isnan(fixedVars.w) * fixedVars.w, ...
isnan(fixedVars.t) * x + ~isnan(fixedVars.t) * fixedVars.t, ...
@(u, v, w) rotFunc(...
isnan(fixedVars.u) * y + ~isnan(fixedVars.u) * fixedVars.u, ...
isnan(fixedVars.v) * y + ~isnan(fixedVars.v) * fixedVars.v, ...
isnan(fixedVars.w) * y + ~isnan(fixedVars.w) * fixedVars.w));
end
Whenever you want to change which variables are inputs, you can call generateFunctionHandle again with a different fixedVars struct.
Please note that this approach assumes that rot can also be expressed in terms of two variables, which might not be the case based on your initial description. If rot needs to take three arguments, you'll need to adjust the higher-order function accordingly.
The use of isnan in the generateFunctionHandle function is a trick to select between the fixed value and the input value based on whether the fixed value is NaN or not.
This method is somewhat complex and may not be the most efficient. If you find that this approach becomes unwieldy or hard to maintain, it may be worth considering structuring your code differently or using classes to encapsulate the varying parameters.
------------------------------------------------------------------------------------------------------------------------------------------------
If you find the solution helpful and it resolves your issue, it would be greatly appreciated if you could accept the answer. Also, leaving an upvote and a comment are also wonderful ways to provide feedback.
Professional Interests
  • Technical Services and Consulting
  • Embedded Systems
  • Electrical and Electronics Engineering
  1 Comment
Paul
Paul on 2 Jan 2024
Edited: Paul on 2 Jan 2024
Thanks for your quick reply, Muhammad Hassaan Shah.
I believe, there might have been some misunderstanding, maybe I did not explain it correctly and/or I did not understand the code that you are suggesting.
I just wanna change the input variables of the function handles, and afterwards, I will use fimplicit, so I do not need to give specific values to two of the four unknowns. In your example, u and v are not fixed, so if I am not wrong, fixedVars.u and fixedVars.v should be NaNs. However, even after this modification, and assuming rot to be negligible (to make things easier), I do not see how fun depends on u and v, it will only depend on x. Am I missing something?
Thanks again for your help.

Sign in to comment.


Steven Lord
Steven Lord on 2 Jan 2024
So you want to fix some of the input arguments while leaving others alone? Let's take a simple example function handle.
f = @(x, y, z) x.^2+sin(y)-exp(z);
If I wanted to make a new function handle, one that only accepted x and y and passed in a constant value of 1 for z, I could do that by defining a new function handle that calls the existing one.
g = @(x, y) f(x, y, 1);
format longg
[g(2, 3); f(2, 3, 1)]
ans = 2×1
1.42283817960082 1.42283817960082
Need a new function handle that accepts the inputs in a different order than f does?
h = @(z, x, y) f(x, y, z)
h = function_handle with value:
@(z,x,y)f(x,y,z)
[h(1, 2, 3); f(2, 3, 1)]
ans = 2×1
1.42283817960082 1.42283817960082
  3 Comments
Steven Lord
Steven Lord on 3 Jan 2024
So you want something like this, that takes advantage of comma-separated lists?
f = @(x, y) x.^2-y.^3;
data = {1:5, 6:10, 11:15};
result12 = f(data{[1, 2]})
result12 = 1×5
-215 -339 -503 -713 -975
check12 = f(1:5, 6:10)
check12 = 1×5
-215 -339 -503 -713 -975
result23 = f(data{[2, 3]})
result23 = 1×5
-1295 -1679 -2133 -2663 -3275
check23 = f(6:10, 11:15)
check23 = 1×5
-1295 -1679 -2133 -2663 -3275
result31 = f(data{[3, 1]})
result31 = 1×5
120 136 142 132 100
check31 = f(11:15, 1:5)
check31 = 1×5
120 136 142 132 100
While I've hard-coded the indices into the data cell array for purposes of demonstration, you could generate those indices automatically. The check variables show that the comma-separated list calls match the explicitly listed input calls.
Paul
Paul on 3 Jan 2024
That's more or less what I want, but instead of having numbers inside data cell array, to have all the (symbolic?) input arguments of the functions involved in the problem ('u','v','w','t').
So once I choose two of them, with automatically generated indices, I can have something like the following: (the code does not work, it is just to show an example of what I am trying to find) :
data = {'u','v','w','t'};
%--- Analyze v-w effect ---%
u = 1; % fixed argument
t = 0; % fixed argument
fun = @(data{2},data{3}) u + v.^2 + w + t; % This should generate fun = @(v,w) u + v.^2 + w + t;
% Or for another case...
%--- Analyze w-t effect ---%
u = 0.5; % fixed argument
v = 0.5; % fixed argument
fun = @(data{3},data{4}) u + v.^2 + w + t; % This should generate fun = @(w,t) u + v.^2 + w + t;
So for the same function, I can analyze the effect of only two variables (e.g., using fimplicit) for specific values of the other two. Is it possible to do something like this?
Thanks and sorry for all the trouble.

Sign in to comment.

Categories

Find more on Creating and Concatenating Matrices in Help Center and File Exchange

Products


Release

R2022a

Community Treasure Hunt

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

Start Hunting!