Ассемблер ARM64 | Умножение матриц с помощью сопроцессора Neon
Последнее обновление: 21.01.2023
Умножение матриц является довольно распространенной задачей, которая применяется в самых различных вычислениях. И использование сопроцессора Neon позволяет оптимизировать умножение матриц. Так, матрица размером 3×3 фактически представляет три операции умножения матрицы на вектор:
Ccol1 = A ∗ Bcol1 Ccol2 = A ∗ Bcol2 Ccol3 = A ∗ Bcol3
Если поместить числа a, d и g в отдельные дорожки регистра V сопроцессора Neon, а числа b, e и h в соответствующие дорожки второго регистра, а числа c, f и i в соответствующие дорожки третьего регистра, то можно вычислить столбец результирующей матрицы
Итак, определим в файле main.s следующую программу
// Программа для умножения 2 матриц 3x3 с помощью сопроцессора NEON // // Используемые регистры: // D0 - первый столбец матрицы A // D1 - второй столбец матрицы A // D2 - третий столбец матрицы A // D3 - первый столбец матрицы B // D4 - второй столбец матрицы B // D5 - третий столбец матрицы B // D6 - первый столбец матрицы C // D7 - второй столбец матрицы C // D8 - третий столбец матрицы C .global main main: STP X19, X20, [SP, #-16]! STR LR, [SP, #-16]! // загружаем матрицу A в регистры D0, D1, D2 LDR X0, =A // адрес матрицы A LDP D0, D1, [X0], #16 LDR D2, [X0] // загружаем матрицу B в регистры D3, D4, D5 LDR X0, =B // адрес матрицы B LDP D3, D4, [X0], #16 LDR D5, [X0] // макрос для умножения матриц .macro mulcol ccol bcol MUL \ccol\().4H, V0.4H, \bcol\().4H[0] MLA \ccol\().4H, V1.4H, \bcol\().4H[1] MLA \ccol\().4H, V2.4H, \bcol\().4H[2] .endm mulcol V6, V3 // обрабатываем первый столбец mulcol V7, V4 // обрабатываем второй столбец mulcol V8, V5 // обрабатываем третий столбец LDR X1, =C // адрес матрицы C STP D6, D7, [X1], #16 // сохраняем данные в матрицу С STR D8, [X1] // выводим матрицу C на консоль // проходим по 3 строкам и печатаем за раз числа из трех стоблцов MOV W19, #3 // счетчик 3 строк LDR X20, =C // адрес результирующей матрицы printloop: LDR X0, =prtstr // загружаем строку форматирования // для вывода транспонируем матрицы, перейдя к стандартному расположению по столбцам // прибавляем к адресу 2 для перехода к первому элементу следующей строки // к адресу во второй инструкции ldrh добавляем 6, то есть 2+6=8=размер строки // аналогично в третьей инструкции ldh прибавляем к адресу 2+14=16 байт, что представляет размер 2-й строки LDRH W1, [X20], #2 // первый элемент текущей строки LDRH W2, [X20, #6] // второй элемент текущей строки LDRH W3, [X20, #14] // третий элемент текущей строки BL printf // вызываем функцию printf SUBS W19, W19, #1 // уменьшаем счетчик строк B. NE printloop // пока не напечатаем все строки MOV X0, #0 // код возврата LDR LR, [SP], #16 LDP X19, X20, [SP], #16 RET .data // первая матрица A: .short 1, 4, 7, 0 .short 2, 5, 8, 0 .short 3, 6, 9, 0 // вторая матрица B: .short 9, 6, 3, 0 .short 8, 5, 2, 0 .short 7, 4, 1, 0 //результирующая матрица C: .fill 12, 2, 0 prtstr: .asciz "%3d %3d %3d\n"
Здесь обе матрицы – A и B хранятся в порядке расположения столбцов, а матрица C генерируется также в порядке расположения столбцов, что позволяет упростить вычисления, поскольку так проще загружать данные в регистры NEON. Однако вывода на консоль в цикле данные печатаются в порядке расположения строк.
Основная работа выполняется в макросе. Сначала выполняем скалярное произведение
MUL \ccol\().4H, V0.4H, \bcol\().4H[0]
Данная инструкция после макроподстановок превращается в
MUL V6. 4H, V0.4H, V3.4H[0]
Набор символов \() представляет разделитель между именем параметра и последующими символами. Здесь
после имени параметра макроса
позволяет отделить название параметра от “.4H”, иначе имя параметра будет рассматриваться как “ccol.4H”.
Таким образом, перемножаем каждую дорожку в регистре V0 на число из соответствующей дорожки из регистра V3. Для доступа к значению в определенной дорожке применяются квадратные скобки, в которых указывается номер дорожки:
[номер_дорожки]
Отсчет дорожек начинается с нуля.
Последующие две инструкции макроса выполняют умножени с прибавлением:
MLA \ccol\().4H, V1.4H, \bcol\().4H[1] MLA \ccol\().4H, V2.4H, \bcol\().4H[2]
mulcol V6, V3 // обрабатываем первый столбец mulcol V7, V4 // обрабатываем второй столбец mulcol V8, V5 // обрабатываем третий столбец
Скомпилируем программу с помощью компилятора gcc и запустим на выполнение. В итоге консоль должна вывести матрицу С построчно
30 24 18 84 69 54 138 114 90
НазадСодержаниеВперед
Транспонирование матриц. Умножение матриц.
К оглавлению
I. Транспонирование матриц
Транспонирование матриц – переход от матрицы А к матрице, в которой строки и столбцы поменялись местами с сохранением порядка.
Пример 1. Составить транспонированную матрицу, полученную из А:
Решение: Поменяем местами строки и столбцы, сохраняя порядок:
Примеры для самостоятельного решения:
Составить из исходной матрицы транспонированную матрицу:
II. Умножение матриц
Пример 1. Рассмотрим для начала простейший пример, когда необходимо найти произведение двух матриц А и В размером 2´2, если
Решение:
Элемент матрицы С, стоящий на первой строке, в первом столбце находится как сумма произведений первой строки матрицы А на первый столбец матрицы В.
Элемент матрицы С, стоящий на первой строке, во втором столбце находится как сумма произведений первой строки матрицы А на второй столбец матрицы В.
Элемент матрицы С, стоящий на второй строке, в
Элемент матрицы С, стоящий на второй строке, во втором столбце находится как сумма произведений второй строки матрицы А на второй столбец матрицы В.
Таким образом, мы получили
То есть мы получили, что
Пример 2. Найдем результат произведения двух матриц
Решение:
то есть мы должны получить матрицу размера 3´3.
Пример 3.
Решение:
Пример 4. Найти произведение двух матриц:
Решение: В первом случае найдем произведение:
Во втором случае найдем произведение:
Пример 5. Вычислить значение многочлена от матрицы
Решение. В многочлен подставим вместо
Теперь получим окончательный результат
III. Примеры для самостоятельного решения
I. Найти произведение матриц:
II. Найти значение многочлена от матрицы А
К оглавлению
linear алгебра – Матричное умножение столбцов на строки вместо строк на столбцы
Прежде чем говорить об умножении двух матриц, давайте рассмотрим другой способ интерпретации матрицы $A$. Скажем, у нас есть матрица $A$, как показано ниже, $$ \begin{bmatrix} 1 и 2 и 3 \\ 1 и 1 и 2 \\ 1 и 2 и 3 \\ \end{bmatrix} $$ легко найти, что столбец $\begin{bmatrix} 3 \\ 2 \\ 3 \\\end{bmatrix}$ является линейной комбинацией первых двух столбцов. $$ 1\begin{bmatrix} 1 \\ 1 \\ 1\\\end{bmatrix} + 1\begin{bmatrix} 2 \\ 1 \\ 2\\\end{bmatrix} = \begin{bmatrix} 3 \\ 2 \\ 3 \\\end{bmatrix} $$ И вы можете сказать, что $\begin{bmatrix} 1 \\ 1 \\ 1 \\\end{bmatrix}$ и $\begin{bmatrix} 2 \\ 1 \\ 2 \\\end{bmatrix}$ – две основы для пространства столбца $A$.
Простите, почему вы хотите сначала разложить матрицу $A$ вот так, $$ \begin{bmatrix} 1 и 2 и 3 \\ 1 и 1 и 2 \\ 1 и 2 и 3 \\ \end{bmatrix} = \begin{bmatrix} 1 и 0 и 1 \\ 1 и 0 и 1 \\ 1 и 0 и 1 \\ \end{bmatrix} + \begin{bmatrix} 0 и 2 и 2 \\ 0 и 1 и 1 \\ 0 и 2 и 2 \\ \end{bmatrix} $$ но вы можете, и, в конце концов, это выглядит разумно.
Если рассматривать это уравнение по столбцам, то каждый $column_j$ матрицы $A$ представляет собой сумму соответствующих $column_j$ каждой матрицы в RHS.
Что особенного в каждой матрице RHS, так это то, что каждая из них является матрицей ранга 1, пространство столбцов которой представляет собой строку, на которой лежит каждое основание пространства столбцов $A$. например. $ \begin{bmatrix} 1 и 0 и 1 \\ 1 и 0 и 1 \\ 1 и 0 и 1 \\ \end{bmatrix} $ охватывает только $\begin{bmatrix} 1 \\ 1 \\ 1 \\\end{bmatrix}$. И люди говорят, что матрицы ранга 1 являются строительными блоками любых матриц.
Если теперь вы вернетесь к концепции просмотра $A$ столбца за столбцом, эта декомпозиция на самом деле подчеркивает концепцию линейной комбинации базовых векторов.
Если это имеет смысл, вы можете расширить RHS дальше, $$ \begin{bmatrix} 1 и 2 и 3 \\ 1 и 1 и 2 \\ 1 и 2 и 3 \\ \end{bmatrix} = \begin{bmatrix} 1 \\ 1 \\ 1 \\\end{bmatrix} \begin{bmatrix} 1 & 0 & 1 \\\end{bmatrix} + \begin{bmatrix} 2 \\ 1 \\ 2 \\\end{bmatrix} \begin{bmatrix} 0 & 1 & 1 \\\end{bmatrix} $$ Каждый термин в RHS говорит: возьмите эту базу и сделайте ее «похожей» на матрицу ранга 3.
А можно немного помассировать, а именно придать RHS матричный вид, получится $$ \begin{bmatrix} 1 и 2 и 3 \\ 1 и 1 и 2 \\ 1 и 2 и 3 \\ \end{bmatrix} = \begin{bmatrix} 1 и 2 \\ 1 и 1 \\ 1 и 2 \\ \end{bmatrix} \begin{bmatrix} 1 и 0 и 1 \\ 0 и 1 и 1 \\ \end{bmatrix} $$
Теперь можно забыть о матрице $A$ и представить, что у вас есть всего две матрицы на RHS. Когда вы прочитаете этот текст задом наперед (я имею в виду логически), я надеюсь, что умножение матриц таким способом теперь имеет для вас смысл. Или, если хотите, вы можете начать с двух матриц в вопросе.
линейная алгебра — умножение матриц — произведение [вектора строк или столбцов] и матрицы [Lay P94, Strang P59]
Задавать вопрос
спросил
Изменено 8 лет, 10 месяцев назад
Просмотрено 4к раз 9м}\mathbf{В} \end{matrix}\right]_{m \times p}. \tag{Столбец}$
$1.$ В (Row), как и почему $\mathbf{A}$ может умножаться слева в форму вектор-столбца $\mathbf{B}$ ?
В (Колн), как и почему $\mathbf{B}$ может умножить вправо вектор-строку $\mathbf{A}$ ?
$2.$ Кто-нибудь объяснит, как $\mathbf{A}$ можно переписать как вектор-строку?
- линейная алгебра
- матрицы
$\endgroup$
4
$\begingroup$
Все это матрицы, так что это стандартное умножение матриц. Например,
$$\слева[ \begin{матрица} 1 и 2\\ 3 и 4\\ \end{матрица}\right]\cdot \left[ \begin{матрица} 1 и 2\\ 3 и 4\\ \конец{матрица}\справа] = \слева[ \begin{матрица} \левый[ \begin{матрица} 1 и 2\\ 3 и 4\\ \конец{матрица}\справа]\cdot\слева[ \begin{матрица} 1\\ 3\\ \end{матрица}\right] и \left[ \begin{матрица} 1 и 2\\ 3 и 4\\ \конец{матрица}\справа]\cdot\слева[ \begin{матрица} 2\\ 4\\ \конец{матрица}\справа]\\ \конец{матрица}\справа] = \левый[ \begin{матрица} \левый[ \begin{матрица} 7\\ 15\\ \end{матрица}\right] и \left[ \begin{матрица} 10\\ 22\\ \конец{матрица}\справа]\\ \конец{матрица}\справа] =\слева[ \begin{матрица} 7 и 10\\ 15 и 22\\ \end{matrix}\right]. $$
(Конечно, здесь есть небольшая ошибка в обозначениях; последние две матрицы не совсем одинаковы).
$\endgroup$
3
$\begingroup$
Проверка тривиальна. Но чтобы дать интуитивное объяснение, запомните это:
Левое умножение $B$ на матрицу $A$ эквивалентно выполнению преобразования строки на $B$. Таким образом, мы должны гарантировать, что $B$ содержит достаточно строк для преобразования. Учтите, что матрица на самом деле полилинейна, чтобы получить уравнение $(Row)$. 9TA=\begin{bmatrix} A(j,1) & \cdots & A(j,n) \\ \end{bmatrix}$ выбирает $j$-ю строку матрицы $A$
Затем напишите $\text{ $i$-й столбец AB } = (AB)e_i=A(Be_i)=Ab_i$.
Это означает, что $i$-й столбец таблицы $AB$ получается умножением $A$ слева на $i$-й столбец таблицы $B$.
Таким образом, все остальные столбцы ($\neq i$) столбцов $B$ и $AB$ не затрагиваются.