Документация Engee
Notebook

Единичная матрица

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

Описание задачи

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

При помощи циклов

Единичную матрицу можно создать при помощи циклов следующим образом.

In [ ]:
n = 14
m = 11

eye = zeros( m, n )

for i in 1:n 
    if m < n
        if i <= m
            eye[i,i] = 1
        end
    else
        eye[i,i] = 1
    end
end
In [ ]:
gr()
heatmap( eye, yflip=:true, c=:Reds )
Out[0]:

Через короткий цикл

Проставить единицы вдоль главной диагонали можно в сжатом цикле.

In [ ]:
eye_array = zeros( 5, 5 );

[eye_array[ i,i ] = 1 for i in 1:minimum( size(eye_array) )];

heatmap( eye_array, yflip=:true, c=:Purples )
Out[0]:

Такой код можно адаптировать для многомерного случая, прибегнув к функции ndims, которая возвращает количество измерений исходной матрицы, главную диагональ которой мы наполняем единицами.

In [ ]:
eye3D = zeros(5,4,3)

[eye3D[ repeat( [i], ndims(eye3D) )... ] = 1 for i in 1:minimum( size(eye3D) )];

display( eye3D )
5×4×3 Array{Float64, 3}:
[:, :, 1] =
 1.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0

[:, :, 2] =
 0.0  0.0  0.0  0.0
 0.0  1.0  0.0  0.0
 0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0

[:, :, 3] =
 0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0
 0.0  0.0  1.0  0.0
 0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0

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

Библиотеки LinearAlgebra: объект I

Наиболее экономный способ создания такой матрицы заключается в использовании команды I.

In [ ]:
using LinearAlgebra
I
Out[0]:
UniformScaling{Bool}
true*I

Этот объект занимает очень мало памяти, ведет себя как единичная матрица, его можно домножать на любые объекты, а при помощи команды Matrix() его перевести в матрицу.

In [ ]:
Matrix( 5I, 3, 3)
Out[0]:
3×3 Matrix{Int64}:
 5  0  0
 0  5  0
 0  0  5

Создадим прямоугольную матрицу из чисел булевского типа с единицами по главной диагонали:

In [ ]:
Matrix{Bool}(I, 4, 10)
Out[0]:
4×10 Matrix{Bool}:
 1  0  0  0  0  0  0  0  0  0
 0  1  0  0  0  0  0  0  0  0
 0  0  1  0  0  0  0  0  0  0
 0  0  0  1  0  0  0  0  0  0

Создадим, для сравнения, единичную матрицу размером 5 на 5.

In [ ]:
eye_I = Matrix{Bool}(I, 5, 5)
Out[0]:
5×5 Matrix{Bool}:
 1  0  0  0  0
 0  1  0  0  0
 0  0  1  0  0
 0  0  0  1  0
 0  0  0  0  1

Библиотека LinearAlgebra: команда Diagonal

Еще один интересный способ предоставляет функция Diagonal. С ее помощью можно расположить вектор вдоль главной диагонали квадратной матрицы. Остальные элементы не хранятся в памяти, матрица отображается как разреженный массив (SparseArray).

In [ ]:
using LinearAlgebra
eye_Diagonal = Diagonal( repeat([1], 5) )
Out[0]:
5×5 Diagonal{Int64, Vector{Int64}}:
 1  ⋅  ⋅  ⋅  ⋅
 ⋅  1  ⋅  ⋅  ⋅
 ⋅  ⋅  1  ⋅  ⋅
 ⋅  ⋅  ⋅  1  ⋅
 ⋅  ⋅  ⋅  ⋅  1

Библиотека LinearAlgebra: функция diagm

Еще одна функция позволяет расположить векторы вдоль любой диагонали матрицы, не только главной.

In [ ]:
eye_diagm = diagm( 0 => repeat([1], 5) )
Out[0]:
5×5 Matrix{Int64}:
 1  0  0  0  0
 0  1  0  0  0
 0  0  1  0  0
 0  0  0  1  0
 0  0  0  0  1

Визуализируем эту матрицу:

In [ ]:
heatmap( diagm( 0 => repeat([1], 5), 3=>repeat([1], 5) ), yflip=:true, c=:Blues )
Out[0]:

Библиотека SparseArrays

Построить единичную разреженную матрицу напрямую средствами библиотеки SparseArrays можно следующим образом:

In [ ]:
using SparseArrays: spdiagm
eye_spdiagm = spdiagm(0 => repeat([1], 5))
Out[0]:
5×5 SparseArrays.SparseMatrixCSC{Int64, Int64} with 5 stored entries:
 1  ⋅  ⋅  ⋅  ⋅
 ⋅  1  ⋅  ⋅  ⋅
 ⋅  ⋅  1  ⋅  ⋅
 ⋅  ⋅  ⋅  1  ⋅
 ⋅  ⋅  ⋅  ⋅  1

Такую матрицу тоже можно визуализировать без каких-либо проблем.

In [ ]:
heatmap( eye_spdiagm, yflip=:true, c=:Greens )
Out[0]:

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

In [ ]:
varinfo( r"eye_array|eye_I|eye_Diagonal|eye_diagm|eye_spdiagm" )
Out[0]:
name size summary
eye_Diagonal 88 bytes 5×5 Diagonal{Int64, Vector{Int64}}
eye_I 65 bytes 5×5 Matrix{Bool}
eye_array 240 bytes 5×5 Matrix{Float64}
eye_diagm 240 bytes 5×5 Matrix{Int64}
eye_spdiagm 288 bytes 5×5 SparseArrays.SparseMatrixCSC{Int64, Int64} with 5 stored entries

Заключение

Мы сравнили несколько способов создания единичных матриц. Меньше всего в памяти занимает матрица, созданная с применением стандартного объекта I.