Replacing variable names when using func2str of anonymous function

23 visualizaciones (últimos 30 días)
I have an anonymous function, say
f=@(x,y) x+y;
I can name the function using func2str:
func2str(f)
ans =
'@(x,y)x+y'
What if I want to get the function name with different names for the anonymous variables x,y. Say replacing x,y with the strings 'Small', 'Large' to yield:
'@(Small,Large)Small+Large'
This becomes more tricky if the function has x or y also as non-variables. say for the case of f(x) x+'x', the correct answer will be '@(Small)Small+'x''
  15 comentarios
James Tursa
James Tursa el 25 de Sept. de 2019
The reordering issue can be catastrophic if you have something like y*x and it gets rewritten as x*y ... and you will be using it for matrix multiply or quaternion multiply which are non-commutative.
Walter Roberson
Walter Roberson el 25 de Sept. de 2019
James has a good point. For use with the symbolic Toolbox, all of the variables need to represent scalar values. The work-around for that is to pass in a matrix of symbolic variables such as
sym('x', [4 4])
for a variable that is expected to be 4 x 4.
Unfortunately, picking back through the results of the expression to repackage the individual variables into an array can be a nuisance.

Iniciar sesión para comentar.

Respuesta aceptada

Guillaume
Guillaume el 26 de Sept. de 2019
As I suggested, it's possible to do this with the undocumented mtree function:
function fstr = replacevar(fstr, vars, replacements)
%fstr: the code of an anomymous function (obtained with str2func). This code is only designed to work with anonymous functions.
%vars: a cell array of variable names to replace
%replacements: a cell array of replacement names
tree = mtree(fstr); %parse the function and get parse tree. Note that mtree is completely undocumented
fvars = tree.strings; %portion of the function that correspond to each parsed element. Includes variables and non-variables for now
[isrep, whichrep] = ismember(tree.strings, vars); %do any of the potential variable match one to be replace and which one?
toreplace = strcmp(tree.kinds, 'ANONID') & isrep(:); %replace elements that are ANONID (input variables of the anonymous function) and match a replaced variables
fvars = fvars(toreplace); %filter the list of potential variables to keep only the ones to be replaced
whichrep = replacements(whichrep(toreplace)); %get matching replacements
varloc = tree.position; %start position of variables in the strings (not sure it's the correct property but appears to be right)
varlength = cellfun(@numel, fvars); %couldn't find a length property in tree. get it from fvars instead
splits = [varloc(toreplace)'; varloc(toreplace)' + varlength]; %compute where to split fstr to isolate the variables
fsplit = mat2cell(fstr, 1, diff([1; splits(:); numel(fstr)+1])); %do the splitting every even element is a variable to replace
fsplit(2:2:end) = whichrep; %do the replacing
fstr = [fsplit{:}]; %and merge back
end
Of course, since mtree is completely undocumented, it's possible it breaks on some inputs and may stops working in future versions. Use at your own risk, but it appears to do the job correctly:
>> replacevar('f = @(x, yyz) strrep(x, ''x'', yyz)', {'x', 'yyz'}, {'str', 'reps'})
ans =
'f = @(str, reps) strrep(str, 'x', reps)'
  2 comentarios
royk
royk el 27 de Sept. de 2019
Wow!
Genius. Works like magic.
Guillaume
Guillaume el 27 de Sept. de 2019
Note that if the anonymous function contains another anonymous function definition using the same variable names, e.g.:
f = @(x, y) arrayfun(@(x, y) x+y, x, y);
Then the variables currently get replaced in both function. The code could be improved to not do this. This is left as an exercise to the reader, one that has time to work out how to get the information out of mtree. I believe it's probably not too complicated but I haven't got the time to work it out.

Iniciar sesión para comentar.

Más respuestas (0)

Etiquetas

Productos


Versión

R2019b

Community Treasure Hunt

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

Start Hunting!

Translated by