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乘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

线性代数库:函数 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]:

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

结论

我们比较了几种创建单位矩阵的方法。 使用标准对象创建的矩阵占用的内存量最少。 I.