7.1.3. Умножение MathCAD 12 руководство
RADIOMASTERЛучшие смартфоны на Android в 2022 году
Серия iPhone от Apple редко чем удивляет. Когда вы получаете новый iPhone, общее впечатление, скорее всего, будет очень похожим на ваше предыдущее устройство. Однако всё совсем не так в лагере владельцев устройств на Android. Существуют телефоны Android всех форм и размеров, не говоря уже о разных ценовых категориях. Другими словами, Android-телефон может подойти многим. Однако поиск лучших телефонов на Android может быть сложной задачей.
1740 0
Документация Схемотехника CAD / CAM Статьи
MathCAD 12 MatLab OrCAD P CAD AutoCAD MathCAD 8 — 11
- Главная /
- База знаний /
- CAD / CAM / org/Breadcrumb»>MathCAD 12
- Линейная алгебра
- 7.1. Простейшие матричные операции
- 7.1.1. Транспонирование
- 7.1.2. Сложение и вычитание
- 7.1.3. Умножение
- 7.2. Векторная алгебра
- 7.2.1. Модуль вектора
- 7.2.2. Скалярное произведение
- 7.2.3. Векторное произведение
- 7.2.4. Векторизация массива
- 7.3. Вычисление определителей и обращение квадратных матриц
- 7.3.1. Определитель квадратной матрицы
- 7.3.2. Ранг матрицы
- 7.3.3. Обращение квадратной матрицы
- 7.3.4. Возведение квадратной матрицы в степень
- 7.3.5. Матричные нормы
- 7.3.6. Число обусловленности квадратной матрицы
- 7.4. Вспомогательные матричные функции
- 7.4.1. Автоматическая генерация матриц
- 7.4.2. Разбиение и слияние матриц
- 7. 4.3. Сортировка элементов матриц
- 7.4.4. Вывод размера матрицы
При умножении следует помнить, что матрицу размерности MxN допустимо умножать только на матрицу размерности NxP (р может быть любым). В результате получается матрица размерности MхP.
Чтобы ввести символ умножения, нужно нажать клавишу со звездочкой <*> или воспользоваться панелью инструментов Matrix (Матрица), нажав на ней кнопку Dot Product (Умножение). Умножение матриц обозначается по умолчанию точкой, как показано в листинге 7.5.
Листинг 7.5. Перемножение матриц
Обратите внимание (нижняя строка листинга 7.5), что попытка перемножить матрицы А и В несоответствующего (одинакового 2х3) размера оказалась безрезультатной: после введенного знака равенства находится пустой местозаполнитель, а само выражение в редакторе Mathcad выделяется красным цветом. При установке курсора на это выражение появляется сообщение о несовпадении числа строк первой матрицы с числом столбцов второй матрицы.
Еще один пример, относящийся к умножению вектора на матрицу-строку и, наоборот, строки на вектор, приведен в листинге 7.6.
ВНИМАНИЕ!
Тот же самый оператор умножения действует на два вектора по-другому (см. разд. 7.2.2).
Листинг 7.6. Умножение вектора и строки
Аналогично сложению матриц со скаляром определяется умножение и деление матрицы на скалярную величину (листинг 7.7). Символ умножения вводится так же, как и в случае умножения двух матриц. На скаляр можно умножать матрицу любой размерности.
Листинг 7.7. Умножение матрицы на скалярную величину
Нравится
Твитнуть
Теги MathCad САПР
Сюжеты MathCad
Глава 1 Основы работы с системой Mathcad 11
10102 0
Глава 10 Работа с информационными ресурсами Mathcad 11
7088 0
Глава 2 Работа с файлами Mathcad 11
12833 0
Комментарии (0)
Вы должны авторизоваться, чтобы оставлять комментарии.
Вход
О проекте Использование материалов Контакты
Новости Статьи База знаний
Радиомастер
© 2005–2022 radiomaster. ru
При использовании материалов данного сайта прямая и явная ссылка на сайт radiomaster.ru обязательна. 0.2357 s
Ассемблер ARM64 | Умножение матриц
Последнее обновление: 17.01.2023
Рассмотрим расспространенную задачу — умножение матриц. Например, у нас есть следующие матрицы
матрица A
a11 | a12 | a13 |
a21 | a22 | a23 |
a31 | a32 | a33 |
матрица B
b11 | b12 | b13 |
b21 | b22 | b23 |
b31 | b32 | b33 |
То результат перемножения матриц будет равен
a11*b11 + a12*b21 + a13*b31 | a11*b12 + a12*b22 + a13*b32 | a11*b13 + a12*b23 + a13*b33 |
a21*b11 + a22*b21 + a23*b31 | a21*b12 + a22*b22 + a23*b32 | a21*b13 + a22*b23 + a23*b33 |
a31*b11 + a32*b21 + a33*b31 | a31*b12 + a32*b22 + a33*b32 | a31*b13 + a32*b23 + a33*b33 |
То есть для получения элемента результирующей матрицы, элементы строки первой матрицы последовательно перемножаются на элементы столбцов второй матрицы, и результаты умножений складываются.
С точки зрения псевдокода это выглядело бы так:
FOR row = 1 to 3 FOR col = 1 to 3 acum = 0 FOR i = 1 to 3 acum = acum + A[row, i]*B[i, col] NEXT I C[row, col] = acum NEXT col NEXT row
Напишем программу для перемножения двух матриц размером 3×3. Для упрощения вывода результатов на консоль воспользуемся функции printf языка С.
Итак, определим файл main.s со следующим кодом:
// Умножение двух матриц 3x3 // // Используемые регистры: // W1 - Индекс строки // W2 - Индекс столбца // X4 - Адрес строки // X5 - Адрес столбца // X7 - накопленная сумма для элемент результирующей матрицы // W9 - элемент матрицы A // W10 - элемент матрицы B // X19 - элемент матрицы C // X20 - счетчик цикла для печати // X12 - номер стороки в цикле dotloop // X6 - номер столбца в цикле dotloop .global main // точка входа в программу . equ N, 3 // Размер матрицы .equ WDSIZE, 4 // размер элемента в байтах main: STR LR, [SP, #-16]! // сохраняем значение регистра LR STP X19, X20, [SP, #-16]! // сохраняем значения регистров X19 и X20 MOV W1, #N // помещаем в W1 индекс строки LDR X4, =A // В X4 адрес текущей строки матрицы А LDR X19, =C // В X19 адрес материцы С rowloop: LDR X5, =B // первый столбец матрицы B MOV W2, #N // индекс столбца (считаем в обратном порядке до 0) colloop: MOV X7, #0 // регистр для накопления результата - по умолчанию равен 0 MOV W0, #N // счетчик цикла MOV X12, X4 // в X12 помещаем адрес строки для перемножения элементов MOV X6, X5 // в X6 помещаем адрес столбца для перемножения элементов dotloop: // Цикл для умножения элементов текущей строки матрицы A на элементы текущего столбца матрицы B LDR W9, [X12], #WDSIZE // загружаем A[row, i] и увеличиваем адрес в X12 на #WDSIZE байт LDR W10, [X6], #(N*WDSIZE) // загружаем в W10 данные из B[i, col] SMADDL X7, W9, W10, X7 // умножаем и сохраняем результат в X7 SUBS W0, W0, #1 // уменьшаем счетчик на 1 B. NE dotloop // если W0 не равно 0, то переходим к dotloop для перемножения новых элементов матриц STR W7, [X19], #4 // сохраняем результат из W7 в X19 - C[row, col] = W7, увеличиваем адрес в X19 на 4 байта ADD X5, X5, #WDSIZE // Переходим к следующему столбцу в матрице B - увеличиваем адрес в X5 на #WDSIZE байт SUBS W2, W2, #1 // увеличиваем счетчик столбцов B.NE colloop // если не все столбцы прошли, то переходим обратно к colloop ADD X4, X4, #(N*WDSIZE) // к адресу в X4 прибавляем #(N*WDSIZE) байт для перехода к адресу новой строки SUBS W1, W1, #1 // уменьшаем счетчик строк B.NE rowloop // если еще есть строки, переходим обратно к rowloop MOV W20, #3 // проходим по трем строкам LDR X19, =C // адрес результирующей матрицы C // выводим матрицу с помощью функции printf языка C printloop: LDR X0, =prtstr // загружаем строку форматирования для функции printf LDR W1, [X19], #WDSIZE // первый элемент текущей строки матрицы LDR W2, [X19], #WDSIZE // второй элемент текущей строки матрицы LDR W3, [X19], #WDSIZE // третий элемент текущей строки матрицы BL printf // Вызыв функции printf SUBS W20, W20, #1 // уменьшаем счетчик строк B. NE printloop // если есть еще строки, переходим обратно к printloop MOV X0, #0 // код возврата из функции LDP X19, X20, [SP], #16 // восстанавливаем значение регистров LDR LR, [SP], #16 // восстанавливаем регистр LR RET // выход из функции .data // первая матрица A: .word 1, 2, 3 .word 4, 5, 6 .word 7, 8, 9 // вторая матрица B: .word 9, 8, 7 .word 6, 5, 4 .word 3, 2, 1 // результирующая матрица C: .fill 9, 4, 0 prtstr: .asciz "%3d %3d %3d\n"
Вкратце рассмотрим данный код. Прежде всего в секции .data определены три матрицы. Матрицы A и B состоят из 9 элементов типа .word
, то есть чисел
размером 4 байта. Матрица C определена с помощью директивы .fill
, которая определяет набор из 9 элементов размеров 4 байта, каждый из которых по умолчанию равен 0.
Для упрощения работы определяем две дополнительные константы:
.equ N, 3 // Размер матрицы .equ WDSIZE, 4 // размер элемента в байтах
Вначале определяем значения для прохода по строкам:
MOV W1, #N // помещаем в W1 индекс строки LDR X4, =A // В X4 адрес текущей строки матрицы А LDR X19, =C // В X19 адрес материцы С
В W1 помещаем счетчик строк, то есть число 3 (надо пройти по трем строкам матрицы А). В регистр X4 загружается адрес матрицы A (адрес первого ее элемента) и в X19 помещается адрес матрицы С, в которую будем сохранять результат.
Дальше начинаем цикл для прохода по строкам и определяем значения для прохода по столбцам матрицы B:
rowloop: LDR X5, =B // первый столбец матрицы B MOV W2, #N // индекс столбца (считаем в обратном порядке до 0)
В регистр X5 помещается адрес матрицы В, а в W2 — счетчик столбцов (то есть надо пройтись по 3 столбцам матрицы В).
Затем начинаем цикл по столбцам
colloop: MOV X7, #0 // регистр для накопления результата - по умолчанию равен 0 MOV W0, #N // счетчик цикла MOV X12, X4 // в X12 помещаем адрес строки для перемножения элементов MOV X6, X5 // в X6 помещаем адрес столбца для перемножения элементов
В регистр Х7 помещаем число 0 — этот регистр будет накапливать значения для одного элемента матрицы С. Кроме того, в W0 помещается счетчик цикла — надо перемножить 3 элемента из строки матрицы А и столбца марицы B. Регистр Х12 будет указывать на адрес текущего элемента строки матрицы А, а Х6 — на адрес текущего элемента столбца матрицы В.
Далее перемножаем все элементы текущей строки матрицы А и текущего столбца матрицы В:
dotloop: // Цикл для умножения элементов текущей строки матрицы A на элементы текущего столбца матрицы B LDR W9, [X12], #WDSIZE // загружаем A[row, i] и увеличиваем адрес в X12 на #WDSIZE байт LDR W10, [X6], #(N*WDSIZE) // загружаем в W10 данные из B[i, col] SMADDL X7, W9, W10, X7 // умножаем и сохраняем результат в X7 SUBS W0, W0, #1 // уменьшаем счетчик на 1 B. NE dotloop // если W0 не равно 0, то переходим к dotloop для перемножения новых элементов матриц
Для перемножения в W9 загружаем элемент по адресу X12, при этом увеличиваем данный адрес на #WDSIZE (4) байт, то есть адрес будет указываать на следующий элемент текущей строки матрицы А. Аналогично в W10 загружаем элемент по адресу X6, при этом увеличиваем данный адрес на #(N*WDSIZE) (12) байт, то есть адрес будет указываать на следующий элемент текущего столба матрицы В. Инструкция SMADDL перемножает значения W9 и W10 и прибавляет к содержимому в регистре X7. И пока не пройдем по всем 3 элементам текущих строки и столбца, продолжаем данные действия.
Таким образом, в цикле dotloop
пройдем по 3 ячейкам текущих строки и столбца, получим результ и сохраним его в регистр X12.
Далее для вычисления элемента матрицы C в следующем столбце переходим к следующему столбцу матрицы B:
STR W7, [X19], #4 // сохраняем результат из W7 в X19 - C[row, col] = W7, увеличиваем адрес в X19 на 4 байта ADD X5, X5, #WDSIZE // Переходим к следующему столбцу в матрице B - увеличиваем адрес в X5 на #WDSIZE байт SUBS W2, W2, #1 // увеличиваем счетчик столбцов B. NE colloop // если не все столбцы прошли, то переходим обратно к colloop
При этом полученный результат из X7 сохраняем в текущей элемент матрицы С, адрес которого хранится в Х19. При этом данный адрес увеличиваем на 4 байта, чтобы в следующий раз сохранить значение для следующего элемента матрицы С. Также увеличиваем адрес в X5 на #WDSIZE байт, то есть переходим к новому столбцу матрицы В и уменьшаем счетчик столбцов в регистре W2.
Если все столбцы матрицы В пройдены, то переходим к новой строке матрицы А:
ADD X4, X4, #(N*WDSIZE) // к адресу в X4 прибавляем #(N*WDSIZE) байт для перехода к адресу новой строки SUBS W1, W1, #1 // уменьшаем счетчик строк B.NE rowloop // если еще есть строки, переходим обратно к rowloop
Для этого изменяем адрес в Х4 на #(N*WDSIZE) байт (по сути на 12 байт — размер строки), уменьшаем счетчик строк в W1 и переходим к следующей строке.
Если все строки перебраны, то переходим к печати на консоль — проходим по трем строкам матрицы С и единосременно с помощью строки форматирования prtstr
выводим значения трех столбцов текущей строки матрицы C.
Поскольку в данном случае используется функция языка С, скомпилируем приложение с помощью следующей команды:
aarch64-none-linux-gnu-gcc main.s -o main -static
После запуска программа отобразит нам результирующую матрицу:
30 24 18 84 69 54 138 114 90
НазадСодержаниеВперед
3 способа умножения матриц в Python
Бала Прия С в Разработка | Последнее обновление: 1 июля 2022 г.
Поделись на:
Сканер безопасности веб-приложений Invicti — единственное решение, обеспечивающее автоматическую проверку уязвимостей с помощью Proof-Based Scanning™.
В этом уроке вы узнаете, как умножить две матрицы на Питоне.
Вы начнете с изучения условия правильного умножения матриц и напишете пользовательскую функцию Python для умножения матриц. Далее вы увидите, как можно добиться того же результата, используя вложенные генераторы списков.
Наконец, вы приступите к использованию NumPy и его встроенных функций для более эффективного выполнения матричного умножения.
Как проверить правильность умножения матриц
Прежде чем писать код Python для умножения матриц, давайте вернемся к основам умножения матриц.
Матрица Умножение двух матриц A и B допустимо, только если количество столбцов в матрице A равно , равному количеству строк в матрице B .
Вероятно, вы уже сталкивались с этим условием умножения матриц раньше. Однако задумывались ли вы когда-нибудь, почему это так?
Ну, это из-за того, как работает умножение матриц. Взгляните на изображение ниже.
В нашем общем примере матрица A имеет м рядов и n столбцов. А матрица B имеет n строк и p столбцов.
Какова форма матрицы продуктов?
Элемент с индексом (i, j) результирующей матрицы C является скалярным произведением строки i матрицы A и столбца j матрицы B.
Итак, чтобы получить элемент с определенным индексом в результирующей матрице C вам нужно будет вычислить скалярное произведение соответствующей строки и столбца в матрицах A и B соответственно.
Повторяя вышеописанный процесс, вы получите матрицу произведения C формы m x p — с m строками и p столбцами, как показано ниже.
А скалярное произведение или скалярное произведение между двумя векторами a и b задается следующим уравнением.
Подведем итоги:
- Очевидно, что скалярное произведение определяется только между векторами одинаковой длины.
- Таким образом, чтобы скалярное произведение между строкой и столбцом было действительным — при умножении двух матриц — вам нужно, чтобы они обе имели одинаковое количество элементов.
- В приведенном выше общем примере каждая строка в матрице A содержит n элементов. И каждый столбец в матрице B также имеет n элементов.
Если присмотреться, то n — это количество столбцов в матрице A, а также количество строк в матрице B. И именно поэтому вам нужно количество столбцов в матрице A должно быть равным числу строк в матрице B .
Надеюсь, вы понимаете условие выполнения матричного умножения и то, как получить каждый элемент в матрице произведения.
Давайте продолжим писать код Python для умножения двух матриц.
Напишите пользовательскую функцию Python для умножения матриц
В качестве первого шага давайте напишем пользовательскую функцию для умножения матриц.
Эта функция должна выполнять следующие действия:
- Принимать две матрицы, A и B, в качестве входных данных.
- Проверить правильность умножения матриц между A и B.
- Если верно, перемножьте две матрицы A и B и верните матрицу произведения C.
- В противном случае верните сообщение об ошибке, что матрицы A и B нельзя перемножить.
Шаг 1 : Создайте две матрицы целых чисел, используя функцию NumPy random.randint()
. Вы также можете объявить матрицы как вложенные списки Python.
импортировать numpy как np np.random.seed (27) A = np.random.randint (1,10, размер = (3,3)) B = np.random.randint (1,10, размер = (3,2)) print(f"Матрица A:\n {A}\n") print(f"Матрица B:\n {B}\n") # Выход Матрица А: [[4 99] [9 1 6] [9 2 3]] Матрица Б: [[2 2] [5 7] [4 4]]
Шаг 2: Идем дальше и определяем функцию multiple_matrix(A,B)
. Эта функция принимает две матрицы A
и B
в качестве входных данных и возвращает матрицу произведения C
, если умножение матриц допустимо.
по умножению_матрицы (A, B): глобальный C если A.shape[1] == B.shape[0]: C = np.zeros((A.shape[0],B.shape[1]),dtype = int) для строки в диапазоне (строки): для столбца в диапазоне (столбцы): для elt в диапазоне (len (B)): C[строка, столбец] += A[строка, элт] * B[элт, колонка] вернуть С еще: return "Извините, я не могу умножить A и B. "
Разбор определения функции
Перейдем к разбору определения функции.
Объявить C как глобальную переменную : По умолчанию все переменные внутри функции Python имеют локальную область видимости. И вы не можете получить к ним доступ извне функции. Чтобы сделать матрицу продукта C доступной извне, нам придется объявить ее как глобальную переменную. Просто добавьте глобальный квалификатор
перед именем переменной.
Проверка правильности умножения матриц: Используйте атрибут формы
, чтобы проверить, можно ли умножить A и B. Для любого массива arr
, arr.shape[0]
и arr.shape[1]
укажите количество строк, и столбцов, соответственно. Таким образом, if A.shape[1] == B.shape[0]
проверяет правильность умножения матриц. Только если это условие равно True
, будет вычислена матрица произведения. В противном случае функция возвращает сообщение об ошибке.
Использовать вложенные циклы для вычисления значений: Чтобы вычислить элементы результирующей матрицы, мы должны перебрать строки матрицы A, и внешний цикл for
делает это. Внутренний цикл for
помогает нам пройти через столбец матрицы B. А самый внутренний цикл for
помогает получить доступ к каждому элементу в выбранном столбце.
▶️ Теперь, когда мы узнали, как работает функция Python для умножения матриц, давайте вызовем функцию с матрицами A и B, которые мы сгенерировали ранее.
умножить_матрицу (А, В) # Выход массив([[ 89, 107], [47, 49], [ 40, 44]])
Поскольку умножение матриц между A и B допустимо, функция multi_matrix()
возвращает матрицу произведения C.
Использование понимания вложенных списков Python для умножения матриц написал функцию Python для умножения матриц. Теперь вы увидите, как можно использовать вложенные списки, чтобы сделать то же самое.
Вот понимание вложенного списка для умножения матриц.
Сначала это может показаться сложным. Но мы будем шаг за шагом разбирать понимание вложенного списка.
Давайте сосредоточимся на анализе одного списка и определим, что он делает.
Мы будем использовать следующий общий шаблон для понимания списка:
[для - в
] где, : что вы хотите сделать — выражение или операцию - : каждый элемент, над которым вы хотите выполнить операцию.
: итерируемый объект (список, кортеж и т. д.), который вы просматриваете в цикле
▶️ Ознакомьтесь с нашим руководством «Понимание списков в Python — с примерами», чтобы получить более глубокое понимание.
Прежде чем продолжить, обратите внимание, что мы хотели бы построить результирующую матрицу C по одной строке за раз.
Объяснение понимания вложенного списка
Шаг 1: Вычисление одного значения в матрице C
Для заданной строки i матрицы A и столбца j матрицы B приведенное ниже выражение дает запись с индексом (i, j) в матрице C.
сумма(a*b для a,b в zip(A_row, B_col) # zip(A_row, B_col) возвращает итератор кортежей # Если A_row = [a1, a2, a3] и B_col = [b1, b2, b3] # zip(A_row, B_col) возвращает (a1, b1), (a2, b2) и т. д.
Если i = j = 1
, выражение вернет запись c_11
матрицы C. Таким образом, вы можете получить один элемент в одной строке таким образом.
Шаг 2: Построить одну строку в матрице C
Наша следующая цель — построить всю строку.
Для строки 1 в матрице A вам нужно перебрать все столбцы в матрице B, чтобы получить одну полную строку в матрице C.
Вернуться к шаблону понимания списка.
- Заменить
<сделать это>
с выражением из шага 1, потому что это то, что вы хотите сделать. - Затем замените
B_col
— каждый столбец в матрице B. - Наконец, замените
zip(*B)
— список, содержащий все столбцы в матрице B.
А вот и первое понимание списка.
[сумма (a * b для a, b в zip (A_row, B_col)) для B_col в zip (* B)] # zip(*B): * оператор распаковки # zip(*B) возвращает список столбцов матрицы B
Шаг 3: Постройте все строки и получите матрицу C
Далее вам нужно будет заполнить матрицу произведения C, вычислив остальные строки.
А для этого нужно перебрать все строки в матрице A.
Еще раз вернуться к пониманию списка и сделать следующее.
- Замените
- Теперь замените
A_row
— каждая строка в матрице A. - И ваш
И вот наше окончательное понимание вложенного списка. for A_row in A]
Пришло время проверить результат! ✔
# преобразование в com/numpy-reshape-arrays-in-python/">массив NumPy с помощью np.array() C = np.array([[sum(a*b для a,b в zip(A_row, B_col)) для B_col в zip(*B)] для A_row в A]) # Выход: [[ 89107] [ 47 49] [ 40 44]]
Если вы присмотритесь, это эквивалентно вложенным циклам for, которые мы использовали ранее, только более лаконично.
Вы также можете сделать это более эффективно, используя некоторые встроенные функции. Давайте узнаем о них в следующем разделе.
Использование NumPy matmul() для умножения матриц в Python
np.matmul()
принимает две матрицы в качестве входных данных и возвращает произведение, если умножение матриц между входными матрицами равно действительный .
C = np.matmul(A,B) печать(С) # Выход: [[ 89 107] [ 47 49] [ 40 44]]
Обратите внимание, насколько этот метод проще, чем два метода, которые мы изучали ранее. На самом деле вместо np.matmul()
можно использовать эквивалентный оператор @, и мы сразу это увидим.
Как использовать оператор @ в Python для умножения матриц
В Python @
— это бинарный оператор, используемый для умножения матриц.
Он работает с двумя матрицами и, как правило, с N-мерными массивами NumPy и возвращает матрицу произведения.
Примечание: Для использования оператора
@
у вас должен быть Python 3.5 или более поздней версии.
Вот как вы можете его использовать.
С = А@В печать(С) # Выход массив([[ 89, 107], [47, 49], [ 40, 44]])
Обратите внимание, что матрица произведения C такая же, как та, которую мы получили ранее.
Можно ли использовать np.dot() для умножения матриц?
Если вы когда-либо сталкивались с кодом, который использует np.dot()
для умножения двух матриц, вот как это работает.
C = np.dot(A,B) печать(С) # Выход: [[ 89 107] [ 47 49] [ 40 44]]
Вы увидите, что np. dot(A, B)
также возвращает ожидаемую матрицу продукта.
Однако, согласно документам NumPy, вы должны использовать np.dot()
только для вычисления скалярного произведения двух одномерных векторов, а не для умножения матриц.
Напомним из предыдущего раздела, что элемент с индексом (i, j) матрицы произведения C является скалярным произведением строки i матрицы A и столбца j матрицы B.
Поскольку NumPy неявно передает эту операцию скалярного произведения всем строкам и всем столбцам, вы получаете результирующую матрицу произведения. Но чтобы ваш код был читабельным и чтобы избежать двусмысленности, используйте вместо этого np.matmul()
или оператор @
.
Заключение
🎯 В этом уроке вы узнали следующее.
- Условие правильности умножения матриц: количество столбцов в матрице A = количество строк в матрице B .
- Как написать пользовательскую функцию Python, которая проверяет правильность умножения матриц и возвращает матрицу произведения. В теле функции используются вложенные циклы for.
- Далее вы узнали, как использовать вложенные списки для умножения матриц. Они более лаконичны, чем циклы for, но подвержены проблемам с читабельностью.
- Наконец, вы узнали, как использовать встроенную функцию NumPy np.matmul() для умножения матриц и как это наиболее эффективно с точки зрения скорости.
- Вы также узнали об операторе @ для умножения двух матриц в Python.
На этом мы завершаем обсуждение умножения матриц в Python. В качестве следующего шага узнайте, как проверить, является ли число простым в Python. Или решить интересные задачи на строки Python.
Приятного обучения!🎉
Спасибо нашим спонсорам
Более 20 примеров для умножения матриц NumPy
В этом уроке мы рассмотрим различные способы выполнения умножения матриц с использованием массивов NumPy. Мы научимся перемножать матрицы разных размеров вместе.
Также мы узнаем, как ускорить процесс умножения с помощью графического процессора и другие горячие темы, так что давайте начнем!
Прежде чем мы двинемся дальше, лучше рассмотреть некоторые основные термины матричной алгебры.
Основные термины
Вектор: Алгебраически вектор представляет собой набор координат точки в пространстве.
Таким образом, вектор с двумя значениями представляет собой точку в двумерном пространстве. В информатике вектор — это расположение чисел в одном измерении. Он также широко известен как массив, список или кортеж.
Напр. [1,2,3,4]
Матрица: Матрица (множественное число матриц) представляет собой двумерное расположение чисел или набор векторов.
Пример:
[[1,2,3], [4,5,6], [7,8,9]]
Скалярное произведение: Скалярное произведение – это математическая операция между 2 векторами одинаковой длины .
Равен сумме произведений соответствующих элементов векторов.
С четким пониманием этих терминов мы готовы к работе.
Умножение матриц на вектор
Начнем с простой формы умножения матриц — между матрицей и вектором.
Прежде чем мы продолжим, давайте сначала поймем, как создать матрицу с помощью NumPy.
Метод array() NumPy используется для представления векторов, матриц и многомерных тензоров. Давайте определим 5-мерный вектор и матрицу 3 × 3, используя NumPy.
импортировать numpy как np а = np.массив ([1, 3, 5, 7, 9]) б = np.массив([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) print("Вектор a:\n", a) Распечатать() print("Matrix b:\n", b)
Вывод:
Давайте теперь посмотрим, как происходит умножение между матрицей и вектором.
При умножении матрицы на вектор следует помнить о следующих моментах:
- Результатом умножения матрицы на вектор является вектор.
- Каждый элемент этого вектора получается путем скалярного произведения между каждой строкой матрицы и умножаемым вектором.
- Количество столбцов в матрице должно быть равно количеству элементов в векторе.
Мы будем использовать метод NumPy matmul() для большинства наших операций умножения матриц.
Давайте определим матрицу 3×3 и умножим ее на вектор длины 3.
импортировать numpy как np а = np.массив([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) б = np.массив ([10, 20, 30]) печать("А=", а) печать("б =", б) печать ("Ab =", np.matmul (а, б))
Вывод:
Обратите внимание, что результатом является вектор длины, равной строкам матрицы множителей.
Умножение на другую матрицу
Теперь мы поняли умножение матрицы на вектор; было бы легко вычислить умножение двух матриц.
Но перед этим повторим самые важные правила умножения матриц:
- Количество столбцов в первой матрице должно быть равно количеству строк во второй матрице.
- Если мы умножаем матрицу размеров m x n на другую матрицу размеров n x p, то результатом будет матрица размеров m x p.
Рассмотрим умножение m x n матрицы A на n x p матрицу B:
Произведение двух матриц C = AB будет иметь m строк и p столбцов.
Каждый элемент в матрице произведения C является результатом скалярного произведения между вектором-строкой в A и вектором-столбцом в B.
Теперь давайте выполним матричное умножение двух матриц в Python, используя NumPy.
Мы случайным образом сгенерируем две матрицы размеров 3 x 2 и 2 x 4.
Мы будем использовать метод np.random.randint() для генерации чисел.
импортировать numpy как np np.random.seed (42) A = np.random.randint (0, 15, размер = (3,2)) B = np.random.randint (0, 15, размер = (2,4)) print("Матрица А:\n", А) print("форма A =", A.shape) Распечатать() print("Матрица B:\n", B) print("shape of B =", B.shape)
Вывод:
Примечание: мы устанавливаем случайное начальное число, используя ‘np. random.seed()’, чтобы сделать генератор случайных чисел детерминированным.
При каждом запуске этого фрагмента кода будут генерироваться одни и те же случайные числа. Этот шаг необходим, если вы хотите воспроизвести результат позже.
Вы можете установить любое другое целое число в качестве начального числа, но я предлагаю установить его на 42 для этого урока, чтобы ваши выходные данные соответствовали показанным на выходных снимках экрана.
Теперь умножим две матрицы, используя Метод np.matmul() . Результирующая матрица должна иметь форму 3 x 4.
C = np.matmul(A, B) print("произведение A и B:\n", C) print("shape of product =", C.shape)
Вывод:
Умножение между 3 матрицами
Умножение трех матриц будет состоять из двух операций умножения 2 матриц, и каждая из двух операций будут следовать тем же правилам, которые обсуждались в предыдущем разделе.
Допустим, мы перемножаем три матрицы A, B и C, и произведение равно D = ABC.
Здесь количество столбцов в A должно быть равно количеству строк в B, а количество строк в C должно быть равно количеству столбцов в B.
Полученная матрица будет иметь строк, равных количеству строк в A и столбцов равно количеству столбцов в C.
Важным свойством операции умножения матриц является то, что является ассоциативным .
При мультиматричном умножении порядок отдельных операций умножения не имеет значения и, следовательно, не дает разных результатов.
Например, в нашем примере умножения трех матриц D = ABC не имеет значения, выполняем ли мы сначала AB или BC.
Оба порядка дадут один и тот же результат. Давайте сделаем пример на Python.
импортировать numpy как np np.random.seed (42) A = np.random.randint (0, 10, размер = (2,2)) B = np.random.randint (0, 10, размер = (2,3)) C = np.random.randint (0, 10, размер = (3,3)) print("Матрица A:\n{}, shape={}\n".format(A, A.shape)) print("Матрица B:\n{}, shape={}\n". format(B, B.shape)) print("Матрица C:\n{}, shape={}\n".format(C, C.shape))
Результат:
На основании правил, которые мы обсуждали выше, умножение этих трех матриц должно дать результирующую матрицу формы (2, 3).
Обратите внимание, что метод np.matmul() принимает только две матрицы в качестве входных данных для умножения, поэтому мы будем вызывать метод дважды в том порядке, в котором мы хотим умножать, и передавать результат первого вызова в качестве параметра в второй.
(Мы найдем лучший способ решения этой проблемы в следующем разделе, когда мы введем оператор @)
Выполним умножение в обоих порядках и проверим свойство ассоциативности.
D = np.matmul(np.matmul(A,B),C) print("Результат умножения в порядке (AB)C:\n\n{},shape={}\n".format(D, D.shape)) D = np.matmul(A, np.matmul(B,C)) print("Результат умножения в порядке A(BC):\n\n{},shape={}".format(D, D.shape))
Вывод:
Как мы видим, Результат умножения трех матриц остается тем же, независимо от того, умножаем ли мы сначала А и В или сначала В и С.
Таким образом, свойство ассоциативности подтверждается.
Кроме того, результирующий массив имеет форму (2, 3), что соответствует ожидаемым строкам.
NumPy Умножение трехмерных матриц
Трехмерная матрица — это не что иное, как набор (или стек) множества двумерных матриц, точно так же, как двумерная матрица представляет собой набор/стек множества одномерных векторов.
Таким образом, матричное умножение трехмерных матриц включает в себя многократное умножение двумерных матриц, что в конечном итоге сводится к скалярному произведению между их векторами строк и столбцов.
Рассмотрим пример матрицы A формы (3,3,2), умноженной на другую трехмерную матрицу B формы (3,2,4).
импортировать numpy как np np.random.seed (42) A = np.random.randint (0, 10, размер = (3,3,2)) B = np.random.randint (0, 10, размер = (3,2,4)) print("A:\n{}, shape={}\nB:\n{}, shape={}".format(A, A.shape,B, B.shape))
Вывод:
Первая матрица представляет собой стопку из трех двумерных матриц, каждая из которых имеет форму (3,2), а вторая матрица представляет собой стопку из трех двумерных матриц, каждая из которых имеет форму (2,4).
Умножение матриц между этими двумя включает три умножения между соответствующими двумерными матрицами A и B, имеющими формы (3,2) и (2,4) соответственно.
В частности, первое умножение будет между A[0] и B[0], второе умножение будет между A[1] и B[1] и, наконец, третье умножение будет между A[2] и БИ 2].
Результат каждого отдельного умножения двумерных матриц будет иметь форму (3,4). Следовательно, конечным продуктом двух трехмерных матриц будет матрица формы (3,3,4).
Давайте реализуем это с помощью кода.
C = np.matmul(A,B) print("Product C:\n{}, shape={}".format(C, C.shape))
Вывод:
Альтернативы np.matmul()
Кроме ‘np.matmul ()’ существует два других способа выполнения матричного умножения — метод np.dot() и оператор ‘@’ , каждый из которых предлагает некоторые различия/гибкость в операциях матричного умножения.
Метод ‘np.dot()’
Вы можете использовать этот метод для нахождения скалярного произведения векторов, но если мы передадим две двумерные матрицы, то он будет вести себя аналогично методу ‘np. matmul()’ и будет возвращать результат матричного умножения две матрицы.
Давайте рассмотрим пример:
импортировать numpy как np # матрица 3x2 A = np.массив([[8, 2, 2], [1, 0, 3]]) # матрица 2x3 B = np.массив([[1, 3], [5, 0], [9, 6]]) # точечный продукт должен возвращать продукт 2x2 С = np.точка (А, В) print("произведение A и B:\n{} shape={}".format(C, C.shape))
Вывод:
Здесь мы определили матрицу 3×2, а матрицу 2×3 и их скалярное произведение дает результат 2×2, который представляет собой матричное умножение двух матриц,
то же самое, что и ‘ np.matmul()’ вернется.
Разница между np.dot() и np.matmul() заключается в их работе с трехмерными матрицами.
В то время как np.matmul() работает с двумя трехмерными матрицами путем вычисления матричного умножения соответствующих пар двумерных матриц (как обсуждалось в последнем разделе), np.dot(), с другой стороны, вычисляет скалярные произведения различных пар векторы-строки и векторы-столбцы из первой и второй матрицы соответственно.
np.dot() для двух трехмерных матриц A и B возвращает произведение суммы по последней оси A и предпоследней оси B.
Это неинтуитивно и нелегко понять .
Итак, если A имеет форму (a, b, c), а B имеет форму (d, c, e), то результат np.dot(A, B) будет иметь форму (a, d, b,e), отдельный элемент которого в позиции (i,j,k,m) определяется как:
dot(A, B)[i,j,k,m] = sum(A[i,j,: ] * B[k,:,m])
Проверим на примере:
импортировать numpy как np np.random.seed (42) A = np.random.randint (0, 10, размер = (2,3,2)) B = np.random.randint (0, 10, размер = (3,2,4)) print("A:\n{}, shape={}\nB:\n{}, shape={}".format(A, A.shape,B, B.shape))
Вывод:
Если теперь мы передадим эти матрицы методу ‘np.dot()’, он вернет матрицу формы (2,3,3,4), отдельные элементы которой вычисляются по приведенной выше формуле.
C = np.dot(A,B) print("np.dot(A,B) =\n{}, shape={}".format(C, C.shape))
Вывод:
Другое важное различие между ‘np. matmul()’ и ‘np.dot()’ состоит в том, что ‘np.matmul()’ не допускает умножения на скаляр (мы обсудим это в следующий раздел), в то время как ‘np.dot()’ разрешает это.
Оператор «@»
Оператор @, представленный в Python 3.5, выполняет ту же операцию, что и «np.matmul()».
Давайте рассмотрим более ранний пример np.matmul() с использованием оператора @ и увидим тот же результат, что и ранее:
импортировать numpy как np np.random.seed (42) A = np.random.randint (0, 15, размер = (3,2)) B = np.random.randint (0, 15, размер = (2,4)) print("Матрица A:\n{}, shape={}".format(A, A.shape)) print("Матрица B:\n{}, shape={}".format(B, B.shape)) С = А @ В print("произведение A и B:\n{}, shape={}".format(C, C.shape))
Вывод:
Оператор ‘@’ становится удобным, когда мы выполняем матричное умножение из более чем двух матриц.
Раньше нам приходилось вызывать np.matmul() несколько раз и передавать их результаты в качестве параметра следующему вызову.
Теперь мы можем выполнить ту же операцию более простым (и более интуитивным) способом:
import numpy as np np.random.seed (42) A = np.random.randint (0, 10, размер = (2,2)) B = np.random.randint (0, 10, размер = (2,3)) C = np.random.randint (0, 10, размер = (3,3)) print("Матрица A:\n{}, shape={}\n".format(A, A.shape)) print("Матрица B:\n{}, shape={}\n".format(B, B.shape)) print("Матрица C:\n{}, shape={}\n".format(C, C.shape)) D = A @ B @ C # раньше np.matmul(np.matmul(A,B),C) print("Продукт ABC:\n\n{}, shape={}\n".format(D, D.shape))
Вывод:
Умножение на скаляр (одно значение)
До сих пор мы выполняли умножение матрицы на вектор или другую матрицу. Но что происходит, когда мы выполняем умножение матриц на скалярное или одно числовое значение?
Результат такой операции получается путем умножения каждого элемента матрицы на скалярное значение. Таким образом, выходная матрица имеет ту же размерность, что и входная матрица.
Обратите внимание, что ‘np.matmul()’ не позволяет умножать матрицу на скаляр. Вы можете добиться этого, используя np.dot() или с помощью оператора ‘*’.
Давайте посмотрим на это на примере кода.
импортировать numpy как np A = np.массив([[1,2,3], [4,5, 6], [7, 8, 9]]) В = А * 10 print("Матрица A:\n{}, shape={}\n".format(A, A.shape)) print("Умножение A на 10:\n{}, shape={}".format(B, B.shape))
Вывод:
Поэлементное матричное умножение
Иногда нам нужно сделать умножение соответствующих элементов двух матриц, имеющих одинаковую форму.
Эта операция также называется продуктом Адамара . Он принимает две матрицы одинакового размера и создает третью матрицу того же размера.
Этого можно добиться, вызвав функцию Multi() NumPy или используя оператор ‘*’ .
импортировать numpy как np np. random.seed (42) A = np.random.randint (0, 10, размер = (3,3)) B = np.random.randint (0, 10, размер = (3,3)) print("Матрица A:\n{}\n".format(A)) печать ("Матрица B:\n{}\n".format(B)) C = np.multiply(A,B) # или A * B print("Поэлементное умножение A и B:\n{}".format(C))
Вывод:
Единственное правило, которое нужно помнить при поэлементном умножении, заключается в том, что две матрицы должны иметь одинаковую форму .
Однако, если одно измерение матрицы отсутствует, NumPy будет транслировать его, чтобы оно соответствовало форме другой матрицы.
На самом деле умножение матриц на скаляр также включает передачу скалярного значения в матрицу формы, равной матричному операнду при умножении.
Это означает, что когда мы умножаем матрицу формы (3,3) на скалярное значение 10, NumPy создаст другую матрицу формы (3,3) с постоянными значениями десять во всех позициях в матрице и выполнит поэлементно умножение двух матриц.
Давайте разберемся с этим на примере:
импортировать numpy как np np.random.seed (42) A = np.random.randint (0, 10, размер = (3,4)) B = np.массив ([[1,2,3,4]]) print("Матрица A:\n{}, shape={}\n".format(A, A.shape)) print("Матрица B:\n{}, shape={}\n".format(B, B.shape)) С = А * В print("Поэлементное умножение A и B:\n{}".format(C))
Вывод:
Обратите внимание, как вторая матрица, имевшая форму (1,4), была преобразована в ( 3,4) матрица через трансляцию, причем поэлементное умножение между двумя матрицами имело место.
Матрица, возведенная в степень (возведение матрицы в степень)
Подобно тому, как мы можем возвести скалярное значение в степень, мы можем проделать ту же операцию с матрицами.
Точно так же, как возведение скалярного значения (основания) в степень n равносильно многократному умножению n оснований, та же закономерность наблюдается при возведении матрицы в степень, которая включает в себя повторяющиеся матричные умножения.
Например, если мы возведем матрицу A в степень n, она будет равна матричному умножению n матриц, каждая из которых будет матрицей A.
Обратите внимание: чтобы эта операция была возможной, базовая матрица должна быть квадратной .
Это делается для того, чтобы количество столбцов в предыдущей матрице было равно количеству строк в следующей матрице.
Эта операция обеспечивается в Python методом linalg.matrix_power() NumPy, который принимает базовую матрицу и целочисленную степень в качестве параметров.
Давайте посмотрим на пример в Python:
импортировать numpy как np np.random.seed (10) A = np.random.randint (0, 10, размер = (3,3)) A_to_power_3 = np.linalg.matrix_power(A, 3) print("Матрица A:\n{}, shape={}\n".format(A, A.shape)) print("A в степени 3:\n{}, shape={}".format(A_to_power_3,A_to_power_3.shape))
Вывод:
Мы можем проверить этот результат, выполнив обычное умножение матриц с тремя операндами (все они A), используя оператор @:
B = A @ A @ A print("B = A @ A @ A :\n{}, shape={}". format(B, B.shape))
Вывод:
Как видите, результаты обеих операций соответствие.
В связи с этой операцией возникает важный вопрос: Что происходит, когда мощность равна 0?
Чтобы ответить на этот вопрос, давайте рассмотрим, что происходит, когда мы возводим скалярную базу в степень 0,9.0423 Получаем значение 1, верно? Теперь, что эквивалентно 1 в матричной алгебре? Вы правильно угадали!
Это матрица идентичности.
Таким образом, возведение матрицы n x n в степень 0 приводит к единичной матрице I формы n x n.
Давайте быстро проверим это на Python, используя нашу предыдущую матрицу A.
C = np.linalg.matrix_power(A, 0) print("A в степени 0:\n{}, shape={}".format(C, C.shape))
Вывод:
Поэлементное возведение в степень
Точно так же, как мы могли бы выполнять поэлементное умножение матриц, мы также можем выполнять поэлементное возведение в степень, т. е. возводить каждый отдельный элемент матрицы в некоторую степень.
Этого можно добиться в Python с помощью стандартного оператора экспоненты ‘ ** ’ — пример оператора, перегружающего .
Опять же, мы можем предоставить одну постоянную степень для всех элементов в матрице или матрицу степеней для каждого элемента в базовой матрице.
Давайте посмотрим на примеры того и другого в Python: 9полномочия:\n{}, shape={}\n».format(C, C.shape))
Вывод:
Умножение определенного индекса
Предположим, у нас есть матрица 5 x 6 A и другую матрицу 3 x 3 B. Очевидно, мы не можем перемножить эти две вместе из-за несоответствия размеров
Но что, если мы хотим умножить подматрицу 3×3 в матрице A на матрицу B, сохраняя при этом другие элементы в A неизменными?
Для лучшего понимания обратитесь к следующему изображению:
Вы можете выполнить эту операцию в Python, используя нарезку матрицы для извлечения подматрицы из A, выполняя умножение на B, а затем записывая результат по соответствующему индексу в A.
Давайте посмотрим это в действии.
импортировать numpy как np np.random.seed (42) A = np.random.randint (0, 10, размер = (5,6)) B = np.random.randint (0, 10, размер = (3,3)) print("Матрица A:\n{}, shape={}\n".format(A, A.shape)) print("Матрица B:\n{}, shape={}\n".format(B, B.shape)) С = А[1:4,2:5] @ В А[1:4,2:5] = С print("Матрица A после умножения подматриц:\n{}, shape={}\n".format(A, A.shape))
Вывод:
Как видите, только элементы с индексами строк с 1 по 3 и индексами столбцов со 2 по 4 были умножены на B, и то же самое было записано обратно в A, в то время как остальные элементы A имеют остался неизменным.
Также нет необходимости перезаписывать исходную матрицу. Мы также можем записать результат в новую матрицу, сначала скопировав исходную матрицу в новую матрицу, а затем записав произведение в позиции подматрицы.
Умножение матриц с использованием графического процессора
Мы знаем, что NumPy ускоряет матричные операции, распараллелив множество вычислений и используя возможности параллельных вычислений нашего ЦП.
Однако современным приложениям нужно нечто большее. ЦП предлагают ограниченные вычислительные возможности, и этого недостаточно для большого количества необходимых нам вычислений, как правило, в таких приложениях, как глубокое обучение.
Именно здесь на сцену выходят графические процессоры. Они предлагают большие вычислительные возможности и превосходную инфраструктуру параллельных вычислений, которая помогает нам сэкономить значительное количество времени, выполняя сотни тысяч операций за доли секунды.
В этом разделе мы рассмотрим, как можно выполнять умножение матриц на графическом процессоре вместо центрального процессора и сэкономить при этом много времени.
NumPy не предлагает функции для умножения матриц на графическом процессоре. Поэтому мы должны установить некоторые дополнительные библиотеки, которые помогут нам достичь нашей цели.
Сначала мы установим библиотеки « scikit-cuda » и « PyCUDA », используя установку pip. Эти библиотеки помогают нам выполнять вычисления на графических процессорах на базе CUDA. Чтобы установить эти библиотеки с вашего терминала, если на вашем компьютере установлен графический процессор.
pip установить pycuda pip install scikit-cuda
Если на вашем компьютере нет графического процессора, вы можете попробовать ноутбуки Google Colab и включить доступ к графическому процессору; это бесплатно для использования. Теперь мы напишем код для генерации двух матриц 1000×1000 и выполнения матричного умножения между ними двумя методами:
Во втором методе мы будем генерировать матрицы на процессоре; затем мы будем хранить их на графическом процессоре (используя PyCUDA’s ‘ gpuarray.to_gpu() ‘метод) перед выполнением умножения между ними. Мы будем использовать модуль « time » для вычисления времени вычислений в обоих случаях.
Использование ЦП
импортировать numpy как np время импорта # генерация матриц 1000 x 1000 np.random.seed (42) x = np.random.randint(0,256, размер=(1000,1000)).astype("float64") y = np.random.randint(0,256, размер=(1000,1000)).astype("float64") # вычисление времени умножения на CPU тик = время.время() г = np.matmul (х, у) ток = время.время() time_taken = toc - тик #время в секундах print("Время, затрачиваемое ЦП (в мс) = {}".format(time_taken*1000))
Вывод:
На некоторых старых аппаратных системах вы можете получить ошибку памяти, но если вам повезет, это будет работать в течение длительного времени (зависит от вашей системы).
Теперь давайте выполним то же самое умножение на графическом процессоре и посмотрим, как отличается время вычислений между ними.
Использование графического процессора
#вычисление времени умножения на графическом процессоре linalg.init() # хранение массивов на GPU x_gpu = gpuarray. to_gpu(x) y_gpu = gpuarray.to_gpu(y) тик = время.время() #выполнение умножения z_gpu = linalg.mdot(x_gpu, y_gpu) ток = время.время() time_taken = toc - тик #время в секундах print("Время, затраченное на GPU (в мс) = {}".format(time_taken*1000))
Вывод:
Как мы видим, выполнение той же операции на GPU дает нам ускорение в 70 раз по сравнению с CPU.
Это все еще было небольшое вычисление. Для крупномасштабных вычислений графические процессоры дают нам ускорение на несколько порядков.
Заключение
В этом уроке мы рассмотрели, как происходит умножение двух матриц, управляющие им правила и как их реализовать в Python.
Мы также рассмотрели различные варианты стандартного умножения матриц (и их реализацию в NumPy), такие как умножение более двух матриц, умножение только на определенный индекс или степень матрицы.
Мы также рассмотрели поэлементные вычисления в матрицах, такие как поэлементное матричное умножение или поэлементное возведение в степень.