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

Matlab 为迭代函数组合定义泛型函数,matlab,function,handle,Matlab,Function,Handle,让我们定义任何函数句柄foo: foo = @(x) x*2 我正在尝试编写一个通用函数defFun,该函数生成函数foo,即n次迭代调用foo,以一种可以存储在另一个句柄函数boo中的方式,如下所示: boo = defFun(foo,n) >> boo = defFun2(foo,3) boo = @(x)cfoo{1}(cfoo{1}(cfoo{1}(x))) // <= your function does not show what it does (o

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

foo = @(x) x*2
我正在尝试编写一个通用函数
defFun
,该函数生成函数
foo
,即n次迭代调用
foo
,以一种可以存储在另一个句柄函数
boo
中的方式,如下所示:

boo = defFun(foo,n)
>> 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)
比如说,

foo = @(x) x^2;  
boo = defFun(foo,3);
boo(3)
将给出
6561[==foo(foo(foo(3))]]
boo(2)
将给出
256[==foo(foo(2))]]

我试图用这段代码编写
defFun
,但这些句柄很难处理。有什么想法吗

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

你只是把你的变量搞混了。您的问题是将函数句柄馈送给匿名函数,而不是值

这将在您的示例的基础上起作用

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

如果函数句柄
foo
仅包含数学公式(如示例中所示),则可以使用MATLAB符号工具箱计算
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种解决方案依赖于构建一个字符串,然后使用
str2func
从中获取函数句柄。相同功能的不同实现,但结果的可读性不同

请注意,正如注释中强调的(感谢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
但现在您的函数定义如下所示:

boo = defFun(foo,n)
>> 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)
现在您可以看到:

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.
boo=defFun3(foo,3)
boo=

@(x) foo{1}(foo{1}(foo{1}(x))/我的代码与您原来的代码非常相似。我冒昧地重命名了一些变量

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

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的
最大递归限制
的限制

timeit(@()feval(fIterate(@(X)X+1,400),0))
ans = 1.2160
间接方法将为您提供更多的速度和灵活性:

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

给出完整计算的结果很好,但我的印象是OP希望向新函数返回
函数句柄
,而不仅仅是结果。@Hoki我不理解其中的问题为什么。我想关键是对`存储它<代码>的解释
it`可以是值或函数。但我认为否决这一点有点苛刻。否决票不是我。我正要投赞成票时,我尝试了你的答案,意识到它并不完整,但我肯定没有投反对票。这仍然是一个有效的部分答案,计算正确。因此,您正在寻找一个替代方案,不需要MuPAD。感谢所有人提供不同的答案@knedlsepp的解决方案正是我所需要的。不错,尽管我更喜欢在编辑之前使用间接方法,因为它在函数定义中留下了基函数的名称。由于您的编辑,它现在已经全部消失,但仍然可以完美地工作。哦,我这样做是为了使两个版本具有相同的界面。我认为,如果有人希望最终句柄具有良好的可读性,您的版本无论如何都是最好的!我喜欢你的间接方法这个想法,它和我的for循环方法一样快,增加了可读性。唯一的缺点是str2func对递归深度只有33的奇数限制。(当使用
n=34
调用时,{,[]和(不能超过32的深度)嵌套的错误
)谢谢@Hoki,我喜欢你的想法