Problem using str2func for creating a function handle

4 visualizaciones (últimos 30 días)
Pedro
Pedro el 28 de En. de 2014
Editada: Stephen23 el 1 de En. de 2022
Hello!
I have two functions:
%---------
function [ handle_res ] = handle_fun_creation_2( File_String,Type_identifier,Value )
if Type_identifier == 0
handle_res = str2func(['@' File_String]);
elseif Type_identifier == 1
handle_res = str2func(['@(t,y)' File_String '(t,y,Value)'] );
end
end
%-------------
and:
%-------------
function [ y ] = test_3( t,x,Var_opt )
y=x+Var_opt(1)+Var_opt(2);
end
%---------------
Could anyone explain me why the following code doesn't work:
%---------------------------
Var_opt = [30 40]';
[handle_4] = handle_fun_creation_2('test_3',1,Var_opt);
[t6,y6] = ode15s(handle_4,[0:1],0);
Undefined function or variable 'Value'.
Error in @(t,y)test_3(t,y,Value)
%---------
But this one does?
%---------
handle_5 = @(t,y)test_3(t,y,Var_opt);
[t7,y7] = ode15s(handle_5,[0:1],0);
I think I'm missing some detail on how str2func works maybe? Thanks in advance.

Respuesta aceptada

Walter Roberson
Walter Roberson el 28 de En. de 2014
str2func() does not execute the content of any strings it is passed so it has no idea that the string 'Value' should relate to the parameter named Value.
if isnumeric(Value)
valstr = sprintf('%g', Value);
else
valstr = char(Value);
end
handle_res = str2func(sprintf('@(t,y)%s(t,y,%s)', File_String, valstr));
  4 comentarios
Pedro
Pedro el 28 de En. de 2014
Editada: Pedro el 28 de En. de 2014
Not exactly, nonetheless I believe I found a solution using eval and sprintf:
%------------
function [ handle_res ] = handle_fun_creation_2(File_String,Type_identifier,Value )
if Type_identifier == 0
handle_res = sprintf('@%s',File_String);
elseif Type_identifier == 1
handle_res = sprintf('@(t,y)%s(t,y,Value)',File_String);
end
%----------------
[sprint_4] = handle_fun_creation_2('test_3',1,Var_opt);
handle_4 = eval(sprint_4);
[t6,y6] = ode15s(handle_4,[0:1],0);
%------------------
Although I'm not sure about this code's efficiency, it works. Many thanks for your input!
Stephen23
Stephen23 el 1 de En. de 2022
Editada: Stephen23 el 1 de En. de 2022
"Although I'm not sure about this code's efficiency, it works"
It is not efficient, nor does it work as you think it does.
For example, although you pass the input argument Value to handle_fun_creation_2 it remains totally unused, it is only when you later EVAL the string in the caller workspace that MATLAB will look for a function or variable named Value. You can easily test this by calling handle_fun_creation_2 with complete nonsense for the third input argument and everything will work (as long as the correct Value is defined in the caller workspace!):
sprint_4 = handle_fun_creation_2('test_3',1,{'hello world'}) % 3rd arg = silly cell array
sprint_4 = '@(t,y)test_3(t,y,Value)'
Value = [pi,2/3]; % <----------- must be defined in the calling workspace...
handle_4 = eval(sprint_4) % <--- because this is actually where Value is included.
handle_4 = function_handle with value:
@(t,y)test_3(t,y,Value)
[t6,y6] = ode15s(handle_4,0:1,0); % no errors
If Value is not defined in the caller workspace then your code will not work, it will throw an error about Value being undefined (see bottom of this comment). It is clear that my silly Hello World cell array actually does nothing.
But this just seems to be a very indirect and inefficient approach to parameterize a function:
As the documentation shows, a much simpler and more efficient approach is to use an anonymous function:
fn1 = @(x,y)test_3(x,y,Value);
[t7,y7] = ode15s(fn1,0:1,0);
isequal(t6,t7)
ans = logical
1
isequal(y6,y7)
ans = logical
1
and if the function name really is provided as text (suboptimal design, but still simpler and more direct than a special "creation" function returning a string and evaluating it to get a function handle):
fns = 'test_3';
fn2 = str2func(fns);
fn3 = @(x,y)fn2(x,y,Value);
[t8,y8] = ode15s(fn3,0:1,0);
isequal(t6,t8)
ans = logical
1
isequal(y6,y8)
ans = logical
1
And finally, lets try your code when Value is not defined in the caller workspace:
clearvars Value
handle_4 = eval(sprint_4) % looks the same... but is it?
handle_4 = function_handle with value:
@(t,y)test_3(t,y,Value)
[t6,y6] = ode15s(handle_4,0:1,0); % nope.
Unrecognized function or variable 'Value'.

Error in solution>@(t,y)test_3(t,y,Value)

Error in odearguments (line 90)
f0 = feval(ode,t0,y0,args{:}); % ODE15I sets args{1} to yp0.

Error in ode15s (line 152)
odearguments(FcnHandlesUsed, solver_name, ode, tspan, y0, options, varargin);

Iniciar sesión para comentar.

Más respuestas (0)

Categorías

Más información sobre Loops and Conditional Statements en Help Center y File Exchange.

Productos

Community Treasure Hunt

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

Start Hunting!

Translated by