Engee 文档
Notebook

单位矩阵

在本脚本中,我们将介绍几种创建单元矩阵的方法,并展示如何比较这些矩阵的内存占用情况。

任务描述

创建一个矩阵,其主对角线上填满单位(其他元素要么为零,要么缺失)。假设这样的矩阵不仅可以是正方形的,最好还是多维的。

使用循环

单位矩阵可以通过循环创建,具体方法如下

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

通过一个短循环

沿着主对角线放置单元可以在压缩循环中完成。

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环境中。

线性代数库:对象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 x 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

线性代数库: 命令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

线性代数库:函数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 直接构建单位稀疏矩阵,具体方法如下:

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