Matlab递归:低效的代码或复杂的递归?

时间:2018-02-28 12:06:14

标签: matlab recursion time execution coding-efficiency

我正在努力在合理的执行时间内解决这个递归问题。

这里,我展示了递归函数,它基本上计算了多项式的系数。

function [ coeff ] = get_coeff( n, k, tau, x )

if(n == 0) % 1st exit condition
    coeff = 0;
else
    if(k == 0) % 2nd exit condition
        coeff = max(0, n*tau-x)^n;
    else % Else recursion
        total = 0;
        for l = k-1:n-2
            total = total + nchoosek(l, k-1)*tau^(l-k+1)*get_coeff(n-1, l, tau, x);
        end
        coeff = (n/k) * total;            
    end
end

end

 % This symbolic summation solution gives numerical errors, probably due to rounding
 % effects.
 %           syms l;
 %           f = nchoosek(l, k-1)*tau^(l-k+1)*get_coeff(n-1, l, tau, x);
 %           coeff = (n/k) * symsum(f, l, k-1, n-2);

这是我使用递归函数的主要脚本:

Tau = 1;
ns = [3];
%delays = 0:0.25:8;
delays = [0];
F_x = zeros(1, size(delays, 2));
rho = 0.95;
tic
for ns_index = 1: size(ns, 2)

  T = Tau*(ns(ns_index)+1)/rho;

  % Iterate delays (x)
  for delay_index = 1:size(delays, 2)
     total = 0;

     % Iterate polynomial.
     for l = 0:ns(ns_index)-1
        total = total + get_coeff(ns(ns_index), l, Tau, delays(delay_index))*(T - ns(ns_index)*Tau + delays(delay_index))^l;
     end

    F_x(1, delay_index) = T^(-ns(ns_index))*total;

  end

end
toc

我已经简化了," ns"和#34;延迟"向量包含单个值,以便更容易遵循。总之,对于" ns"的固定值,我需要使用递归函数计算多项式的所有系数,并在"延迟"计算其最终值。通过增加"延迟"中的点数,我可以看到固定" ns"的曲线。 我的问题是:对于任何" ns"在1到10之间,计算速度非常快,大约为0.069356秒(即使是整个"延迟"向量)。相反,对于ns = [15]或[20],计算时间增加A LOT(我甚至没有设法看到结果)。 我并不热衷于评估计算复杂性,因此我不知道我的代码中是否存在问题(可能是nchoosek函数?或者是循环?)或者它可能是它必须具备的方式记住这个递归问题。

编辑: 正如Adriaan所说,我认为这确实是计算量的因子增长。你是否认为nchoosek的任何近似可能有助于解决这个问题?类似于:en.wikipedia.org/wiki/Stirling%27s_approximation

The last formula in this paper是我尝试实施的内容(注意我为tau更改了delta):

enter image description here

2 个答案:

答案 0 :(得分:0)

我在你的代码上运行了个人资料,我明白了:

Profiler result

我看起来大部分时间花在了nchoosek身上,nchoosek以两个整数作为输入。您可以尝试预先计算所需的值并将其存储在矩阵中以便更快地访问!

编辑:我试过预先计算nchoosek:

for i = 0 : ns
    for j = 0 : ns
        if j < i
            nchoosek_(i+1,j+1) = nchoosek(i,j);
        else
            nchoosek_(i+1,j+1) = NaN;
        end
    end
end

然后在函数中:

total = total + nchoosek_(l+1, k-1+1)*tau^(l-k+1)*get_coeff(n-1, l, tau, x , nchoosek_);

它似乎有用,我用ns = 12得到了很好的改进:

Profiler result with precalculation

但是我仍然坚持使用ns = 15 ......

答案 1 :(得分:0)

所以我终于设法在合理的时间内计算系数。基本上,我接受了Adriaan和rahnema1的建议并创建了一个ns by ns矩阵来存储我以递归方式计算的所有系数。因此,当重复递归树的某个叶子时,我能够通过从矩阵中提取值来修剪树。请注意,增益不是基于预计算值(因为我在移动中计算它们),而是基于修剪递归的数量。这里有一些数字:

  • ns = 10; delay = 0 :对旧递归函数的调用次数为23713.现在,这已经在175次调用中解决了。
  • 对于ns = 10; delay = [0:0.25:8] :782529使用旧函数调用,执行时间为2.74秒,新执行时调用495,快速调整为0.02,这是〜125x倍。