我有一个不使用随机化的脚本,当我运行它时会给出不同的答案。每次运行脚本时,我都希望答案是一样的。问题似乎只发生在某些(病态的)输入数据上。
该片段来自为线性系统计算特定类型控制器的算法,它主要由线性代数(矩阵求逆,Riccati方程,特征值)组成。
显然,这对我来说是一个主要的担忧,因为我现在不能相信我的代码能给我正确的结果。我知道结果对条件差的数据来说可能是错误的,但我一直都错了。为什么我的Windows机器上的答案并不总是一样的?为什么Linux& Windows机器没有给出相同的结果?
我使用Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win 32
,使用Numpy版本1.8.2和Scipy 0.14.0。 (Windows 8,64位)。
代码如下。我也尝试在两台Linux机器上运行代码,脚本总是给出相同的答案(但机器给出了不同的答案)。一个是运行Python 2.7.8,Numpy 1.8.2和Scipy 0.14.0。第二个是使用Numpy 1.6.1和Scipy 0.12.0运行Python 2.7.3。
我三次解决Riccati方程,然后打印答案。我希望每次都得到相同的答案,而不是我得到序列' 1.75305103767e-09; 3.25501787302e-07; 3.25501787302e-07'
import numpy as np
import scipy.linalg
matrix = np.matrix
A = matrix([[ 0.00000000e+00, 2.96156260e+01, 0.00000000e+00,
-1.00000000e+00],
[ -2.96156260e+01, -6.77626358e-21, 1.00000000e+00,
-2.11758237e-22],
[ 0.00000000e+00, 0.00000000e+00, 2.06196064e+00,
5.59422224e+01],
[ 0.00000000e+00, 0.00000000e+00, 2.12407340e+01,
-2.06195974e+00]])
B = matrix([[ 0. , 0. , 0. ],
[ 0. , 0. , 0. ],
[ -342.35401351, -14204.86532216, 31.22469724],
[ 1390.44997337, 342.33745324, -126.81720597]])
Q = matrix([[ 5.00000001, 0. , 0. , 0. ],
[ 0. , 5.00000001, 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]])
R = matrix([[ -3.75632852e+04, -0.00000000e+00, 0.00000000e+00],
[ -0.00000000e+00, -3.75632852e+04, 0.00000000e+00],
[ 0.00000000e+00, 0.00000000e+00, 4.00000000e+00]])
counter = 0
while counter < 3:
counter +=1
X = scipy.linalg.solve_continuous_are(A, B, Q, R)
print(-3449.15531628 - X[0,0])
我的numpy配置如下print np.show_config()
lapack_opt_info: libraries = ['mkl_blas95', 'mkl_lapack95', 'mkl_intel_c', 'mkl_intel_thread', 'mkl_core', 'libiomp5md', 'mkl_blas95', 'mkl_lapack95', 'mkl_intel_c', 'mkl_intel_thread', 'mkl_core', 'libiomp5md'] library_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/lib/ia32', 'C:/Program Files (x86)/Intel/Composer XE 2013 SP1/compiler/lib/ia32'] define_macros = [('SCIPY_MKL_H', None)] include_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/include'] blas_opt_info: libraries = ['mkl_blas95', 'mkl_lapack95', 'mkl_intel_c', 'mkl_intel_thread', 'mkl_core', 'libiomp5md'] library_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/lib/ia32', 'C:/Program Files (x86)/Intel/Composer XE 2013 SP1/compiler/lib/ia32'] define_macros = [('SCIPY_MKL_H', None)] include_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/include'] openblas_info: NOT AVAILABLE lapack_mkl_info: libraries = ['mkl_blas95', 'mkl_lapack95', 'mkl_intel_c', 'mkl_intel_thread', 'mkl_core', 'libiomp5md', 'mkl_blas95', 'mkl_lapack95', 'mkl_intel_c', 'mkl_intel_thread', 'mkl_core', 'libiomp5md'] library_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/lib/ia32', 'C:/Program Files (x86)/Intel/Composer XE 2013 SP1/compiler/lib/ia32'] define_macros = [('SCIPY_MKL_H', None)] include_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/include'] blas_mkl_info: libraries = ['mkl_blas95', 'mkl_lapack95', 'mkl_intel_c', 'mkl_intel_thread', 'mkl_core', 'libiomp5md'] library_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/lib/ia32', 'C:/Program Files (x86)/Intel/Composer XE 2013 SP1/compiler/lib/ia32'] define_macros = [('SCIPY_MKL_H', None)] include_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/include'] mkl_info: libraries = ['mkl_blas95', 'mkl_lapack95', 'mkl_intel_c', 'mkl_intel_thread', 'mkl_core', 'libiomp5md'] library_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/lib/ia32', 'C:/Program Files (x86)/Intel/Composer XE 2013 SP1/compiler/lib/ia32'] define_macros = [('SCIPY_MKL_H', None)] include_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/include'] None
(编辑以减少问题)
答案 0 :(得分:7)
通常,Windows上的linalg库在机器精度级别的不同运行中给出不同的答案。我从来没有听说过为什么这种情况只发生在Windows上或者主要发生在Windows上。
如果您的矩阵病态恶化,则inv将主要是数字噪声。在Windows上,连续运行时噪声并不总是相同,在其他操作系统上噪声可能总是相同但可能会有所不同,具体取决于线性代数库的细节,线程选项,缓存使用等等。
我已经在scipy邮件列表上看到并在Windows上发布了几个这样的示例,我主要使用ATLAS BLAS / LAPACK的官方32位二进制文件。
唯一的解决方案是使计算结果不依赖于浮点精度问题和数值噪声,例如将矩阵求逆,使用广义逆,pinv,重新参数化等。
答案 1 :(得分:2)
pv中提到comments to user333700's answer,Riccati求解器的先前公式虽然在理论上是正确的,但在数值上并不稳定。此问题已在SciPy的开发版本上修复,求解器也支持广义Riccati方程。
Riccati解算器已更新,所得到的求解器将从0.19及更高版本开始提供。您可以查看development branch docs here。
如果使用问题中的给定示例,我用
替换最后一个循环ERROR:Simulator:1026 - The switch -hwcosim_clock <clock_port_name> must be specified for hardware cosimulation.
我得到(windows 10,py3.5.2)
for _ in range(5):
x = scipy.linalg.solve_continuous_are(A, B, Q, R)
Res = x@a + a.T@x + q - x@b@ np.linalg.solve(r,b.T)@ x
print(Res)
作为参考,返回的解决方案是
[[ 2.32314924e-05 -2.55086270e-05 -7.66709854e-06 -9.01878229e-06]
[ -2.62447211e-05 2.61182140e-05 8.27328768e-06 1.00345896e-05]
[ -7.92257197e-06 8.57094892e-06 2.50908488e-06 3.05714639e-06]
[ -9.51046241e-06 9.80847472e-06 3.13103374e-06 3.60747799e-06]]
[[ 2.32314924e-05 -2.55086270e-05 -7.66709854e-06 -9.01878229e-06]
[ -2.62447211e-05 2.61182140e-05 8.27328768e-06 1.00345896e-05]
[ -7.92257197e-06 8.57094892e-06 2.50908488e-06 3.05714639e-06]
[ -9.51046241e-06 9.80847472e-06 3.13103374e-06 3.60747799e-06]]
[[ 2.32314924e-05 -2.55086270e-05 -7.66709854e-06 -9.01878229e-06]
[ -2.62447211e-05 2.61182140e-05 8.27328768e-06 1.00345896e-05]
[ -7.92257197e-06 8.57094892e-06 2.50908488e-06 3.05714639e-06]
[ -9.51046241e-06 9.80847472e-06 3.13103374e-06 3.60747799e-06]]
[[ 2.32314924e-05 -2.55086270e-05 -7.66709854e-06 -9.01878229e-06]
[ -2.62447211e-05 2.61182140e-05 8.27328768e-06 1.00345896e-05]
[ -7.92257197e-06 8.57094892e-06 2.50908488e-06 3.05714639e-06]
[ -9.51046241e-06 9.80847472e-06 3.13103374e-06 3.60747799e-06]]
[[ 2.32314924e-05 -2.55086270e-05 -7.66709854e-06 -9.01878229e-06]
[ -2.62447211e-05 2.61182140e-05 8.27328768e-06 1.00345896e-05]
[ -7.92257197e-06 8.57094892e-06 2.50908488e-06 3.05714639e-06]
[ -9.51046241e-06 9.80847472e-06 3.13103374e-06 3.60747799e-06]]