Что такое матрица в информатике
Содержание урока
Что такое матрицы?
Что такое матрицы?
Такие таблицы называются матрицами или двумерными массивами. Каждый элемент матрицы, в отличие от обычного (линейного) массива, имеет два индекса — номер строки и номер столбца. На рисунке 8.14 серым фоном выделен элемент, находящийся на пересечении второй строки и третьего столбца.
Матрица — это прямоугольная таблица, составленная из элементов одного типа (чисел, строк и т. д.). Каждый элемент матрицы имеет два индекса — номера строки и столбца.
При объявлении матриц указывают два диапазона индексов (для строк и столбцов):
Каждому элементу матрицы можно присвоить любое значение, допустимое для выбранного типа данных. Поскольку индексов два, для заполнения матрицы нужно использовать вложенный цикл. Далее в примерах будем считать, что объявлена матрица из N строк и М столбцов, a i и j — целочисленные переменные, обозначающие индексы строки и столбца. В следующем примере матрица заполняется случайными числами и выводится на экран:
Такой же двойной цикл нужно использовать для перебора всех элементов матрицы. Вот как вычисляется сумма значений всех элементов:
Следующая страница Обработка элементов матрицы
Cкачать материалы урока
Матрицы. Понятие. Применение
Матрица — это набор чисел, записываемый в виде прямоугольной таблицы. Строки и столбцы матрицы можно считать векторами. Матрицы, у которых число строк равно числу столбцов, называют квадратными. Существует особая квадратная матрица I (Identity) — единичная. Она характеризуется тем, что ее диагональные элементы равны единице, а остальные — нулю:
В 3D-графике, матрицы используются для преобразования координат из одной системы координат в другую. Вообще, для преобразования базиса (базис — набор векторов, задающих координатные оси) в трехмерном пространстве вполне хватает матрицы 3х3, однако, для целей 3D-графики этого не всегда достаточно. В частности, перспективное проецирование удобно представить матрицей, но для этого необходима матрица 4х4. Также с этой целью вводятся т.н. однородные координаты, где трехмерной точке (x, y, z) соответствует набор четырех координат (xw, yw, zw, w).
Основные операции
Из операций, определенных над матрицами, мы рассмотрим умножение, транспонирование и, частично, обращение.
Умножение матриц
Определяется произведение матриц так:
Если Aij — элемент матрицы A, стоящий в i-ой строке и j-ом столбце, и C = AB, то
т.е. элементы матрицы C получаются как скалярные произведения строк A на столбцы B.
Зато оно ассоциативно. Проще говоря:
$$(AB)С = A(BC)$$
Умножение любой матрицы на единичную, дает исходную:
$$AI = A$$
Транспонирование матриц
Обращение
Существует обратная к данной матрица далеко не всегда и процесс её нахождения далеко не тривиален. Однако, в 3D графике, напомню, матрицы используются для задания преобразований системы координат (базиса). Базис, заданный тремя взаимно перпендикулярными векторами единичной длины, называется ортонормированным. А у матрицы, задающей преобразование из одного ортонормированного базиса в другой, обратная матрица совпадает с транспонированной:
$$A^ <-1>= A^T$$
Матрицы, обладающие этим свойством, называются ортогональными.
В 3D-графике матрицы поворота ортогональны и их произведение тоже.
Применение матриц
Выше уже было сказано, что в 3D-графике матрицы используются для преобразования координат. С этой целью точка умножается (как однострочная матрица) на соответствующую матрицу преобразования.
Например, для поворота точки относительно оси X и параллельного переноса, ее надо последовательно умножить на матрицу поворота и параллельного переноса (см. следующий раздел). Причем, т.к. произведение матриц не коммутативно, результат зависит от последовательности умножения:
$$PRT \neq PTR$$, т.к.
$$RT \neq TR,$$
где P — точка, R — матрица поворота, T — матрица переноса.
Ассоциативность произведения матриц позволяет не умножать каждую точку на несколько матриц, а сперва перемножить матрицы преобразования и умножать точки уже на результирующую матрицу:
$$PRT = P(RT)$$
Основные матрицы
Здесь приведены наиболее часто используемые в 3D-графике матрицы.
Параллельный перенос точки на вектор (x, y, z):
1 | 0 | 0 | 0 |
0 | 1 | 0 | 0 |
0 | 0 | 1 | 0 |
x | y | z | 1 |
Вращение относительно оси X на угол a:
1 | 0 | 0 | 0 |
0 | cos a | sin a | 0 |
0 | -sin a | cos a | 0 |
0 | 0 | 0 | 1 |
Вращение относительно оси Y на угол a:
cos a | 0 | -sin a | 0 |
0 | 1 | 0 | 0 |
sin a | 0 | cos a | 0 |
0 | 0 | 0 | 1 |
Вращение относительно оси Z на угол a:
cos a | sin a | 0 | 0 |
-sin a | cos a | 0 | 0 |
0 | 0 | 1 | 0 |
0 | 0 | 0 | 1 |
Масштабирование по осям X, Y и Z на x, y и z соответственно:
z | 0 | 0 | 0 |
0 | y | 0 | 0 |
0 | 0 | x | 0 |
0 | 0 | 0 | 1 |
Проективная матрица с вертикальным и горизонтальным углами обзора fovx и fovy соответственно:
ctg fovx/2 | 0 | 0 | 0 |
0 | ctg fovy/2 | 0 | 0 |
0 | 0 | Zf/(Zf — Zn) | 0 |
0 | 0 | -Zn*Zf/(Zf — Zn) | 1 |
где Zn — ближняя z-плоскость. Zf — дальняя z-плоскость.
Полезно знать
В 3D-графике матрицы преобразования координат, в большинстве случаев,
являются композицией (произведением) матриц вращения, масштабирования и
переноса, и имеют следующую структуру:
Rx | Ry | Rz | 0 |
Ux | Uy | Uz | 0 |
Fx | Fy | Fz | 0 |
Tx | Ty | Tz | 1 |
где R — вектор, показывающий направление оси X новой (т.е. задаваемой данной матрицей) системы координат, в координатах исходной. U и F, соответственно, направления осей Y и Z. Модули этих векторов совпадают с масштабированием по соответствующим осям в новой системе. T — вектор переноса, совмещающего начала координат исходной и новой системы. Получается, что подматрица 3х3, состоящая из векторов R, U и F, задает вращение и масштабирование, а четвертая строка отвечает за перенос.
Знакомство с матрицами
Понятие и базовые операции.
Разработчики нейросетей говорят, что все нейросети — это просто бесконечное перемножение матриц. Мы решили разобраться, что это за матрицы и как их перемножать, а для этого пришлось полезть в линейную алгебру. И это оказалось не так сложно, как мы думали:
Вектор — это «кирпичик» линейной алгебры. На его основе мы переходим к понятию матрицы.
Что такое матрица
Если вектор — это строка с числами в определённом порядке, то матрица — это таблица с числами в определённом порядке. Как у любой таблицы, у матрицы есть столбцы и строки. В них сидят какие-то числа. Всё вместе — это математический объект, то есть в каких-то случаях всю эту таблицу можно рассматривать как единое целое и совершать с ним операции.
Матрицы принято обозначать большими буквами латинского алфавита вроде А, В, С, D и так далее.
Числа внутри матрицы называют элементами. Каждый элемент обозначается двумя цифрами: первая цифра указывает на строку, а вторая — на столбец. Это адрес числа внутри матрицы. Например, элемент А₂₃ означает, что нужное число находится во второй строке и третьем столбце. Нумерация элементов нужна для записи формул и устного объяснения того, где находится нужное число в матрице.
В матрице может находиться неограниченное количество строк, столбцов и элементов. Из-за этого матрицы бывают разных видов и могут обладать разными особенностями. Например, если в матрице совпадает число строк и столбцов, то такая матрица называется квадратной.
В этой статье и в следующих материалах мы будем рассматривать разные виды матрицы и постепенно изучим их особенности.
Общая схема матрицы Пример квадратной матрицы с пятью строками и столбцами. Записывается как матрица размера 5×5. В числовой матрице мы не нумеруем элементы — они закрепляются за числами по умолчанию. Например, элементу А₂₃ соответствует число три
Простые операции с матрицами
Вынесение минуса за пределы матрицы. Если внутри матрицы у большинства элементов знак минус, то часто это мешает расчётам или приводит к ошибкам. Чтобы этого избежать, от минуса избавляются. Для этого нужно вынести минус за пределы матрицы и изменить знак всех элементов внутри самой матрицы.
И наоборот: если внутри матрицы у большинства элементов знак минус и перед матрицей стоит минус, то минус можно внести в матрицу.
Выносим минус за пределы матрицы и получаем вместо двадцати одного отрицательного элемента — четыре Перед матрицей минус, и внутри у большинства элементов минус. Вносим минус в матрицу и делаем её удобной для дальнейших вычислений
Умножение матрицы на число. Для умножения матрицы на число достаточно каждый элемент матрицы умножить на это число.
Пример умножения матрицы на число
Транспонирование матрицы. Это операция, которая позже нам понадобится для решения матричных уравнений. Для транспонирования мы берём известную матрицу, меняем в ней местами строки со столбцами и получаем новую матрицу. Как бы поставили матрицу набок.
⚠️ При этом в матрице запрещено в произвольном порядке менять элементы. Зато можно полностью менять местами строки или столбцы. Если мы поменяем местами первую и вторую строку, то это останется прежняя матрица.
Схема транспонирования матриц: первая строка переходит в первый столбец, вторая строка — во второй столбец и так далее в зависимости от количества элементов матрицы Пример транспонирования. Транспонированная матрица обозначается буквой той же матрицы, из которой она получилась + надстрочечный индекс в виде печатной буквы «Т» Матрицу можно перетасовывать, но это нужно делать по правилам. Транспонирование — одно из таких правил
Сложение и вычитание матриц
Если в нескольких матрицах совпадает число строк и столбцов, то мы можем их складывать и вычитать. Для вычислений нам нужно поэлементно сложить или вычесть каждый элемент матриц: первый элемент первой матрицы складываем с первым элементом второй матрицы или вычитаем из него и так далее. В результате получаем новую матрицу.
Пример сложения двух прямоугольных матриц с тремя строками и двумя столбцами Пример вычитания двух матриц
Умножение матриц
Матрицы умножаются по принципу строка на столбец. Мы умножаем первую строку первой матрицы, на первый столбец второй матрицы, складываем результаты и получаем первый элемент новой матрицы. По аналогичной схеме вычисляем все остальные элементы. Звучит запутанно, поэтому идём по шагам:
Если нам нужно найти матрицу в квадрате, то мы умножаем эту матрицу на саму себя. Если нужна матрица в кубе — умножаем её на саму себя три раза и так далее в зависимости от количества степеней. Если в одной из матриц все элементы нули, то она считается нулевой и после умножения на другую матрицу даёт нулевую матрицу — это как нуль умноженный на число всегда даёт нуль.
Формула умножения матриц Пример умножения квадратных матриц размерностью 2×2
Что дальше
В следующий раз продолжим знакомиться с базовыми понятиями, которые нам понадобятся для решения матричных уравнений. А на сегодня Нео свободен 👽
Функциональное программирование на примере работы с матрицами из теории линейной алгебры
Вступление
Определение матрицы и реализация на F#
Прямоугольная таблица чисел, содержащая m строк и n столбцов, называется матрицей размера m x n
Матрицы, как правило, обозначаются прописными буквами латинского алфавита и записываются в виде
Для работы с матрицами в F# создадим запись, основанную на двумерной таблице, которую в дальнейшем будем расширять полезными методами для того, чтобы совершать необходимые математические операции над ней.
Добавим вспомогательный метод для инициализации записи двумерным массивом
Входным аргументом функции будет двумерный массив, а на ее выходе — запись типа Matrix. Ниже приведем пример инициализации записи.
Две матрицы A=(aij) и B=(bij) называются равными, если они совпадают поэлементно, т.е. aij=bij для всех i=1,2. m и j=1,2. n
Для реализации этого правила будем использовать переопределенный оператор == и добавим пару полезных функций, которые также понадобятся нам в дальнейшем.
Давайте подробнее рассмотрим код выше. Как можно заметить, здесь есть три функции. Первая функция sizes возвращает размерность матрицы в виде кортежа. Так как мы работаем только с прямоугольными матрицами, то для получения количества строк мы берем полный срез первой колонки и возвращаем ее длину.
Аналогичным способом работает определение количества колонок — получаем полный срез первой строки и возвращаем ее длину.
Следующая функция isEquallySized сравнивает размерность двух матриц и возвращает true если они равны. Для этого она использует уже готовую функцию sizes и просто сравнивает результаты.
Оператор == для поэлементного сравнения двух матриц кажется сложнее, но сейчас вы увидите, что он также простой.
Перед тем, как сравнивать две матрицы, сравним их размерность. Если они не равны, то нет дальше смысла проводить проверку, так как уже понятно, что и матрицы будут не равны.
Далее, на основе исходных матриц matrix1 и matrix2 мы формируем новую матрицу, заполненную true или false, в зависимости от того, совпадают ли соответствующие ячейки обеих матриц.
Функция Array2D.mapi перебирает все элементы matrix1 и передает в обработчик три параметра
x — индекс строки
y — индекс колонки
v — содержимое ячейки
Содержимое ячейки v мы сравниваем с соответствующей ячейкой matrix2 и если они равны, то пишем true, иначе — false.
Если есть хоть одна ячейка с элементом false, то это означает, что матрицы не равны между собой.
Так как Array2D не содержит в себе методов для фильтрации или поиска, то реализуем это сами. Для этого разложим матрицу в линейный список
И найдем хоть одно несовпадение
Функция Seq.contains вернет true если в разложенном списке будет найдено хоть одно значение false. Поэтому нам нужно инвертировать полученный результат, чтобы оператор == работал так, как мы хотим
Матрица O называется нулевой или нуль-матрицей, если все ее элементы равны нулю.
Пример использования этой функции
Полагаю, что здесь нет ничего сложного, что требует пояснений, поэтому продолжаем.
Матрица, число строк которой равно числу столбцов и равно n, называется квадратной матрицей порядка n
В рамках этого правила мы создадим функцию, которая прямоугольную матрицу трансформирует в квадратную путем отсечения всех элементов, которые не попадают в квадрат.
Комментариев в исходном коде поясняют принцип работы функции, поэтому продолжим.
Квадратная матрица называется треугольной, если все ее элементы ниже главной диагонали равны нулю, т.е. треугольная матрица имеет вид
Ниже приведен код функции, который преобразует исходную матрицу в треугольную. Но в нашей функции мы будем работать с прямоугольной матрицей, то есть она может быть не квадратной. Читатель легко может модифицировать код функции так, чтобы она возвращала квадратную треугольную матрицу, используя функцию, которую мы рассмотрели ранее.
Функция Array2D.mapi преобразовывает исходный двумерный массив в новый при помощи обработчика, который принимает три параметра
x — номер строки
y — номер колонки
v — содержимое ячейки
Здесь мы делаем проверку, находится ли элемент ниже главной диагонали и если да, то заполняем ячейку 0. В противном случае — исходным значение из входной матрицы.
Ниже приведен пример использования этой функции.
Получаем следующий результат
Квадратная матрица называется диагональной, если все ее элементы, расположенные вне главной диагонали, равны нулю
Эта функция очень похожа на предыдущую, отличается только условие проверки. Ниже пример использования
Диагональная матрица является единичной и обозначается E, если все ее элементы, расположенные на главной диагонали, равны единице
Реализация такой матрицы на F# выглядит так
Операции над матрицами при помощи F#
Суммой двух матриц Amn=(aij)и Bmn=(bij)одинаковых размеров называется матрица того же размера A+B=Cmn=(cij), элементы которой равны сумме элементов матриц A и B, расположенных на соответствующих местах
Пример, для заданных матриц A и B находим сумму A+B
Рассмотрим код для сложения двух матриц
Перед тем, как складывать матрицы, нужно убедиться, что их размерность совпадает, в противном случае функция генерирует исключение. Ниже приведем пример использования данной функции
Произведением матрицы A=(aij) на число k называется матрица kA=(kaij) такого же размера, что и матрица A, полученная умножением всех элементов матрицы A на число k
Матрицу -A=(-1)*A будем называть противоположной матрице A. Из этого определения плавно переходим к следующему
Разностью матриц A и B одинаковых размеров называется сумма матрицы A и матрицы, противоположной к B
Две матрицы называются согласованными, если число столбцов первой равны числу строк второй
Проверка согласованности матриц требуется для их перемножения.
Произведением AB согласованных матриц Amn=(aij) и Bnp=(bjk) называется матрица Cmn=(cik), элемент cik которой вычисляется как сумма произведений элементов i-й строки матрицы A и соответствующих элементов k-го столбца матрицы B
Решение по определению произведения матриц
Рассмотрим код для умножения двух матриц
Давайте разберемся с кодом подробнее.
Перед умножением нужно убедиться, что матрицы являются согласованными
Итоговая матрица будет иметь размерность, в которой количество строк такое же, как у первой матрицы и количество столбцов такое же, как у второй матрицы
После этого мы последовательно перебираем все строки и все столбцы исходных матриц
Вычисляем итоговое значение каждой ячейки
Функция List.fold2 на вход получает два списка (строку и колонку) и передает в обработчик следующие параметры
acc — аккумулятор, содержащий результат предыдущего вычисления
val1 — содержимое ячейки из первого массива. В нашем случае это строка из первой матрицы
val2 — содержимое ячейки из второго массива, то есть колонки второй матрицы
Так как матрицы являются согласованными, то мы уверены, что у нас не произойдет выхода за пределы массивов.
Обработчик добавляет к аккумулятору произведение ячеек из строк и столбца и полученное значение будет передано следующей итерации. Таким образом конечным итогом работы функции List.fold2 будет итоговое значение произведений двух матриц. Остается только заполнить им предварительно созданную пустую матрицу
Которая вернется как результат
Ниже приведем пример использования данной функции
Если k ∈ N, то k-й степенью квадратной матрицы Aназывается произведение k матриц A
Рассмотрим код на F# для произведения матрицы в степень. Здесь будет использоваться хвостовая рекурсия для того, чтобы не переполнить стек при больших значениях степеней. Хвостовая рекурсия — это такая рекурсия, которая компилятором в итоге преобразуется в цикл. По возможности рекомендуется всегда использовать именно хвостовую рекурсию вместо обычной, но для этого нужно чтобы каждый кадр рекурсии возвращал итоговое вычисленное значение. Это значение обычно называется аккумулятором и передается в следующий кадр рекурсии. То есть, в отличие от обычной рекурсии, которая возвращает вычисленное значение вверх по стеку, хвостовая рекурсия передает вычисленное значение вниз по стеку. Каждый новый кадр рекурсии делает свои вычисления и добавляет их к уже ранее вычисленному значению, которое хранится в аккумуляторе. После того, как последний кадр рекурсии отработал, в аккумуляторе уже есть вычисленное значение, которое просто возвращается как результат.
Таким образом, компилятор может оптимизировать код и преобразовать его в обычный цикл.
Код содержит подробные комментарии о том, как он работает. Требует небольшого пояснения, зачем используется единичная матрица? Она нужна для первого кадра рекурсии и служит в качестве базового значения аккумулятора, в котором будет накапливаться итоговый результат.
Ниже рассмотрим пример использования нашей функции
Вычислим следующее произведение
Где E — это единичная матрица. Так как мы не можем к матрице прибавить число, то мы должны прибавлять 3E.
Итоги
В этот статье мы рассмотрели примеры реализации и использования матриц из теории линейной алгебры. А также основных математических операций над ними, с использованием функционального подхода на языке F#. Я надеюсь, что читатель смог оценить ту гибкость, которую дают функциональные языки.
Полный исходный код модуля матриц, фрагменты которого были рассмотрены в рамках статьи, вы сможете найти на гитхабе.