Engee documentation
Notebook

The identity matrix

In this script, we will talk about several ways to create unit matrices and show how these matrices can be compared with each other in terms of the memory they occupy.

Task description

Let's create a matrix with the main diagonal filled with ones (the remaining elements are either zero or missing). Assume that such a matrix can be not only square, but ideally also multidimensional.

Using cycles

The identity matrix can be created using loops as follows.

In [ ]:
Pkg.add(["LinearAlgebra"])
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]:

After a short cycle

You can put units along the main diagonal in a compressed cycle.

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]:

Such code can be adapted for the multidimensional case by resorting to the function ndims, which returns the number of dimensions of the original matrix, the main diagonal of which we fill with units.

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

But this custom code will quickly become difficult to maintain if the system requirements grow. It is better to use additional libraries, especially since they are also built into the Engee environment.

LinearAlgebra libraries: object I

The most economical way to create such a matrix is to use the command I.

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

This object takes up very little memory, behaves like a single matrix, it can be multiplied by any objects, and using the command Matrix() translate it into a matrix.

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

Let's create a rectangular matrix of Boolean numbers with units along the main diagonal.:

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

Let's create, for comparison, a 5-by-5 unit matrix.

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 Library: command Diagonal

Another interesting way is provided by the function Diagonal. It can be used to position a vector along the main diagonal of a square matrix. The remaining elements are not stored in memory, the matrix is displayed as a sparse array (SparseArray).

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

LinearAlgebra Library: function diagm

Another function allows you to arrange vectors along any diagonal of the matrix, not just the main one.

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

Visualize this matrix:

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

SparseArrays Library

To construct a single sparse matrix directly using the library SparseArrays it can be done as follows:

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

Such a matrix can also be visualized without any problems.

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

However, as we will see, it takes up more memory than all previous versions.

In [ ]:
varinfo( r"eye_array|eye_I|eye_Diagonal|eye_diagm|eye_spdiagm" )
Out[0]:

varinfo( r"eye_array|eye_I|eye_Diagonal|eye_diagm|eye_spdiagm" )

Conclusion

We compared several ways to create unit matrices. The matrix created using a standard object occupies the least amount of memory. I.