计算多个多项式的根

时间:2013-11-23 15:09:28

标签: matlab polynomial-math

给定矩阵A,表示每列中的多项式。如何在没有循环的情况下有效地计算每个多项式的根?

3 个答案:

答案 0 :(得分:8)

以下是3种方法之间的比较:

  1. 在所有行中进行简单循环,每行使用roots
  2. 一种完全无循环的方法,基于YBE使用块对角矩阵的想法, 使用sparse作为中间人
  3. 通过所有行的简单循环,但这次使用roots中的“内联”代码。
  4. 代码:

    %// The polynomials
    m = 15;
    n = 8;
    N = 1e3;
    
    X = rand(m,n);
    
    
    %// Simplest approach
    tic
    for mm = 1:N
    
        R = zeros(n-1,m);
        for ii = 1:m
            R(:,ii) = roots(X(ii,:));
        end
    
    end
    toc
    
    
    %// Completely loopless approach
    tic
    for mm = 1:N
    
        %// Indices for the scaled coefficients
        ii = repmat(1:n-1:m*(n-1), n-1,1);
        jj = 1:m*(n-1);
    
        %// Indices for the ones
        kk = bsxfun(@plus, repmat(2:n-1, m,1), (n-1)*(0:m-1).');  %'
        ll = kk-1;
    
        %// The block diagonal matrix
        coefs = -bsxfun(@rdivide, X(:,2:end), X(:,1)).';  %'
        one   = ones(n-2,m);
        C = full(sparse([ii(:); kk(:)], [jj(:); ll(:)],...
            [coefs(:); one(:)]));
    
        %// The roots
        R = reshape(eig(C), n-1,m);
    
    end
    toc
    
    
    %// Simple loop, roots() "inlined"
    tic    
    R = zeros(n-1,m);
    for mm = 1:N
    
        for ii = 1:m            
            A = zeros(n-1);
            A(1,:) = -X(ii,2:end)/X(ii,1);
            A(2:n:end) = 1;
            R(:,ii) = eig(A);            
        end
    
    end
    toc
    

    结果:

    %// m=15, n=8, N=1e3:
    Elapsed time is 0.780930 seconds. %// loop using roots()
    Elapsed time is 1.959419 seconds. %// Loopless
    Elapsed time is 0.326140 seconds. %// loop over inlined roots()
    
    %// m=150, n=18, N=1e2:
    Elapsed time is 1.785438 seconds. %// loop using roots()
    Elapsed time is 110.1645 seconds. %// Loopless
    Elapsed time is 1.326355 seconds. %// loop over inlined roots()
    

    当然,您的里程可能会有所不同,但一般信息应该是明确的:在MATLAB中避免循环的旧建议只是: OLD 。它不再适用于MATLAB版本R2009及更高版本。

    尽管矢量化仍然是一件好事,但肯定并非总是如此。在这种情况下:分析将告诉您大部分时间花在计算块对角矩阵的特征值上。 eig下面的算法会缩放为(是的,这是 3 ),加上它无法以任何方式利用稀疏矩阵(比如这个块对角线) ,使这种方法在这种特定背景下成为一个糟糕的选择。

    循环是你的朋友^ _ ^

    现在,这当然基于伴随矩阵的eig(),这是一次计算所有根的一个很好且简单的方法。当然还有更多的方法来计算多项式的根,每个方法都有自己的优点/缺点。有些速度要快得多,但是当一些根很复杂时,它们就不那么好了。其他的更快,但需要对每个根进行相当好的初始估计等。大多数其他的根寻找方法通常要复杂得多,这就是为什么我把它们留在这里。

    Here是一个很好的概述,here是一个更深入的概述,以及一些MATLAB代码示例。

    如果你很聪明,如果你需要在接下来的几周里每天进行数百万次这样的计算,你应该只深入研究这些材料,否则,这是不值得投资的。

    如果你更聪明,你会发现这无疑会在某些时候回到你身边,所以无论如何都要做到这一点。

    如果你是一名学者,你掌握了所有寻根方法,这样你就拥有了一个巨大的工具箱,这样你就可以在新工作出现时为工作挑选最好的工具。或者甚至梦想自己的方法:)

答案 1 :(得分:1)

您可以将arrayfunroots结合使用,它会根据单元格数组为您提供结果。

n = size(A,2);
t = arrayfun(@(x)roots(A(:,x)), 1:n, 'UniformOutput', 0);

然后,您可以使用cell2mat将其转换为矩阵。要么:r = cell2mat(t),要么

r = cell2mat(arrayfun(@(x)roots(A(:,x)), 1:n, 'UniformOutput', 0));

答案 2 :(得分:1)

实际上roots的作用是找到伴随矩阵的特征值。

roots(p) = eig(compan(p))

所以这是我的例子,它构造了每个多项式的伴随矩阵中的块对角矩阵,而不是找到块对角矩阵的特征值。

>> p1=[2 3 5 7];
>> roots(p1)

ans =

  -0.0272 + 1.5558i
  -0.0272 - 1.5558i
  -1.4455          

>> eig(compan(p1))

ans =

  -0.0272 + 1.5558i
  -0.0272 - 1.5558i
  -1.4455          

>> p2=[1 2 9 5];
>> roots(p2)

ans =

  -0.6932 + 2.7693i
  -0.6932 - 2.7693i
  -0.6135          

>> p3=[5 1 4 7];
>> roots(p3)

ans =

   0.3690 + 1.1646i
   0.3690 - 1.1646i
  -0.9381          

>> A=blkdiag(compan(p1),compan(p2),compan(p3))

A =

   -1.5000   -2.5000   -3.5000         0         0         0         0         0         0
    1.0000         0         0         0         0         0         0         0         0
         0    1.0000         0         0         0         0         0         0         0
         0         0         0   -2.0000   -9.0000   -5.0000         0         0         0
         0         0         0    1.0000         0         0         0         0         0
         0         0         0         0    1.0000         0         0         0         0
         0         0         0         0         0         0   -0.2000   -0.8000   -1.4000
         0         0         0         0         0         0    1.0000         0         0
         0         0         0         0         0         0         0    1.0000         0

>> eig(A)

ans =

  -0.0272 + 1.5558i
  -0.0272 - 1.5558i
  -1.4455          
  -0.6932 + 2.7693i
  -0.6932 - 2.7693i
  -0.6135          
   0.3690 + 1.1646i
   0.3690 - 1.1646i
  -0.9381