矩阵平衡算法

计算科学 线性代数 matlab 拉帕克 scipy 矩阵方程
2021-12-24 08:12:12

我一直在从头开始编写一个控制系统工具箱,纯粹是在 Python3 中(无耻的插件:)haroldcare.m根据我过去的研究,我总是出于技术/无关的原因抱怨 Riccati 求解器。

因此,我一直在编写自己的一套例程。我找不到解决办法的一件事是获得一个高性能的平衡算法,至少和balance.m. 在你提到它之前,xGEBAL家庭在 Scipy 中公开,你基本上可以从 Scipy 调用如下,假设你有一个浮点类型的 2D 数组A

import scipy as sp
gebal = sp.linalg.get_lapack_funcs(('gebal'),(A,)) # this picks up DGEBAL
Ab, lo, hi, scaling , info = gebal(A, scale=1 , permute=1 , overwrite_a=0 )

现在,如果我使用以下测试矩阵

array([[ 6.      ,  0.      ,  0.      ,  0.      ,  0.000002],
       [ 0.      ,  8.      ,  0.      ,  0.      ,  0.      ],
       [ 2.      ,  2.      ,  6.      ,  0.      ,  0.      ],
       [ 2.      ,  2.      ,  0.      ,  8.      ,  0.      ],
       [ 0.      ,  0.      ,  0.000002,  0.      ,  2.      ]])

我明白了

array([[ 8.      ,  0.      ,  0.      ,  2.      ,  2.      ],
       [ 0.      ,  2.      ,  0.000002,  0.      ,  0.      ],
       [ 0.      ,  0.      ,  6.      ,  2.      ,  2.      ],
       [ 0.      ,  0.000002,  0.      ,  6.      ,  0.      ],
       [ 0.      ,  0.      ,  0.      ,  0.      ,  8.      ]])

但是,如果我将其传递给balance.m,我会得到

>> balance(A)

ans =

    8.0000         0         0    0.0625    2.0000
         0    2.0000    0.0001         0         0
         0         0    6.0000    0.0002    0.0078
         0    0.0003         0    6.0000         0
         0         0         0         0    8.0000

如果您检查排列模式,它们是相同的,但缩放是关闭的。gebal给出统一比例,而 matlab 给出以下 2 的幂[-5,0,8,0,2]

显然,这些都没有使用相同的机器。我尝试了各种选项,例如 Lemonnier、Van Dooren 双面缩放、原始 Parlett-Reinsch 以及文献中其他一些鲜为人知的方法,例如SPBALANCE.

我可能要强调的一点是我了解本纳的工作。特别是专门为此目的的哈密顿矩阵的辛平衡。但是,请注意,这种类型的处理是在gcare.m(广义 Riccati 求解器)内完成的,平衡是通过 直接完成的balance.m因此,如果有人能指出我的实际实施,我将不胜感激。


披露:我真的不是想对mathworks代码进行逆向工程:由于各种原因,包括这个问题的动机,我实际上想摆脱它,也就是说,我不知道它在做什么,这让我付出了很多代价时光倒流。我的目的是获得一个令人满意的平衡算法,它允许我传递 CAREX 示例,以便我可以在常规求解器之上实现牛顿迭代方法。

1个回答

我花了很长时间才弄清楚这一点,并且像往常一样,在找到罪魁祸首后就很明显了。

在检查了 David S. Watkins 报告的问题案例之后。平衡有害的情况。电子。反式。编号。Anal, 23:1–4, 2006 以及此处的讨论(均在arXiv:1401.5766v1中引用),事实证明 matlab 通过首先分离对角线元素来使用平衡。

我最初的想法是,根据 LAPACK 函数的经典有限文档,GEBAL 会自动执行此操作。但是,我猜作者忽略对角线元素的意思并不是将它们从行/列总和中删除。

事实上,如果我手动从数组中去掉对角线,那么两个结果是一致的,即

import scipy as sp
gebal = sp.linalg.get_lapack_funcs(('gebal'),(A,)) # this picks up DGEBAL
Ab, lo, hi, scaling , info = gebal(A - np.diag(np.diag(A)), scale=1 , permute=1 , overwrite_a=0 )  

balance.m给出与(当然没有对角线条目)相同的结果。

如果任何精通 Fortran 的用户可以通过检查dgebal.f来确认这一点,我将不胜感激。

编辑:以上结果并不意味着这是唯一的区别。我还构建了不同的矩阵,其中 GEBAL 和 balance.m 即使在对角线分离后也会产生不同的结果。

我很好奇可能有什么区别,但似乎没有办法知道,因为它是 matlab 内置的,因此是封闭的代码。

EDIT2:事实证明,matlab 使用的是旧版本的 LAPACK(可能是 3.5.0 之前的版本),到 2016b 时,它们似乎已升级到新版本。现在,就我可以测试的结果而言,结果是一致的。所以我认为这解决了这个问题。我应该用旧的 LAPACK 版本测试它。