【问题标题】:How to solve 4 x 4 array with 16 unknown with Python (Update)如何使用 Python 求解 4 x 4 数组,其中 16 个未知数(更新)
【发布时间】:2019-08-29 22:25:58
【问题描述】:

我需要用 4 个未知数求解一个 2×2 数组

A B
光盘

我知道所有水平和 A+B=11, C+D=7
我知道所有垂直和 A+C=10, B+D=8
我知道所有对角线和 A+D=15, B+C=3

然后我使用 Python 求解 A、B、C、D

import numpy as np

A = [[1, 1, 1, 1], 
     [1, 0, 0, 1], 
     [1, 0, 1, 0], 
     [0, 0, 1, 1]]
a = [18, 15, 10, 7]
answera = np.linalg.solve(A, a)
print(answera)

答案是 [9. 2. 1. 6.] 这是正确的

现在我需要用 16 个未知数解决 4 x 4 数组

A B C D
E F G H
I J K L
中号

我知道水平和 A+B+C+D=10, E+F+G+H=26, I+J+K+L=42, M+N+O+P=58
我知道垂直和 A+E+I+M=28, B+F+J+N=32, C+G+K+O=36, D+H+L+P=40
我知道对角线和 M=13, I+N=23, E+J+O=30, A+F+K+P=34, B+G+L=21, C+H=11, D=4 另一个对角线和 A=1, B+E=7, C+F+I=18, D+G+J+M=34, H+K+N=33, L+O=27, P=16 这意味着我知道 4 个角的值。

我尝试了以下代码,但没有成功

C = [[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
     [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], 
     [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1],
     [0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0],
     [0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0],
     [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
     [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
     [0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]] 

c = [10, 26, 42, 58, 7, 21, 39, 33, 27, 11, 23, 35, 30, 23, 32, 136]
answerc = np.linalg.solve(C, c)
print(answerc)

正确答案应该是 [1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16.] 但我收到错误消息

Traceback (most recent call last):
answerc = np.linalg.solve(C, c)
r = gufunc(a, b, signature=signature, extobj=extobj)
 raise LinAlgError("Singular matrix")
numpy.linalg.LinAlgError: Singular matrix

我的方向正确吗?我需要用 25 个未知数求解 5X5,用 36 个未知数求解 6X6,依此类推。有没有更简单的方法?

-----------------------------------------------------------------------------

按照Rory Daulton先生的解决方案,我可以毫无问题地解决上面的1到16 4X4阵列,但是当我使用它时另一个带有负数的数组,它没有按预期给出答案;

负4X4数组如下

-20   -10    -5    0
-10   -20   -10   -5
-5      0   -10   -20
-10   -20   -10   -5

我的python代码如下

import numpy as np
G = [[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  # horizontal rows
     [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], 
     [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1],
     [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],  # vertical columns
     [0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
     [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0],
     [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],  # forward diagonals
     [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
     [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
     [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
     [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0],
     [0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  # back diagonals
     [0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
    ]

g = [-35, -45, -35, -45,  # horizontal rows
     -45, -50, -35, -30,  # vertical columns
     -10, -25, -20, -55, -40, -10, 0,  # forward diagonals
     -20, -20, -30, -20, -35, -30, -5,  # back diagonals
    ]

answerg = np.linalg.lstsq(G, g, rcond=None)
print(answerg[0])

输出不完全是原始数组

[-2.00000000e+01 -1.31250000e+01 -1.87500000e+00  8.88178420e-15
 -6.87500000e+00 -2.00000000e+01 -1.00000000e+01 -8.12500000e+00
 -8.12500000e+00  2.13162821e-14 -1.00000000e+01 -1.68750000e+01
 -1.00000000e+01 -1.68750000e+01 -1.31250000e+01 -5.00000000e+00]

我应该尝试什么?提前谢谢你。

【问题讨论】:

  • 你可以看看here
  • 矩阵的行列式是 0,因此它不能倒置,你可以自己用 print(np.linalg.det(C)) 来检查这个
  • 我看到文本中有 22 个总和,但矩阵中只有 16 行。
  • 象征性地是一件苦差事。如果您以数字方式进行,则应该使用 LU 分解。如果你想要一个通用的解决方案,这将是必要的。
  • 我在我的答案中添加了更新,以匹配您的问题的更新。摘要:要获得一个答案,您需要在问题的要求中添加更多信息。

标签: python arrays math


【解决方案1】:

简短回答:您的问题有无数种解决方案。所以这需要对方程进行更复杂的分析。

长答案:您的代码存在多个问题。

首先,您很容易出错,因为矩阵的行与您提供的数据不对应。更糟糕的是,你没有 cmets 来解释事情。这种不匹配可能会导致错误。您的总和中有 22 条数据,因此请使用它们。您尝试合并一些总和并忽略其他总和(四个角),但您没有正确执行,最终得到一个奇异矩阵。

接下来,您使用linalg.solve。在您的问题中,您的数据项 (22) 比未知数 (16) 多,因此 solve 不合适。 The numpy documentation for solve 状态

a 必须是正方形并且是满秩的,即所有行(或者,等效地, 列)必须是线性独立的;如果其中一个不正确,请使用 lstsq 表示系统/方程的最小二乘最佳“解”。

您的数据生成的矩阵不是正方形的,因此行不是线性独立的,因此您应该使用lstsq 而不是solvelstsq 例程提供的信息比您解决问题所需的信息多,因此只需打印结果列表中的第一项即可。

结合这些想法并添加一些 cmets 得到以下代码:

import numpy as np

C = [[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  # horizontal rows
     [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], 
     [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1],
     [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],  # vertical columns
     [0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
     [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0],
     [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],  # forward diagonals
     [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
     [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
     [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
     [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0],
     [0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  # back diagonals
     [0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
    ]

c = [10, 26, 42, 58,  # horizontal rows
     28, 32, 36, 40,  # vertical columns
     13, 23, 30, 34, 21, 11, 4,  # forward diagonals
     1, 7, 18, 34, 33, 27, 16,  # back diagonals
    ]

answerc = np.linalg.lstsq(C, c, rcond=None)
print(answerc[0])

打印出来的就是你想要的:

[ 1.  2.  3.  4.  5.  6.  7.  8.  9. 10. 11. 12. 13. 14. 15. 16.]

但是,老实说,不能保证这是一个答案 - 只是它是一个“最接近”的答案。此外,如果它是一个答案,可能还有其他答案。而且,实际上,进一步分析表明,还有其他答案可以满足您的所有条件。

sympy 模块可以生成矩阵的行缩减梯形形式,可用于对所有答案进行更深入的分析。但是,这些常量将成为矩阵的一部分,而不是用作单独的数组。这是 sympy 尝试解决您的问题的代码:

import sympy

C = [[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],  # horizontal rows
     [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 26], 
     [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 42],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 58],
     [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 28],  # vertical columns
     [0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 32],
     [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 36],
     [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 40],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 13],  # forward diagonals
     [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 23],
     [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30],
     [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 34],
     [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 21],
     [0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 11],
     [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  4],
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1],  # back diagonals
     [0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  7],
     [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 18],
     [0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 34],
     [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 33],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 27],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 16],
    ]

print(sympy.Matrix(C).rref())

打印出来的是

(Matrix([
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0,   1],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -13],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1, 0,  18],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0,   4],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1, 0,  20],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0,   6],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,  0, 0,   7],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, -1, 0,  -7],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0,  -6],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,  0, 0,  10],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,  0, 0,  11],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,  1, 0,  27],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,  0, 0,  13],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  1, 0,  29],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 1,  16],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0,   0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0,   0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0,   0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0,   0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0,   0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0,   0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0,   0]]), (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15))

如果您知道如何分析这个问题,您会发现有无数个问题可以解决您的问题。如果您将第 15 个单元格中的数字设置为 15+x,那么上面的矩阵表明您的所有限制的答案是

 1     2+x   3-x   4
 5-x   6     7     8+x
 9+x  10    11    12-x
13    14-x  15+x  16

numpy 的 solve 函数仅在只有一个解决方案时才有效,因此即使您以不同的方式调整矩阵,它也不适合您。


回答您的更新:

看来你错过了我回答的重点。您的 4x4 问题有无限多的答案,因此没有程序可以选择您心目中的特定答案。 np.linalg.lstsq 例程可以找到问题的答案之一,但可能找不到您想要的答案。您应该认为在您的第一个问题中使用该例程给出了您想要的答案是一个巧合 - 这可能不适用于其他问题。

解释新问题的给定答案有点困难,因为科学记数法很难阅读。但是所有这些矩阵值都是精确的,在这里它们是一种特定格式的有理数,应该很明显:

-20          -10-(3+1/8)  - 5+(3+1/8)    0
-10+(3+1/8)  -20          -10          - 5-(3+1/8)
- 5-(3+1/8)    0          -10          -20+(3+1/8)
-10          -20+(3+1/8)  -10-(3+1/8)  - 5

您会看到 numpy 的答案是您所期望的答案,将值 3+1/8 添加到数组值的一半或从数组值的一半中减去。这使得x=3+1/8 成为我为您的第一个问题提供的一般答案。

这和您期望的一样好。 Numpy 给了你一个正确的答案——它不知道如何从你的问题的无数正确答案中选择你脑海中的答案。只获得一个答案的唯一方法是更改​​您的问题 - 可能说明第一行和第二列中的值,或者任何一行中的第一个和第三个值的总和,或类似的东西。

【讨论】:

  • 感谢 Rory Daulton 爵士的详细回答。很有帮助。
  • 我接受了最佳答案,但我还没有投票的声誉。
  • @SimonSimoon:我明白——这就是为什么我在我的(现已删除)评论中说“如果你有足够的声誉”。你做得很好——你问了一个很好的问题,并且很好地回答了一个答案。我希望你继续在这个网站上。
  • 我为以下 4X4 数组尝试了 np.linalg.lstsq
猜你喜欢
  • 2022-06-10
  • 1970-01-01
  • 2016-05-29
  • 1970-01-01
  • 1970-01-01
  • 2018-01-02
  • 2017-01-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多