Replacing variable names when using func2str of anonymous function

6 views (last 30 days)
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 Comments
James Tursa
James Tursa on 25 Sep 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 on 25 Sep 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.

Sign in to comment.

Accepted Answer

Guillaume
Guillaume on 26 Sep 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 Comments
Guillaume
Guillaume on 27 Sep 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.

Sign in to comment.

More Answers (0)

Products


Release

R2019b

Community Treasure Hunt

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

Start Hunting!