Создание матриц: литералы и генераторы

От ручного перечисления чисел до генераторов нулей, единиц и случайных матриц.

Литерал матрицы — запись в квадратных скобках, где пробел/запятая разделяют элементы строки, а точка с запятой — строки.

Ручная запись

Самый прямой способ — перечислить элементы. Внутри одной строки элементы разделяют пробелом или запятой, строки — точкой с запятой. Все строки обязаны быть одной длины, иначе MATLAB выдаст ошибку о несогласованных размерах.

A = [1 2 3; 4 5 6];   % матрица 2x3
B = [1, 2; 3, 4];     % запятые тоже допустимы

Генераторы стандартных матриц

Руками задавать большие матрицы бессмысленно. Для типовых заготовок есть функции: zeros(m,n) — нули, ones(m,n) — единицы, eye(n) — единичная матрица (диагональ из единиц), rand(m,n) — случайные числа в [0,1), randn — нормальное распределение. Если передать один аргумент n, получится квадратная матрица n×n.

Z = zeros(2,3);   % нули 2x3
O = ones(3);      % единицы 3x3
I = eye(3);       % единичная 3x3
R = rand(2,2);    % случайные [0,1)

Вывод (I):

I =
     1     0     0
     0     1     0
     0     0     1

Сборка из блоков

Матрицы можно склеивать как кирпичи — это называется конкатенацией. Горизонтально — через пробел/запятую, вертикально — через точку с запятой, лишь бы совпадали размеры стыкуемых сторон. Это тот же синтаксис литерала, только вместо чисел — целые матрицы.

a = [1 2];
b = [3 4];
h = [a b];      % 1x4: 1 2 3 4 (по горизонтали)
v = [a; b];     % 2x2 (по вертикали)

Параллель с NumPy

Если вы знаете NumPy, аналогии очевидны: zeros, ones, eye называются так же, а rand похож на numpy.random.rand. Разница в записи литерала: в MATLAB строки разделяют ; прямо в скобках, в NumPy — вложенными списками [[1,2],[3,4]]. И помните: в MATLAB генераторы по умолчанию создают тип double, тогда как в NumPy тип нужно держать в голове.

Как работает под капотом

Функции вроде zeros сразу выделяют непрерывный блок памяти нужного размера. Это даёт важный приём оптимизации — предварительное выделение (preallocation). Если вы собираетесь заполнять матрицу в цикле, сначала создайте её через zeros, а потом записывайте элементы. Иначе при каждом расширении MATLAB вынужден копировать весь массив в новое, большее место памяти — и цикл становится квадратично медленным.

Частые ошибки

  • Строки разной длины в литерале — [1 2; 3 4 5] вызовет ошибку.
  • Конкатенация несовместимых блоков: склеить по вертикали матрицы с разным числом столбцов нельзя.
  • Заполнять растущую матрицу в цикле без preallocation — медленно на больших размерах.

Случайные матрицы и воспроизводимость

Функции rand и randn заслуживают отдельного слова. В научных расчётах случайность нужна постоянно — для имитационного моделирования, инициализации алгоритмов, генерации тестовых данных. Но «случайный» расчёт, который при каждом запуске даёт другой результат, трудно отлаживать и невозможно воспроизвести в отчёте. Поэтому генератор случайных чисел в MATLAB псевдослучаен: им управляет внутреннее состояние, которое можно зафиксировать командой rng(0) (любое число вместо нуля задаёт «зерно»). После этого последовательность rand станет повторяемой — тот же зерно даёт ту же последовательность. Это стандартная практика: ставить rng в начале скрипта, чтобы результаты можно было воспроизвести.

Специальные конструкторы

Помимо базовых генераторов есть удобные специализированные. diag(v) строит матрицу с вектором v на диагонали (а diag(A), наоборот, извлекает диагональ матрицы — функция работает в обе стороны в зависимости от аргумента). repmat(A, m, n) тиражирует блок A в сетку m×n — удобно для построения периодических структур. reshape(A, r, c) переформирует матрицу, не меняя данные, лишь перераспределяя их по новым размерам (помня про column-major порядок). Эти функции вместе с генераторами покрывают почти любую потребность в создании структурированных матриц без единого цикла.

Итоги

  • Литерал: пробел/запятая — элементы строки, ; — новая строка.
  • zeros/ones/eye/rand генерируют типовые матрицы; одиночный аргумент — квадрат.
  • Перед заполнением в цикле выделяйте память заранее через zeros.
Проверьте себя
1. Что создаёт eye(3)?
AМатрицу из троек
BЕдиничную матрицу 3×3 с единицами на диагонали
CВектор [1 2 3]
DМатрицу случайных чисел
2. Зачем нужно preallocation (zeros перед циклом)?
AЧтобы код был короче
BЧтобы избежать копирования массива при каждом расширении
CЭто обязательное требование синтаксиса
DЧтобы матрица стала случайной
3. Как вертикально склеить векторы a=[1 2] и b=[3 4]?
A[a b]
B[a; b]
C[a, b]
Da + b