Defining a common function for composing repeating functions

Define any function descriptor foo :

 foo = @(x) x*2 

I am trying to write a generic defFun function that generates the nth functional force of the foo function, i.e. n iterative calls to foo so that they can be stored in another function of the boo descriptor, for example:

 boo = defFun(foo,n) 

For example,

 foo = @(x) x^2; boo = defFun(foo,3); 

boo(3) will give 6561 [== foo(foo(foo(3)))] , and boo(2) will give 256 [== foo(foo(foo(2)))] .

I tried this code to write defFun , but these pens are hard to handle. Any ideas?

 function boo = defFun(foo,n) h = foo; for i=2:n h = h(h); end boo = h end 
+7
function matlab handle
source share
4 answers

My code is very similar to your original one. I took the liberty of renaming several variables.

Direct approach:

For single input and one output argument, you can use a direct approach similar to your code:

 function ftoN = fIterate(f, N) ftoN = f; for i = 2:N ftoN = @(x) f(ftoN(x)); end end 

Indirect approach: (possibly faster)

It will be much faster, and it will also work for several (but the same number) inputs and outputs.

 function ftoN = fIterate(f, N) ftoN = @(varargin) fIterateLocal(f, N, varargin{:}); function varargout = fIterateLocal(f, N, varargin) varargout = varargin; for i = 1:N [varargout{1:nargin-2}] = f(varargout{:}); end end end 

Example:

Both approaches should work with this:

 square = @(x) x^2; square(2) >> ans = 4 squaresquaresquare = fIterate(square, 3) squaresquaresquare(3) >> ans = 6561 

Aftermath:

Direct approach will be quite slow as well as the limited Maximum recursion limit for MATLAB.

 timeit(@()feval(fIterate(@(X)X+1,400),0)) ans = 1.2160 

an indirect approach will give you much more speed and flexibility:

 timeit(@()feval(fIterate(@(X)X+1,400),0)) ans = 0.0072 
+4
source share

The 3 solutions here are based on building the string, and then using str2func to get the function handle from it. Different implementations for the same functionality, but different readability of the result.

Please note that as highlighted in the comment (thanks to knedlsepp), the recursion order n cannot exceed 32 .


One way is to parse the string definition of the input function and recreate it recursively in the string before converting it to a function handle:

 function boo = defFun(foo,n) %% // retrieve the string of the initial function A = functions(foo) ; fstrfull = A.function ; %% // find "input variables" in the header [i1 i2] = regexp(fstrfull, '\(([^\)]+)\)' , 'once' ) ; %// probably can be improved, regexp are not my strong suit strVar = fstrfull(i1+1:i2-1) ; %// => strVar='x' %// to get rid of the parenthesis returned by the regex %% // isolate only the function expression (without the header) ilast = strfind( fstrfull , ')' )+1 ; %// ilast= 5 find the last position of the header fstr = fstrfull(ilast(1):end) ; %// fstr='x.^2' separate only function expression %% // replace "variables" by the expression the desired number of time strFinalFunction = fstr ; for i=2:n strFinalFunction = strrep(strFinalFunction, strVar, ['(' fstr ')'] ) ; end boo = str2func( ['@(' strVar ')' strFinalFunction ] ) ; end 

This will give you:

 >> boo = defFun(foo,3) boo = @(x)((x.^2).^2).^2 // <= your function shows the full expression >> boo(3) ans = 6561 

It will work in much more complex cases, if only the input function accepts only one variable.


Alternatively, there is a simpler method that should be even more general. It does not require parsing and, therefore, will work in the potential case when the parsing in the solution above is not performed. The disadvantage is that the definition of a function becomes very opaque.

 function boo = defFun2(foo,n) cfoo = {foo} ; %// place the function handle in a cell %// create a string calling the function on itself N number of times strFun = ['@(x) ' repmat('cfoo{1}(',1,n) 'x' repmat(')',1,n) ] ; %// Generate a function handle for the corresponding function boo = str2func( strFun ) ; 

But now your function definition is as follows:

 >> boo = defFun2(foo,3) boo = @(x)cfoo{1}(cfoo{1}(cfoo{1}(x))) // <= your function does not show what it does (only the number of time it calls itself) 

Much less readable, but it still gives the correct results.


Finally, if readability is critical, you can also include the name of the original function in the function definition, but you have to resort to the controversial eval .

 function boo = defFun3(fh,n) fname = inputname(1) ; %// get the name of the function which was called eval( [ fname '={fh};' ] ) ; %// place the function handle in a cell strFun = ['@(x) ' repmat([fname '{1}('],1,n) 'x' repmat(')',1,n) ] ; %// create a string calling the function on itself N number of times boo = str2func( strFun ) ; %// Generate a function handle for the corresponding function 

Now this gives you:

 boo = defFun3(foo,3) boo = @(x)foo{1}(foo{1}(foo{1}(x))) // <= now you know that boo is the function 'foo' called on itself 3 times. 
+3
source share

If your function descriptor foo contains only mathematical formulas (as in your example), you can use the Symbolic Toolbox MATLAB to calculate the formula for boo

 function boo = defFun(foo,n) syms x; % Create a symbolic variable x f = sym(foo); % Convert the function handle to a symbolic expression g = symfun(f,x); % Create a symbolic function to work with v = g; for k=2:n % repeat n times v = g(v); end boo = matlabFunction(v); % convert v to a function handle end 

In your example for n=3 this creates a function handle

 foo = @(x) x.^2; boo = defFun(foo,3) boo = @(x)x.^8 boo(3) ans = 6561 
+1
source share

You just messed up your variables a bit. Your problem is that you are loading the function descriptor into an anonymous function, not a value.

This will work based on your example.

 foo = @(x) x^2; function boo = defFun(fcn_handle,n) v = fcn_handle(n); % The output here is the value of the anonymous function for i=2:n v = fcn_handle(v); end boo = v; end defFun(foo,3) ans = 6561 
0
source share

All Articles