Как решить массив 4 x 4 с 16 неизвестными с помощью Python (обновление)

Мне нужно решить массив 2 на 2 с 4 неизвестными

А Б
КОМПАКТ ДИСК

Я знаю всю горизонтальную сумму 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.] что верно

Теперь мне нужно решить массив 4 на 4 с 16 неизвестными

А Б В Г
Э Ф Г Ч
Я Дж К Л
М Н О П

Я знаю горизонтальную сумму 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

Я в правильном направлении? Мне нужно будет решить 5X5 с 25 неизвестными, 6X6 с 36 неизвестными и так далее. Есть ли способ проще?

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

Следуя решению мистера Рори Долтона, я могу без проблем решить приведенный выше массив 4X4 от 1 до 16, но когда я использую его в другом массиве с отрицательным числом, он не дает ответа, как ожидалось;

Отрицательный массив 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]

Что мне попробовать? Заранее спасибо.

Вы можете посмотреть здесь.

Vasilis G. 08.04.2019 19:58

Определитель вашей матрицы равен 0, поэтому его нельзя инвертировать, вы можете проверить это самостоятельно с помощью print(np.linalg.det(C))

Mntfr 08.04.2019 20:00

Я вижу 22 суммы в тексте, но только 16 строк в матрице.

VPfB 08.04.2019 20:59

Символически это муторно. Вы должны использовать разложение LU, если вы делаете это численно. Это будет необходимо, если вы хотите общее решение.

duffymo 08.04.2019 21:28

Я добавил обновление к своему ответу, чтобы оно соответствовало обновлению вашего вопроса. Резюме: для получения одного ответа нужно добавить больше информации к требованиям задачи.

Rory Daulton 30.04.2019 23:09
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
5
172
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

КРАТКИЙ ОТВЕТ: У вашей проблемы бесконечно много решений. Так что это требует более сложного анализа уравнений.

ДЛИННЫЙ ОТВЕТ: У вас несколько проблем с кодом.

Во-первых, вы легко допускаете ошибки, так как строки вашей матрицы не соответствуют тем данным, которые вы представляете. Хуже того, у вас нет комментариев, чтобы объяснить вещи. Это несоответствие, вероятно, вызовет ошибки. У вас есть 22 элемента данных в ваших суммах, так что используйте их. Вы пытались объединить некоторые суммы и проигнорировать другие (четыре угла), но сделали это неправильно и в итоге получили сингулярную матрицу.

Затем вы используете linalg.solve. В вашей задаче элементов данных (22) больше, чем неизвестных (16), поэтому solve не подходит. Документация numpy для solve состояний

a must be square and of full-rank, i.e., all rows (or, equivalently, columns) must be linearly independent; if either is not true, use lstsq for the least-squares best “solution” of the system/equation.

Матрица, полученная из ваших данных, не является квадратной, поэтому строки не являются линейно независимыми, поэтому вы должны использовать lstsq, а не solve. Подпрограмма lstsq дает больше информации, чем вам нужно для вашей проблемы, поэтому просто напечатайте первый элемент в полученном списке.

Объединение этих идей и добавление нескольких комментариев дает такой код:

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

Функция solve numpy работает только в том случае, если есть только одно решение, поэтому, даже если вы настроили свою матрицу по-другому, она не сработала бы для вас.


ОТВЕТ НА ВАШЕ ОБНОВЛЕНИЕ:

Кажется, вы не поняли суть моего ответа. У вашей задачи 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 дал вам правильный ответ — он понятия не имеет, как выбрать ответ, который был у вас в голове, из бесконечного множества правильных ответов на вашу проблему. Единственный способ получить только один ответ — изменить задачу — например, указать значение в первой строке и втором столбце, или сумму первого и третьего значений в любой из строк, или что-то подобное.

Спасибо, сэр Рори Долтон, за подробный ответ. Это очень помогает.

Simon Simoon 11.04.2019 15:25

Я принял лучший ответ, но у меня пока нет репутации, чтобы голосовать.

Simon Simoon 14.04.2019 19:05

@SimonSimoon: я понимаю, поэтому я сказал «если у вас достаточно репутации» в моем (теперь удаленном) комментарии. Вы молодец: задали хороший вопрос и хорошо ответили на него. Я надеюсь, что вы продолжите на этом сайте.

Rory Daulton 14.04.2019 19:07

Я попробовал np.linalg.lstsq для следующего массива 4X4.

Simon Simoon 30.04.2019 18:01

Другие вопросы по теме