为迭代函数组合定义泛型函数

时间:2015-01-04 12:39:59

标签: matlab function handle

让我们定义任何函数句柄foo

foo = @(x) x*2

我正在尝试编写一个通用函数defFun来生成函数foo的{​​{3}},即 n 迭代调用foo ,在某种程度上它可以存储在另一个句柄函数boo中,如下所示:

boo = defFun(foo,n)

例如,

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

boo(3)会提供6561 [== foo(foo(foo(3)))]boo(2)会提供256 [== foo(foo(foo(2)))]

我尝试使用此代码编写defFun但这些句柄处理起来很棘手。有什么想法吗?

function boo = defFun(foo,n)
   h = foo;
   for i=2:n
      h = h(h);
   end
   boo = h
end

4 个答案:

答案 0 :(得分:4)

我的代码非常类似于原始代码。我冒昧地重命名了一些变量。

直接方法:

对于单输入和单输出参数,您可以使用类似于您的代码的直接方法:

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

间接方法:(可能更快)

这个将更快,它也适用于多个(但数量相同)的输入和输出。

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

实施例

这两种方法都适用于此:

square = @(x) x^2;
square(2)
>> ans = 4

squaresquaresquare = fIterate(square, 3)
squaresquaresquare(3)
>> ans = 6561

后果:

直接方法将会相当缓慢,并受到MATLAB Maximum recursion limit的限制。

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

间接方法将为您提供更多速度和灵活性:

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

答案 1 :(得分:3)

这里的3个解决方案依赖于构建字符串,然后使用str2func来获取函数句柄。相同功能的不同实现,但结果的可读性不同。

请注意,在评论中突出显示( thanks knedlsepp ),递归n的顺序不能超过32


一种方法是解析输入函数字符串定义并在将其转换为函数句柄之前在字符串中递归地重新创建它:

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

这会给你:

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

>> boo(3)
ans =
        6561

只要输入函数只输入一个变量作为输入,它就适用于更复杂的情况。


或者,有一种更简单的方法应该更通用。它不需要解析,因此可能在上述解决方案中的解析失败的情况下工作。缺点是功能定义变得非常不透明。

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 ) ;

但现在您的函数定义如下所示:

>> 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)

可读性差得多,但它仍能提供正确的结果。


最后,如果可读性至关重要,您还可以在函数定义中包含原始函数的名称,但您必须求助于有争议的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

现在给你:

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.

答案 2 :(得分:1)

如果函数句柄foo仅包含数学公式(如示例中所示),则可以使用MATLAB Symbolic Toolbox计算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

n=3的示例中,这将创建函数句柄

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

boo(3)
ans =
    6561

答案 3 :(得分:0)

你只是让你的变量混淆了一下。您的问题是您将函数句柄输入到匿名函数而不是值。

这将以你的榜样为基础。

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