Программирование на Python/умножение матриц

Тонкости умножения матриц при программировании на Python с использованием списков

Подробный анализ умножения матриц на языке программирования Python.

Умножение матриц — это процесс, результатом которого является создание матрицы путем умножения двух матриц. Главное условие для этого состоит в том, что столбец первой матрицы должен совпадать со строкой второй матрицы. Умножение матриц — обязательная тема для ученика XII класса. Задание по вычислению умножения матриц с использованием C/C+ является повсеместным для студента, поступающего в колледж информатики. Тем не менее, сложности, связанные с умножением матриц, также часто упускаются из виду, когда программа написана на Python.

Если вы выполните поиск по термину «python для умножения матриц», Google предоставит вам множество страниц, на которых указаны жестко закодированные коды умножения матриц. Почти каждый код, указанный на этих веб-сайтах, удобно игнорирует случай, когда умножение происходит между матрицей с одной строкой и матрицей с несколькими строками. Давайте углубимся в это дальше.

Простая жестко закодированная программа для умножения матриц на Python будет легко напоминать код ниже:

def matrix_mul(MatrixA, MatrixB):
    """
    Function to create a matrix resulting from multiplication of two matrices
    """
    global r1, c1
    global r2, c2
    global MatrixC
    for i in range(r1):
        for j in range(c2):
            for k in range(r2):
                MatrixC[i][j] += MatrixA[i][k] * MatrixB[k][j]
MatrixA = [[1, 2], [3, 4]]
MatrixB = [[1, 2, 3, 4, 5], [5, 6, 7, 8, 9]]
r1 = 2
c1 = 2
r2 = 2
c2 = 5
MatrixC = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
matrix_mul(MatrixA, MatrixB)
aster = '*'
print(aster * 68)
print('The resultant matrix is:')
print(aster * 68)
print(MatrixC)
print(aster * 68)

Когда вы запустите код, он выдаст следующий вывод:

********************************************************************
The resultant matrix is:
********************************************************************
[[11, 14, 17, 20, 23], [23, 30, 37, 44, 51]]
********************************************************************

Код начинается с инициализации значений MatrixA (порядка 2x2) и MatrixB (порядка 2x5). Затем вызывается функция matrix_mul с матрицами для перемножения в качестве аргументов. Функция выполняет умножение матриц на скалярное произведение строк первой матрицы на столбцы второй матрицы (Скалярное произведение — это умножение совпадающих элементов). Результирующая матрица будет иметь строки, равные первой матрице, и столбцы, равные второй матрице.

Недостатки кода (как и большинство кодов, доступных в Интернете на различных веб-сайтах) проявляются, когда матрица A (порядка 1x3) умножается на другую матрицу B (порядка 3x1). При запуске кода возникает TypeError.

TypeError: объект «int» не может быть подписан

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-26-a342be5c878d> in <module>()
     16 MatrixB = [[4], [5], [6]]
     17 MatrixC = [0]
---> 18 matrix_mul(MatrixA, MatrixB)
     19 aster = '*'
     20 print(aster * 70)
<ipython-input-26-a342be5c878d> in matrix_mul(MatrixA, MatrixB)
      9         for j in range(5):
     10             for k in range(2):
---> 11                 MatrixC[i][j] += MatrixA[i][k] * MatrixB[k][j]
     12 
     13 
TypeError: 'int' object is not subscriptable

Чтобы лучше понять эту ошибку, давайте рассмотрим список из трех элементов.

list1 = [1, 2, 3]
print(list1[0][0])

Если мы запустим этот код, произойдет тот же TypeError. Причина в том, что индекс списка, к которому пытается получить доступ код, находится вне допустимого диапазона. Если бы list1 был списком списков (как в приведенном ниже коде), вывод был бы 1.

list1 = [[1], [2], [3]]
print(list1[0][0])

В программе функция matrix_mul(MatrixA, MatrixB) выполняет умножение матриц в следующих строках кода.

for i in range(r1):
        for j in range(c2):
            for k in range(r2):
                MatrixC[i][j] += MatrixA[i][k] * MatrixB[k][j]

Основная причина TypeError связана с этой самой строкой кода. Причина в незнании программистом следующих двух сценариев, в которых задействована однострочная матрица:

Сценарий 1: когда строка первой матрицы и столбец второй матрицы совпадают. Матрица A порядка 1x3 и MatrixB порядка 3x1 являются типичным примером. В этом случае MatrixA и MatrixC (нулевая матрица) являются списками (вместо списка списков). Следовательно, когда вычисляется MatrixC[i][j] += MatrixA[i][k] * MatrixB[k][j], индекс выходит за пределы допустимого диапазона для MatrixC и MatrixA, поскольку они являются однострочными матрицами. Следовательно, объект TypeError: ‘int’ не подлежит подписке.

Сценарий 2: Когда строка первой матрицы равна единице, а столбец второй матрицы не равен единице. MatrixA порядка 1x2 и MatrixB порядка 2x2 являются примером. Как и в предыдущем случае, матрицы MatrixA и MatrixC являются однострочными матрицами. Следовательно, возникает TypeError.

Давайте исправим эти проблемы и постараемся создать программу, включающую все аспекты умножения матриц. Одновременно давайте расширим возможности конечного пользователя (человека, запускающего код) и сделаем код более универсальным, позволив ему/ей определять порядок матриц и вводить соответствующие значения во время выполнения.

Приведенный выше код получает пользовательский ввод во время выполнения и проверяет, ввел ли пользователь правильные данные. Код проверяет все возможные ошибки, которые пользователь может допустить во время ввода. Для начала программа проверяет, являются ли входные данные, полученные для порядка матрицы, целым числом. Для этого используется обработка исключений Python (попробуйте, кроме) для повышения ValueError.

Enter the no. of rows of Matrix A: 2.5
Please enter a valid integer greater than zero

Сообщение об ошибке появляется, если столбец первой матрицы не равен строке второй матрицы.

Enter the no. of rows of Matrix A: 2
Enter the no. of columns of Matrix A: 3
Enter the no. of rows of Matrix B: 4
Enter the np. of columns of Matrix B: 2
Kindly change the order of matrices. For multiplication of matrices, the no. of columns of first matrix must be equal to no. of rows of second matrix.

Если порядок первой матрицы 2x2 и пользователь вводит четыре элемента для первой строки, программа выдает сообщение об ошибке «Пожалуйста, введите элементы равные 2 — размер столбца матрицы A».

Программа учитывает два сценария однострочной матрицы, которые обсуждались ранее. Рассмотрим Сценарий 1, когда количество строк первой матрицы и количество столбцов второй матрицы равно единице (например, матрица A имеет порядок 1x3, а матрица B имеет порядок 3x1), матрица C будет быть матрицей 1x1. Как и matrixC, MatrixA будет однострочной матрицей. В этом случае умножение матриц выполняется с помощью следующей строки кода:

if(r1 == 1)&(c2 == 1):  #(1x3)*(3x1)=(1x1)
        for i in range(r1):
            for j in range(c2):
                for k in range(r2):
                    matrixC[i] += matrixA[k] * matrixB[k][j]

Сценарий 2 имеет дело с ситуацией, когда количество строк первой матрицы равно единице, а количество столбцов второй матрицы не равно единице (например, матрица A имеет порядок 1x2, а матрица B имеет порядок 2х2). Как и в сценарии 1, матрицы A и C являются однострочными матрицами. Разница заключается в способе вычисления значения матричного умножения. В сценарии 1 матрица C повторяется по значениям i (строка матрицы A), тогда как в сценарии 2 матрица C повторяется по значениям j (столбец матрицы B).

elif(r1 == 1)&(c2 != 1): #(1x2)*(2x2)=(1x2)
        for i in range(r1):
            for j in range(c2):
                for k in range(r2):
                    matrixC[j] += matrixA[k] * matrixB[k][j]

И в Сценарии 1, и в Сценарии 2 матрица C вычисляется таким образом, что она становится матрицей с одной строкой.

if(r1 == 1)|(r1 == c2 == 1): 
        for i in range(r1):
            matrixC = []
            for j in range(c2):
                matrixC.append(0)

Во всех остальных случаях умножение матриц выполняется обычным кодом:

else: #all other cases
        for i in range(r1):
            for j in range(c2):
                for k in range(r2):
                    matrixC[i][j] += matrixA[i][k] * matrixB[k][j]

matrixC, представляющий собой многострочную матрицу, вычисляется по формуле:

for i in range(r1):
            row_matrixC = []
            for j in range(c2):
                row_matrixC.append(0)            
            matrixC.append(row_matrixC)

Все эти случаи можно рассматривать как один случай в C++ (одно решение подходит для всех подходов). Умножение матриц, выполненное в C++:

Ссылка на гитхаб



Удачного кодирования!!!