Sparse Arrays
Julia 对稀疏向量和 sparse matrices 在 SparseArrays
标准库模块中提供支持。稀疏数组是指包含足够多零的数组,将它们存储在特殊数据结构中可以节省空间和执行时间,相较于密集数组。
可以在 Noteworthy External Sparse Packages 中找到实现不同稀疏存储类型、多维稀疏数组等的外部包。
Compressed Sparse Column (CSC) Sparse Matrix Storage
在 Julia 中,稀疏矩阵存储在 Compressed Sparse Column (CSC) format 中。Julia 稀疏矩阵的类型为 SparseMatrixCSC{Tv,Ti}
,其中 Tv
是存储值的类型,Ti
是用于存储列指针和行索引的整数类型。SparseMatrixCSC
的内部表示如下:
struct SparseMatrixCSC{Tv,Ti<:Integer} <: AbstractSparseMatrixCSC{Tv,Ti}
m::Int # Number of rows
n::Int # Number of columns
colptr::Vector{Ti} # Column j is in colptr[j]:(colptr[j+1]-1)
rowval::Vector{Ti} # Row indices of stored values
nzval::Vector{Tv} # Stored values, typically nonzeros
end
压缩稀疏列存储使得访问稀疏矩阵列中的元素变得简单快捷,而按行访问稀疏矩阵则明显较慢。在CSC结构中,逐个插入之前未存储的条目等操作往往较慢。这是因为所有在插入点之后的稀疏矩阵元素都必须向后移动一个位置。
所有对稀疏矩阵的操作都经过精心实现,以利用CSC数据结构提高性能,并避免昂贵的操作。
如果您有来自不同应用程序或库的 CSC 格式数据,并希望在 Julia 中导入,请确保使用 1 基索引。每列中的行索引需要排序,如果没有排序,矩阵将显示不正确。如果您的 SparseMatrixCSC
对象包含未排序的行索引,一种快速的排序方法是进行双重转置。由于转置操作是惰性执行的,请复制以实现每次转置的具体化。
在某些应用中,将显式零值存储在 SparseMatrixCSC
中是方便的。这些 是 被 Base
中的函数接受的(但不能保证在变更操作中会被保留)。许多例程将这些显式存储的零视为结构非零。nnz
函数返回稀疏数据结构中显式存储的元素数量,包括非结构零。为了准确计算数值非零的数量,请使用 count(!iszero, x)
,该函数检查稀疏矩阵中每个存储的元素。dropzeros
和就地的 dropzeros!
可用于从稀疏矩阵中移除存储的零。
julia> A = sparse([1, 1, 2, 3], [1, 3, 2, 3], [0, 1, 2, 0])
3×3 SparseMatrixCSC{Int64, Int64} with 4 stored entries:
0 ⋅ 1
⋅ 2 ⋅
⋅ ⋅ 0
julia> dropzeros(A)
3×3 SparseMatrixCSC{Int64, Int64} with 2 stored entries:
⋅ ⋅ 1
⋅ 2 ⋅
⋅ ⋅ ⋅
Sparse Vector Storage
稀疏向量以与稀疏矩阵的压缩稀疏列格式相似的方式存储。在 Julia 中,稀疏向量的类型为 SparseVector{Tv,Ti}
,其中 Tv
是存储值的类型,Ti
是索引的整数类型。内部表示如下:
struct SparseVector{Tv,Ti<:Integer} <: AbstractSparseVector{Tv,Ti}
n::Int # Length of the sparse vector
nzind::Vector{Ti} # Indices of stored values
nzval::Vector{Tv} # Stored values, typically nonzeros
end
关于 SparseMatrixCSC
,SparseVector
类型也可以包含显式存储的零。(参见 Sparse Matrix Storage。)
Sparse Vector and Matrix Constructors
创建稀疏数组的最简单方法是使用一个等同于 zeros
的函数,该函数是 Julia 提供的用于处理密集数组的函数。要生成稀疏数组,您可以使用相同的名称并加上 sp
前缀:
julia> spzeros(3)
3-element SparseVector{Float64, Int64} with 0 stored entries
sparse
函数通常是构造稀疏数组的便捷方法。例如,要构造一个稀疏矩阵,我们可以输入一个行索引向量 I
、一个列索引向量 J
和一个存储值的向量 V
(这也被称为 COO (coordinate) format)。然后,sparse(I,J,V)
构造一个稀疏矩阵,使得 S[I[k], J[k]] = V[k]
。等效的稀疏向量构造函数是 sparsevec
,它接受(行)索引向量 I
和存储值的向量 V
,并构造一个稀疏向量 R
,使得 R[I[k]] = V[k]
。
julia> I = [1, 4, 3, 5]; J = [4, 7, 18, 9]; V = [1, 2, -5, 3];
julia> S = sparse(I,J,V)
5×18 SparseMatrixCSC{Int64, Int64} with 4 stored entries:
⎡⠀⠈⠀⠀⠀⠀⠀⠀⢀⎤
⎣⠀⠀⠀⠂⡀⠀⠀⠀⠀⎦
julia> R = sparsevec(I,V)
5-element SparseVector{Int64, Int64} with 4 stored entries:
[1] = 1
[3] = -5
[4] = 2
[5] = 3
sparse
和 sparsevec
函数的逆是 findnz
,它检索用于创建稀疏数组的输入(包括等于零的存储条目)。 findall(!iszero, x)
返回 x
中非零条目的笛卡尔索引(不包括等于零的存储条目)。
julia> findnz(S)
([1, 4, 5, 3], [4, 7, 9, 18], [1, 2, 3, -5])
julia> findall(!iszero, S)
4-element Vector{CartesianIndex{2}}:
CartesianIndex(1, 4)
CartesianIndex(4, 7)
CartesianIndex(5, 9)
CartesianIndex(3, 18)
julia> findnz(R)
([1, 3, 4, 5], [1, -5, 2, 3])
julia> findall(!iszero, R)
4-element Vector{Int64}:
1
3
4
5
另一种创建稀疏数组的方法是使用 sparse
函数将密集数组转换为稀疏数组:
julia> sparse(Matrix(1.0I, 5, 5))
5×5 SparseMatrixCSC{Float64, Int64} with 5 stored entries:
1.0 ⋅ ⋅ ⋅ ⋅
⋅ 1.0 ⋅ ⋅ ⋅
⋅ ⋅ 1.0 ⋅ ⋅
⋅ ⋅ ⋅ 1.0 ⋅
⋅ ⋅ ⋅ ⋅ 1.0
julia> sparse([1.0, 0.0, 1.0])
3-element SparseVector{Float64, Int64} with 2 stored entries:
[1] = 1.0
[3] = 1.0
您可以使用 Array
构造函数朝另一个方向前进。issparse
函数可用于查询矩阵是否稀疏。
julia> issparse(spzeros(5))
true
Sparse matrix operations
稀疏矩阵上的算术运算与密集矩阵上的运算相同。稀疏矩阵的索引、赋值和连接的方式与密集矩阵相同。索引操作,特别是赋值,在逐个元素执行时是昂贵的。在许多情况下,将稀疏矩阵转换为 (I,J,V)
格式可能更好,使用 findnz
,在密集向量 (I,J,V)
中操作值或结构,然后重建稀疏矩阵。
Correspondence of dense and sparse methods
下表给出了稀疏矩阵上的内置方法与其对应的密集矩阵类型的方法之间的对应关系。一般来说,生成稀疏矩阵的方法与其密集对应物的不同之处在于,生成的矩阵遵循给定稀疏矩阵 S
的相同稀疏模式,或者生成的稀疏矩阵具有密度 d
,即每个矩阵元素有概率 d
为非零。
详细信息可以在标准库参考的 Sparse Vectors and Matrices 部分找到。
Sparse | Dense | Description |
---|---|---|
spzeros(m,n) | zeros(m,n) | Creates a m-by-n matrix of zeros. (spzeros(m,n) is empty.) |
sparse(I,n,n) | Matrix(I,n,n) | Creates a n-by-n identity matrix. |
sparse(A) | Array(S) | Interconverts between dense and sparse formats. |
sprand(m,n,d) | rand(m,n) | Creates a m-by-n random matrix (of density d) with iid non-zero elements distributed uniformly on the half-open interval $[0, 1)$. |
sprandn(m,n,d) | randn(m,n) | Creates a m-by-n random matrix (of density d) with iid non-zero elements distributed according to the standard normal (Gaussian) distribution. |
sprandn(rng,m,n,d) | randn(rng,m,n) | Creates a m-by-n random matrix (of density d) with iid non-zero elements generated with the rng random number generator |
Sparse Linear Algebra
稀疏矩阵求解器调用来自 SuiteSparse 的函数。以下分解可用:
Type | Description |
---|---|
CHOLMOD.Factor | Cholesky and LDLt factorizations |
UMFPACK.UmfpackLU | LU factorization |
SPQR.QRSparse | QR factorization |
这些因式分解在 Sparse Linear Algebra API section 中有更详细的描述:
SparseArrays API
SparseArrays.AbstractSparseArray
— TypeAbstractSparseArray{Tv,Ti,N}
N
维稀疏数组(或类似数组类型)的超类型,元素类型为Tv
,索引类型为Ti
。SparseMatrixCSC
、SparseVector
和SuiteSparse.CHOLMOD.Sparse
是其子类型。
SparseArrays.AbstractSparseVector
— TypeAbstractSparseVector{Tv,Ti}
一维稀疏数组(或类似数组类型)的超类型,元素类型为 Tv
,索引类型为 Ti
。是 AbstractSparseArray{Tv,Ti,1}
的别名。
SparseArrays.AbstractSparseMatrix
— TypeAbstractSparseMatrix{Tv,Ti}
二维稀疏数组(或类似数组类型)的超类型,元素类型为 Tv
,索引类型为 Ti
。是 AbstractSparseArray{Tv,Ti,2}
的别名。
SparseArrays.SparseVector
— TypeSparseVector{Tv,Ti<:Integer} <: AbstractSparseVector{Tv,Ti}
用于存储稀疏向量的向量类型。可以通过传递向量的长度、一个已排序的非零索引向量和一个非零值向量来创建。
例如,向量 [5, 6, 0, 7]
可以表示为
SparseVector(4, [1, 2, 4], [5, 6, 7])
这表示索引 1 的元素是 5,索引 2 的元素是 6,索引 3 的元素是 zero(Int)
,索引 4 的元素是 7。
直接从稠密向量创建稀疏向量可能更方便,使用 sparse
如下
sparse([5, 6, 0, 7])
也会产生相同的稀疏向量。
SparseArrays.SparseMatrixCSC
— TypeSparseMatrixCSC{Tv,Ti<:Integer} <: AbstractSparseMatrixCSC{Tv,Ti}
用于以压缩稀疏列格式存储稀疏矩阵的矩阵类型。构造SparseMatrixCSC的标准方法是通过sparse
函数。另请参见spzeros
、spdiagm
和sprand
。
SparseArrays.sparse
— Functionsparse(A)
将抽象矩阵 A
转换为稀疏矩阵。
示例
julia> A = Matrix(1.0I, 3, 3)
3×3 Matrix{Float64}:
1.0 0.0 0.0
0.0 1.0 0.0
0.0 0.0 1.0
julia> sparse(A)
3×3 SparseMatrixCSC{Float64, Int64} with 3 stored entries:
1.0 ⋅ ⋅
⋅ 1.0 ⋅
⋅ ⋅ 1.0
sparse(I, J, V,[ m, n, combine])
创建一个维度为 m x n
的稀疏矩阵 S
,使得 S[I[k], J[k]] = V[k]
。combine
函数用于合并重复项。如果未指定 m
和 n
,则它们分别设置为 maximum(I)
和 maximum(J)
。如果未提供 combine
函数,则 combine
默认为 +
,除非 V
的元素为布尔值,此时 combine
默认为 |
。所有的 I
元素必须满足 1 <= I[k] <= m
,所有的 J
元素必须满足 1 <= J[k] <= n
。在 (I
, J
, V
) 中的数值零被保留为结构非零;要删除数值零,请使用 dropzeros!
。
有关更多文档和专家驱动程序,请参见 SparseArrays.sparse!
。
示例
julia> Is = [1; 2; 3];
julia> Js = [1; 2; 3];
julia> Vs = [1; 2; 3];
julia> sparse(Is, Js, Vs)
3×3 SparseMatrixCSC{Int64, Int64} with 3 stored entries:
1 ⋅ ⋅
⋅ 2 ⋅
⋅ ⋅ 3
SparseArrays.sparse!
— Functionsparse!(I::AbstractVector{Ti}, J::AbstractVector{Ti}, V::AbstractVector{Tv},
m::Integer, n::Integer, combine, klasttouch::Vector{Ti},
csrrowptr::Vector{Ti}, csrcolval::Vector{Ti}, csrnzval::Vector{Tv},
[csccolptr::Vector{Ti}], [cscrowval::Vector{Ti}, cscnzval::Vector{Tv}] ) where {Tv,Ti<:Integer}
sparse
的父方法和专家驱动;有关基本用法,请参见 sparse
。此方法允许用户为 sparse
的中间对象和结果提供预分配的存储,如下所述。此功能使得从坐标表示中更高效地连续构建 SparseMatrixCSC
,并且还可以在没有额外成本的情况下提取结果转置的无序列表示。
此方法由三个主要步骤组成:(1)将提供的坐标表示计数排序为包含重复条目的无序行 CSR 形式。(2)遍历 CSR 形式,同时计算所需的 CSC 形式的列指针数组,检测重复条目,并将 CSR 形式中的重复条目重新打包;此阶段产生一个没有重复条目的无序行 CSR 形式。(3)将前面的 CSR 形式计数排序为一个完全排序的 CSC 形式,且没有重复条目。
输入数组 csrrowptr
、csrcolval
和 csrnzval
构成中间 CSR 形式的存储,并要求 length(csrrowptr) >= m + 1
、length(csrcolval) >= length(I)
和 length(csrnzval >= length(I))
。输入数组 klasttouch
,第二阶段的工作区,要求 length(klasttouch) >= n
。可选输入数组 csccolptr
、cscrowval
和 cscnzval
构成返回的 CSC 形式 S
的存储。如有必要,这些数组会自动调整大小以满足 length(csccolptr) = n + 1
、length(cscrowval) = nnz(S)
和 length(cscnzval) = nnz(S)
;因此,如果 nnz(S)
在开始时未知,传入适当类型的空向量(Vector{Ti}()
和 Vector{Tv}()
)即可,或者调用 sparse!
方法时忽略 cscrowval
和 cscnzval
。
返回时,csrrowptr
、csrcolval
和 csrnzval
包含结果转置的无序列表示。
您可以重用输入数组的存储(I
、J
、V
)用于输出数组(csccolptr
、cscrowval
、cscnzval
)。例如,您可以调用 sparse!(I, J, V, csrrowptr, csrcolval, csrnzval, I, J, V)
。请注意,它们将被调整大小以满足上述条件。
为了提高效率,此方法在 1 <= I[k] <= m
和 1 <= J[k] <= n
之外不执行参数检查。请谨慎使用。使用 --check-bounds=yes
进行测试是明智的。
此方法的运行时间为 O(m, n, length(I))
。F. Gustavson 在其论文 "Two fast algorithms for sparse matrices: multiplication and permuted transposition," ACM TOMS 4(3), 250-269 (1978) 中描述的 HALFPERM 算法启发了此方法使用一对计数排序。
SparseArrays.sparse!(I, J, V, [m, n, combine]) -> SparseMatrixCSC
sparse!
的变体,重新使用输入向量(I
,J
,V
)作为最终矩阵存储。在构造后,输入向量将别名矩阵缓冲区;S.colptr === I
,S.rowval === J
,和 S.nzval === V
成立,并且它们会根据需要进行 resize!
。
请注意,仍然会分配一些工作缓冲区。具体来说,此方法是 sparse!(I, J, V, m, n, combine, klasttouch, csrrowptr, csrcolval, csrnzval, csccolptr, cscrowval, cscnzval)
的便利包装,其中此方法分配适当大小的 klasttouch
,csrrowptr
,csrcolval
和 csrnzval
,但重用 I
,J
和 V
作为 csccolptr
,cscrowval
和 cscnzval
。
参数 m
,n
和 combine
默认为 maximum(I)
,maximum(J)
和 +
,分别。
此方法需要 Julia 1.10 或更高版本。
SparseArrays.sparsevec
— Functionsparsevec(I, V, [m, combine])
创建一个长度为 m
的稀疏向量 S
,使得 S[I[k]] = V[k]
。重复的元素使用 combine
函数合并,如果没有提供 combine
参数,则默认为 +
,除非 V
的元素是布尔值,在这种情况下 combine
默认为 |
。
示例
julia> II = [1, 3, 3, 5]; V = [0.1, 0.2, 0.3, 0.2];
julia> sparsevec(II, V)
5-element SparseVector{Float64, Int64} with 3 stored entries:
[1] = 0.1
[3] = 0.5
[5] = 0.2
julia> sparsevec(II, V, 8, -)
8-element SparseVector{Float64, Int64} with 3 stored entries:
[1] = 0.1
[3] = -0.1
[5] = 0.2
julia> sparsevec([1, 3, 1, 2, 2], [true, true, false, false, false])
3-element SparseVector{Bool, Int64} with 3 stored entries:
[1] = 1
[2] = 0
[3] = 1
sparsevec(d::Dict, [m])
创建一个长度为 m
的稀疏向量,其中非零索引是字典中的键,非零值是字典中的值。
示例
julia> sparsevec(Dict(1 => 3, 2 => 2))
2-element SparseVector{Int64, Int64} with 2 stored entries:
[1] = 3
[2] = 2
sparsevec(A)
将向量 A
转换为长度为 m
的稀疏向量。
示例
julia> sparsevec([1.0, 2.0, 0.0, 0.0, 3.0, 0.0])
6-element SparseVector{Float64, Int64} with 3 stored entries:
[1] = 1.0
[2] = 2.0
[5] = 3.0
Base.similar
— Methodsimilar(A::AbstractSparseMatrixCSC{Tv,Ti}, [::Type{TvNew}, ::Type{TiNew}, m::Integer, n::Integer]) where {Tv,Ti}
创建一个未初始化的可变数组,具有给定的元素类型、索引类型和大小,基于给定的源 SparseMatrixCSC
。新的稀疏矩阵保持原始稀疏矩阵的结构,除非输出矩阵的维度与输出不同。
输出矩阵在与输入相同的位置上有零,但在非零位置上有未初始化的值。
SparseArrays.issparse
— Functionissparse(S)
如果 S
是稀疏的,则返回 true
,否则返回 false
。
示例
julia> sv = sparsevec([1, 4], [2.3, 2.2], 10)
10-element SparseVector{Float64, Int64} with 2 stored entries:
[1] = 2.3
[4] = 2.2
julia> issparse(sv)
true
julia> issparse(Array(sv))
false
SparseArrays.nnz
— Functionnnz(A)
返回稀疏数组中存储(填充)元素的数量。
示例
julia> A = sparse(2I, 3, 3)
3×3 SparseMatrixCSC{Int64, Int64} with 3 stored entries:
2 ⋅ ⋅
⋅ 2 ⋅
⋅ ⋅ 2
julia> nnz(A)
3
SparseArrays.findnz
— Functionfindnz(A::SparseMatrixCSC)
返回一个元组 (I, J, V)
,其中 I
和 J
是稀疏矩阵 A
中存储的(“结构上非零”)值的行和列索引,V
是值的向量。
示例
julia> A = sparse([1 2 0; 0 0 3; 0 4 0])
3×3 SparseMatrixCSC{Int64, Int64} with 4 stored entries:
1 2 ⋅
⋅ ⋅ 3
⋅ 4 ⋅
julia> findnz(A)
([1, 1, 3, 2], [1, 2, 2, 3], [1, 2, 4, 3])
SparseArrays.spzeros
— Functionspzeros([type,]m[,n])
创建一个长度为 m
的稀疏向量或大小为 m x n
的稀疏矩阵。该稀疏数组将不包含任何非零值。在构造过程中不会为非零值分配任何存储。如果未指定类型,则默认为 Float64
。
示例
julia> spzeros(3, 3)
3×3 SparseMatrixCSC{Float64, Int64} with 0 stored entries:
⋅ ⋅ ⋅
⋅ ⋅ ⋅
⋅ ⋅ ⋅
julia> spzeros(Float32, 4)
4-element SparseVector{Float32, Int64} with 0 stored entries
spzeros([type], I::AbstractVector, J::AbstractVector, [m, n])
创建一个维度为 m x n
的稀疏矩阵 S
,在 S[I[k], J[k]]
处具有结构零。
此方法可用于构造矩阵的稀疏模式,并且比使用例如 sparse(I, J, zeros(length(I)))
更高效。
有关更多文档和专家驱动程序,请参见 SparseArrays.spzeros!
。
此方法需要 Julia 版本 1.10 或更高版本。
SparseArrays.spzeros!
— Functionspzeros!(::Type{Tv}, I::AbstractVector{Ti}, J::AbstractVector{Ti}, m::Integer, n::Integer,
klasttouch::Vector{Ti}, csrrowptr::Vector{Ti}, csrcolval::Vector{Ti},
[csccolptr::Vector{Ti}], [cscrowval::Vector{Ti}, cscnzval::Vector{Tv}]) where {Tv,Ti<:Integer}
spzeros(I, J)
的父类和专家驱动,允许用户提供预分配的中间对象存储。此方法对 spzeros
的作用类似于 SparseArrays.sparse!
对 sparse
的作用。有关详细信息和所需缓冲区长度,请参阅 SparseArrays.sparse!
的文档。
此方法需要 Julia 1.10 或更高版本。
SparseArrays.spzeros!(::Type{Tv}, I, J, [m, n]) -> SparseMatrixCSC{Tv}
spzeros!
的变体,重新使用输入向量 I
和 J
作为最终矩阵存储。在构造后,输入向量将别名矩阵缓冲区;S.colptr === I
和 S.rowval === J
成立,并且它们会根据需要进行 resize!
。
请注意,仍然会分配一些工作缓冲区。具体来说,此方法是 spzeros!(Tv, I, J, m, n, klasttouch, csrrowptr, csrcolval, csccolptr, cscrowval)
的便利包装,其中此方法分配适当大小的 klasttouch
、csrrowptr
和 csrcolval
,但重新使用 I
和 J
作为 csccolptr
和 cscrowval
。
参数 m
和 n
默认为 maximum(I)
和 maximum(J)
。
此方法需要 Julia 1.10 或更高版本。
SparseArrays.spdiagm
— Functionspdiagm(kv::Pair{<:Integer,<:AbstractVector}...)
spdiagm(m::Integer, n::Integer, kv::Pair{<:Integer,<:AbstractVector}...)
从 Pair
的向量和对角线构造稀疏对角矩阵。每个向量 kv.second
将放置在 kv.first
对角线上。默认情况下,矩阵是方形的,其大小由 kv
推断,但可以通过将 m,n
作为第一个参数传递来指定非方形大小 m
×n
(根据需要用零填充)。
示例
julia> spdiagm(-1 => [1,2,3,4], 1 => [4,3,2,1])
5×5 SparseMatrixCSC{Int64, Int64} with 8 stored entries:
⋅ 4 ⋅ ⋅ ⋅
1 ⋅ 3 ⋅ ⋅
⋅ 2 ⋅ 2 ⋅
⋅ ⋅ 3 ⋅ 1
⋅ ⋅ ⋅ 4 ⋅
spdiagm(v::AbstractVector)
spdiagm(m::Integer, n::Integer, v::AbstractVector)
构造一个稀疏矩阵,其元素为向量的对角元素。默认情况下(未给定 m
和 n
),矩阵为方形,其大小由 length(v)
给出,但可以通过将 m
和 n
作为第一个参数传递来指定非方形大小 m
×n
。
这些函数至少需要 Julia 1.6。
示例
julia> spdiagm([1,2,3])
3×3 SparseMatrixCSC{Int64, Int64} with 3 stored entries:
1 ⋅ ⋅
⋅ 2 ⋅
⋅ ⋅ 3
julia> spdiagm(sparse([1,0,3]))
3×3 SparseMatrixCSC{Int64, Int64} with 2 stored entries:
1 ⋅ ⋅
⋅ ⋅ ⋅
⋅ ⋅ 3
SparseArrays.sparse_hcat
— Functionsparse_hcat(A...)
沿着维度 2 进行连接。返回一个 SparseMatrixCSC 对象。
此方法是在 Julia 1.8 中添加的。它模仿了之前的连接行为,其中与来自 LinearAlgebra.jl 的专用 "稀疏" 矩阵类型的连接在没有任何 SparseArray 参数的情况下自动产生稀疏输出。
SparseArrays.sparse_vcat
— Functionsparse_vcat(A...)
沿着维度 1 连接。返回一个 SparseMatrixCSC 对象。
此方法是在 Julia 1.8 中添加的。它模仿了之前的连接行为,其中与来自 LinearAlgebra.jl 的专用 "稀疏" 矩阵类型的连接即使在没有任何 SparseArray 参数的情况下也会自动产生稀疏输出。
SparseArrays.sparse_hvcat
— Functionsparse_hvcat(rows::Tuple{Vararg{Int}}, values...)
稀疏的水平和垂直连接在一个调用中。此函数用于块矩阵语法。第一个参数指定每个块行中要连接的参数数量。
此方法是在 Julia 1.8 中添加的。它模仿了之前的连接行为,其中与来自 LinearAlgebra.jl 的专用“稀疏”矩阵类型的连接在没有任何 SparseArray 参数的情况下自动产生稀疏输出。
SparseArrays.blockdiag
— Functionblockdiag(A...)
以块对角的方式连接矩阵。目前仅对稀疏矩阵实现。
示例
julia> blockdiag(sparse(2I, 3, 3), sparse(4I, 2, 2))
5×5 SparseMatrixCSC{Int64, Int64} with 5 stored entries:
2 ⋅ ⋅ ⋅ ⋅
⋅ 2 ⋅ ⋅ ⋅
⋅ ⋅ 2 ⋅ ⋅
⋅ ⋅ ⋅ 4 ⋅
⋅ ⋅ ⋅ ⋅ 4
SparseArrays.sprand
— Functionsprand([rng],[T::Type],m,[n],p::AbstractFloat)
sprand([rng],m,[n],p::AbstractFloat,[rfn=rand])
创建一个随机长度为 m
的稀疏向量或 m
x n
的稀疏矩阵,其中任何元素为非零的概率独立地由 p
给出(因此非零的平均密度也恰好为 p
)。可选的 rng
参数指定一个随机数生成器,参见 Random Numbers。可选的 T
参数指定元素类型,默认为 Float64
。
默认情况下,非零值是从均匀分布中采样的,使用 rand
函数,即通过 rand(T)
,或者如果提供了 rng
,则为 rand(rng, T)
;对于默认的 T=Float64
,这对应于在 [0,1)
中均匀采样的非零值。
您可以通过传递自定义的 rfn
函数来从不同的分布中采样非零值,而不是使用 rand
。这应该是一个函数 rfn(k)
,返回一个包含 k
个从所需分布中采样的随机数的数组;或者,如果提供了 rng
,则应该是一个函数 rfn(rng, k)
。
示例
julia> sprand(Bool, 2, 2, 0.5)
2×2 SparseMatrixCSC{Bool, Int64} with 2 stored entries:
1 1
⋅ ⋅
julia> sprand(Float64, 3, 0.75)
3-element SparseVector{Float64, Int64} with 2 stored entries:
[1] = 0.795547
[2] = 0.49425
SparseArrays.sprandn
— Functionsprandn([rng][,Type],m[,n],p::AbstractFloat)
创建一个长度为 m
的随机稀疏向量或大小为 m
x n
的稀疏矩阵,具有指定的(独立的)概率 p
,表示任何条目为非零的概率,其中非零值是从正态分布中抽样的。可选的 rng
参数指定一个随机数生成器,参见 Random Numbers。
指定输出元素类型 Type
至少需要 Julia 1.1。
示例
julia> sprandn(2, 2, 0.75)
2×2 SparseMatrixCSC{Float64, Int64} with 3 stored entries:
-1.20577 ⋅
0.311817 -0.234641
SparseArrays.nonzeros
— Functionnonzeros(A)
返回稀疏数组 A
中结构非零值的向量。这包括在稀疏数组中显式存储的零。返回的向量直接指向 A
的内部非零存储,对返回向量的任何修改也会改变 A
。请参见 rowvals
和 nzrange
。
示例
julia> A = sparse(2I, 3, 3)
3×3 SparseMatrixCSC{Int64, Int64} with 3 stored entries:
2 ⋅ ⋅
⋅ 2 ⋅
⋅ ⋅ 2
julia> nonzeros(A)
3-element Vector{Int64}:
2
2
2
SparseArrays.rowvals
— Functionrowvals(A::AbstractSparseMatrixCSC)
返回 A
的行索引向量。对返回的向量的任何修改也会改变 A
。提供对行索引内部存储方式的访问在与遍历结构非零值时可能会很有用。另请参见 nonzeros
和 nzrange
。
示例
julia> A = sparse(2I, 3, 3)
3×3 SparseMatrixCSC{Int64, Int64} with 3 stored entries:
2 ⋅ ⋅
⋅ 2 ⋅
⋅ ⋅ 2
julia> rowvals(A)
3-element Vector{Int64}:
1
2
3
SparseArrays.nzrange
— Functionnzrange(A::AbstractSparseMatrixCSC, col::Integer)
返回稀疏矩阵列的结构非零值的索引范围。结合 nonzeros
和 rowvals
,这允许方便地遍历稀疏矩阵:
A = sparse(I,J,V)
rows = rowvals(A)
vals = nonzeros(A)
m, n = size(A)
for j = 1:n
for i in nzrange(A, j)
row = rows[i]
val = vals[i]
# 执行稀疏魔法...
end
end
向矩阵添加或移除非零元素可能会使 nzrange
无效,在迭代时不应修改矩阵。
nzrange(x::SparseVectorUnion, col)
给出稀疏向量的结构非零值的索引范围。列索引 col
被忽略(假定为 1
)。
SparseArrays.droptol!
— Functiondroptol!(A::AbstractSparseMatrixCSC, tol)
从 A
中移除绝对值小于或等于 tol
的存储值。
droptol!(x::AbstractCompressedVector, tol)
从 x
中移除绝对值小于或等于 tol
的存储值。
SparseArrays.dropzeros!
— FunctionSparseArrays.dropzeros
— Functiondropzeros(A::AbstractSparseMatrixCSC;)
生成 A
的副本,并从该副本中移除存储的数值零。
有关就地版本和算法信息,请参见 dropzeros!
。
示例
julia> A = sparse([1, 2, 3], [1, 2, 3], [1.0, 0.0, 1.0])
3×3 SparseMatrixCSC{Float64, Int64} 具有 3 个存储条目:
1.0 ⋅ ⋅
⋅ 0.0 ⋅
⋅ ⋅ 1.0
julia> dropzeros(A)
3×3 SparseMatrixCSC{Float64, Int64} 具有 2 个存储条目:
1.0 ⋅ ⋅
⋅ ⋅ ⋅
⋅ ⋅ 1.0
dropzeros(x::AbstractCompressedVector)
生成 x
的副本并从该副本中移除数值零。
有关就地版本和算法信息,请参见 dropzeros!
。
示例
julia> A = sparsevec([1, 2, 3], [1.0, 0.0, 1.0])
3-element SparseVector{Float64, Int64} with 3 stored entries:
[1] = 1.0
[2] = 0.0
[3] = 1.0
julia> dropzeros(A)
3-element SparseVector{Float64, Int64} with 2 stored entries:
[1] = 1.0
[3] = 1.0
SparseArrays.permute
— Functionpermute(A::AbstractSparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer},
q::AbstractVector{<:Integer}) where {Tv,Ti}
双向置换 A
,返回 PAQ
(A[p,q]
)。列置换 q
的长度必须与 A
的列数匹配 (length(q) == size(A, 2)
)。行置换 p
的长度必须与 A
的行数匹配 (length(p) == size(A, 1)
).
有关专家驱动程序和其他信息,请参见 permute!
.
示例
julia> A = spdiagm(0 => [1, 2, 3, 4], 1 => [5, 6, 7])
4×4 SparseMatrixCSC{Int64, Int64} with 7 stored entries:
1 5 ⋅ ⋅
⋅ 2 6 ⋅
⋅ ⋅ 3 7
⋅ ⋅ ⋅ 4
julia> permute(A, [4, 3, 2, 1], [1, 2, 3, 4])
4×4 SparseMatrixCSC{Int64, Int64} with 7 stored entries:
⋅ ⋅ ⋅ 4
⋅ ⋅ 3 7
⋅ 2 6 ⋅
1 5 ⋅ ⋅
julia> permute(A, [1, 2, 3, 4], [4, 3, 2, 1])
4×4 SparseMatrixCSC{Int64, Int64} with 7 stored entries:
⋅ ⋅ 5 1
⋅ 6 2 ⋅
7 3 ⋅ ⋅
4 ⋅ ⋅ ⋅
Base.permute!
— Methodpermute!(X::AbstractSparseMatrixCSC{Tv,Ti}, A::AbstractSparseMatrixCSC{Tv,Ti},
p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer},
[C::AbstractSparseMatrixCSC{Tv,Ti}]) where {Tv,Ti}
双向置换 A
,将结果 PAQ
(A[p,q]
) 存储在 X
中。如果存在,则将中间结果 (AQ)^T
(transpose(A[:,q])
) 存储在可选参数 C
中。要求 X
、A
,以及(如果存在)C
之间没有别名;要将结果 PAQ
存回 A
,请使用以下不带 X
的方法:
permute!(A::AbstractSparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer},
q::AbstractVector{<:Integer}[, C::AbstractSparseMatrixCSC{Tv,Ti},
[workcolptr::Vector{Ti}]]) where {Tv,Ti}
X
的维度必须与 A
匹配(size(X, 1) == size(A, 1)
和 size(X, 2) == size(A, 2)
),并且 X
必须有足够的存储空间来容纳 A
中的所有分配条目(length(rowvals(X)) >= nnz(A)
和 length(nonzeros(X)) >= nnz(A)
)。列置换 q
的长度必须与 A
的列数匹配(length(q) == size(A, 2)
)。行置换 p
的长度必须与 A
的行数匹配(length(p) == size(A, 1)
)。
C
的维度必须与 transpose(A)
匹配(size(C, 1) == size(A, 2)
和 size(C, 2) == size(A, 1)
),并且 C
必须有足够的存储空间来容纳 A
中的所有分配条目(length(rowvals(C)) >= nnz(A)
和 length(nonzeros(C)) >= nnz(A)
)。
有关更多(算法)信息,以及放弃参数检查的这些方法的版本,请参见(未导出的)父方法 unchecked_noalias_permute!
和 unchecked_aliasing_permute!
。
另见 permute
.
SparseArrays.halfperm!
— Functionhalfperm!(X::AbstractSparseMatrixCSC{Tv,Ti}, A::AbstractSparseMatrixCSC{TvA,Ti},
q::AbstractVector{<:Integer}, f::Function = identity) where {Tv,TvA,Ti}
列置换并转置 A
,同时对 A
的每个条目应用 f
,将结果 (f(A)Q)^T
(map(f, transpose(A[:,q]))
) 存储在 X
中。
X
的元素类型 Tv
必须与 f(::TvA)
匹配,其中 TvA
是 A
的元素类型。X
的维度必须与 transpose(A)
匹配(size(X, 1) == size(A, 2)
和 size(X, 2) == size(A, 1)
),并且 X
必须有足够的存储空间来容纳 A
中的所有分配条目(length(rowvals(X)) >= nnz(A)
和 length(nonzeros(X)) >= nnz(A)
)。列置换 q
的长度必须与 A
的列数匹配(length(q) == size(A, 2)
)。
此方法是执行 SparseMatrixCSC
上的转置和置换操作的多个方法的父方法。由于此方法不执行参数检查,因此更倾向于使用更安全的子方法([c]transpose[!]
,permute[!]
)而不是直接使用。
此方法实现了 F. Gustavson 描述的 HALFPERM
算法,"Two fast algorithms for sparse matrices: multiplication and permuted transposition," ACM TOMS 4(3), 250-269 (1978)。该算法的运行时间为 O(size(A, 1), size(A, 2), nnz(A))
,并且不需要超出传入的空间。
SparseArrays.ftranspose!
— Functionftranspose!(X::AbstractSparseMatrixCSC{Tv,Ti}, A::AbstractSparseMatrixCSC{Tv,Ti}, f::Function) where {Tv,Ti}
转置 A
并将其存储在 X
中,同时对非零元素应用函数 f
。不会移除 f
创建的零。size(X)
必须等于 size(transpose(A))
。除了在需要时调整 X
的 rowval
和 nzval
之外,不会分配额外的内存。
请参见 halfperm!
Sparse Linear Algebra API
LinearAlgebra.cholesky
— Functioncholesky(A, NoPivot(); check = true) -> Cholesky
计算稠密对称正定矩阵 A
的 Cholesky 分解,并返回一个 Cholesky
分解。矩阵 A
可以是一个 Symmetric
或 Hermitian
AbstractMatrix
,或者是一个 完全 对称或 Hermitian 的 AbstractMatrix
。
可以通过 F.L
和 F.U
从分解 F
中获得三角形 Cholesky 因子,其中 A ≈ F.U' * F.U ≈ F.L * F.L'
。
对于 Cholesky
对象,提供以下函数:size
、\
、inv
、det
、logdet
和 isposdef
。
如果你有一个由于构造中的舍入误差而稍微非 Hermitian 的矩阵 A
,请在将其传递给 cholesky
之前用 Hermitian(A)
将其包装,以便将其视为完全 Hermitian。
当 check = true
时,如果分解失败,将抛出错误。当 check = false
时,检查分解有效性的责任(通过 issuccess
)在于用户。
示例
julia> A = [4. 12. -16.; 12. 37. -43.; -16. -43. 98.]
3×3 Matrix{Float64}:
4.0 12.0 -16.0
12.0 37.0 -43.0
-16.0 -43.0 98.0
julia> C = cholesky(A)
Cholesky{Float64, Matrix{Float64}}
U factor:
3×3 UpperTriangular{Float64, Matrix{Float64}}:
2.0 6.0 -8.0
⋅ 1.0 5.0
⋅ ⋅ 3.0
julia> C.U
3×3 UpperTriangular{Float64, Matrix{Float64}}:
2.0 6.0 -8.0
⋅ 1.0 5.0
⋅ ⋅ 3.0
julia> C.L
3×3 LowerTriangular{Float64, Matrix{Float64}}:
2.0 ⋅ ⋅
6.0 1.0 ⋅
-8.0 5.0 3.0
julia> C.L * C.U == A
true
cholesky(A, RowMaximum(); tol = 0.0, check = true) -> CholeskyPivoted
计算稠密对称半正定矩阵 A
的带主元的 Cholesky 分解,并返回一个 CholeskyPivoted
分解。矩阵 A
可以是 Symmetric
或 Hermitian
AbstractMatrix
,或者是 完全 对称或 Hermitian 的 AbstractMatrix
。
可以通过 F.L
和 F.U
从分解 F
中获得三角 Cholesky 因子,以及通过 F.p
获得置换,其中 A[F.p, F.p] ≈ Ur' * Ur ≈ Lr * Lr'
,其中 Ur = F.U[1:F.rank, :]
和 Lr = F.L[:, 1:F.rank]
,或者替代地 A ≈ Up' * Up ≈ Lp * Lp'
,其中 Up = F.U[1:F.rank, invperm(F.p)]
和 Lp = F.L[invperm(F.p), 1:F.rank]
。
以下函数可用于 CholeskyPivoted
对象:size
、\
、inv
、det
和 rank
。
参数 tol
决定了确定秩的容差。对于负值,容差为机器精度。
如果您有一个由于构造中的舍入误差而略微非 Hermitian 的矩阵 A
,请在将其传递给 cholesky
之前用 Hermitian(A)
将其包装,以便将其视为完全 Hermitian。
当 check = true
时,如果分解失败,将抛出错误。当 check = false
时,检查分解有效性的责任(通过 issuccess
)在于用户。
示例
julia> X = [1.0, 2.0, 3.0, 4.0];
julia> A = X * X';
julia> C = cholesky(A, RowMaximum(), check = false)
CholeskyPivoted{Float64, Matrix{Float64}, Vector{Int64}}
U factor with rank 1:
4×4 UpperTriangular{Float64, Matrix{Float64}}:
4.0 2.0 3.0 1.0
⋅ 0.0 6.0 2.0
⋅ ⋅ 9.0 3.0
⋅ ⋅ ⋅ 1.0
permutation:
4-element Vector{Int64}:
4
2
3
1
julia> C.U[1:C.rank, :]' * C.U[1:C.rank, :] ≈ A[C.p, C.p]
true
julia> l, u = C; # destructuring via iteration
julia> l == C.L && u == C.U
true
cholesky(A::SparseMatrixCSC; shift = 0.0, check = true, perm = nothing) -> CHOLMOD.Factor
计算稀疏正定矩阵 A
的 Cholesky 分解。A
必须是 SparseMatrixCSC
或 SparseMatrixCSC
的 Symmetric
/Hermitian
视图。请注意,即使 A
没有类型标签,它仍然必须是对称的或厄米的。如果未给出 perm
,则使用填充减少的置换。F = cholesky(A)
最常用于通过 F\b
求解方程组,但方法 diag
、det
和 logdet
也为 F
定义。您还可以使用 F.L
提取单个因子。然而,由于默认情况下启用了主元,因子分解在内部表示为 A == P'*L*L'*P
,其中 P
是置换矩阵;仅使用 L
而不考虑 P
将给出不正确的答案。为了包括置换的影响,通常更可取的是提取“组合”因子,如 PtL = F.PtL
(相当于 P'*L
)和 LtP = F.UP
(相当于 L'*P
)。
当 check = true
时,如果分解失败,将抛出错误。当 check = false
时,检查分解有效性的责任(通过 issuccess
)由用户承担。
设置可选的 shift
关键字参数将计算 A+shift*I
的分解,而不是 A
。如果提供了 perm
参数,它应该是 1:size(A,1)
的一个置换,给出要使用的顺序(而不是 CHOLMOD 的默认 AMD 顺序)。
示例
在以下示例中,使用的填充减少置换是 [3, 2, 1]
。如果将 perm
设置为 1:3
以强制不进行置换,则因子中的非零元素数量为 6。
julia> A = [2 1 1; 1 2 0; 1 0 2]
3×3 Matrix{Int64}:
2 1 1
1 2 0
1 0 2
julia> C = cholesky(sparse(A))
SparseArrays.CHOLMOD.Factor{Float64, Int64}
type: LLt
method: simplicial
maxnnz: 5
nnz: 5
success: true
julia> C.p
3-element Vector{Int64}:
3
2
1
julia> L = sparse(C.L);
julia> Matrix(L)
3×3 Matrix{Float64}:
1.41421 0.0 0.0
0.0 1.41421 0.0
0.707107 0.707107 1.0
julia> L * L' ≈ A[C.p, C.p]
true
julia> P = sparse(1:3, C.p, ones(3))
3×3 SparseMatrixCSC{Float64, Int64} with 3 stored entries:
⋅ ⋅ 1.0
⋅ 1.0 ⋅
1.0 ⋅ ⋅
julia> P' * L * L' * P ≈ A
true
julia> C = cholesky(sparse(A), perm=1:3)
SparseArrays.CHOLMOD.Factor{Float64, Int64}
type: LLt
method: simplicial
maxnnz: 6
nnz: 6
success: true
julia> L = sparse(C.L);
julia> Matrix(L)
3×3 Matrix{Float64}:
1.41421 0.0 0.0
0.707107 1.22474 0.0
0.707107 -0.408248 1.1547
julia> L * L' ≈ A
true
此方法使用来自 SuiteSparse 的 CHOLMOD[ACM887][DavisHager2009] 库。CHOLMOD 仅支持单精度或双精度的实数或复数类型。输入矩阵如果不是这些元素类型,将适当地转换为这些类型。
CHOLMOD 的许多其他函数被封装但未从 Base.SparseArrays.CHOLMOD
模块导出。
LinearAlgebra.cholesky!
— Functioncholesky!(A::AbstractMatrix, NoPivot(); check = true) -> Cholesky
与 cholesky
相同,但通过覆盖输入 A
来节省空间,而不是创建副本。如果因分解产生的数字无法用 A
的元素类型表示,例如对于整数类型,将抛出 InexactError
异常。
示例
julia> A = [1 2; 2 50]
2×2 Matrix{Int64}:
1 2
2 50
julia> cholesky!(A)
ERROR: InexactError: Int64(6.782329983125268)
Stacktrace:
[...]
cholesky!(A::AbstractMatrix, RowMaximum(); tol = 0.0, check = true) -> CholeskyPivoted
与 cholesky
相同,但通过覆盖输入 A
来节省空间,而不是创建副本。如果因子分解产生的数字无法由 A
的元素类型表示,例如对于整数类型,将抛出 InexactError
异常。
cholesky!(F::CHOLMOD.Factor, A::SparseMatrixCSC; shift = 0.0, check = true) -> CHOLMOD.Factor
计算 A
的 Cholesky ($LL'$) 分解,重用符号分解 F
。A
必须是 SparseMatrixCSC
或 SparseMatrixCSC
的 Symmetric
/ Hermitian
视图。请注意,即使 A
没有类型标签,它仍然必须是对称的或厄米的。
另请参见 cholesky
。
此方法使用来自 SuiteSparse 的 CHOLMOD 库,仅支持单精度或双精度的实数或复数类型。输入矩阵如果不是这些元素类型,将会适当地转换为这些类型。
LinearAlgebra.lowrankupdate
— Functionlowrankupdate(C::Cholesky, v::AbstractVector) -> CC::Cholesky
使用向量 v
更新 Cholesky 分解 C
。如果 A = C.U'C.U
,则 CC = cholesky(C.U'C.U + v*v')
,但 CC
的计算仅使用 O(n^2)
操作。
lowrankupdate(F::CHOLMOD.Factor, C::AbstractArray) -> FF::CHOLMOD.Factor
获取给定 A
的 LDLt
或 LLt
分解 F
的 A + C*C'
的 LDLt
分解。
返回的因子始终是 LDLt
分解。
LinearAlgebra.lowrankupdate!
— Functionlowrankupdate!(C::Cholesky, v::AbstractVector) -> CC::Cholesky
使用向量 v
更新 Cholesky 分解 C
。如果 A = C.U'C.U
,则 CC = cholesky(C.U'C.U + v*v')
,但 CC
的计算仅使用 O(n^2)
操作。输入的分解 C
会就地更新,以便在退出时 C == CC
。在计算过程中,向量 v
会被销毁。
lowrankupdate!(F::CHOLMOD.Factor, C::AbstractArray)
将 A
的 LDLt
或 LLt
分解 F
更新为 A + C*C'
的分解。
LLt
分解会转换为 LDLt
。
LinearAlgebra.lowrankdowndate
— Functionlowrankdowndate(C::Cholesky, v::AbstractVector) -> CC::Cholesky
使用向量 v
对 Cholesky 分解 C
进行降维。如果 A = C.U'C.U
,则 CC = cholesky(C.U'C.U - v*v')
,但 CC
的计算仅使用 O(n^2)
的操作。
lowrankdowndate(F::CHOLMOD.Factor, C::AbstractArray) -> FF::CHOLMOD.Factor
给定 A
的 LDLt
或 LLt
分解 F
,获取 A + C*C'
的 LDLt
分解。
返回的因子始终是 LDLt
分解。
LinearAlgebra.lowrankdowndate!
— Functionlowrankdowndate!(C::Cholesky, v::AbstractVector) -> CC::Cholesky
使用向量 v
对 Cholesky 分解 C
进行降维。如果 A = C.U'C.U
,则 CC = cholesky(C.U'C.U - v*v')
,但 CC
的计算仅使用 O(n^2)
操作。输入的分解 C
会就地更新,以便在退出时 C == CC
。在计算过程中,向量 v
会被销毁。
lowrankdowndate!(F::CHOLMOD.Factor, C::AbstractArray)
将 A
的 LDLt
或 LLt
分解 F
更新为 A - C*C'
的分解。
LLt
分解会转换为 LDLt
。
SparseArrays.CHOLMOD.lowrankupdowndate!
— Functionlowrankupdowndate!(F::CHOLMOD.Factor, C::Sparse, update::Cint)
将 A
的 LDLt
或 LLt
分解 F
更新为 A ± C*C'
的分解。
如果使用保持稀疏性的分解,即 L*L' == P*A*P'
,则新因子将是 L*L' == P*A*P' + C'*C
update
:Cint(1)
表示 A + CC'
,Cint(0)
表示 A - CC'
LinearAlgebra.ldlt
— Functionldlt(S::SymTridiagonal) -> LDLt
计算实对称三对角矩阵 S
的 LDLt
(即 $LDL^T$)分解,使得 S = L*Diagonal(d)*L'
,其中 L
是单位下三角矩阵,d
是一个向量。LDLt
分解 F = ldlt(S)
的主要用途是求解线性方程组 Sx = b
,使用 F\b
。
另请参见 bunchkaufman
,它是任意对称或厄米矩阵的类似但带有主元的分解。
示例
julia> S = SymTridiagonal([3., 4., 5.], [1., 2.])
3×3 SymTridiagonal{Float64, Vector{Float64}}:
3.0 1.0 ⋅
1.0 4.0 2.0
⋅ 2.0 5.0
julia> ldltS = ldlt(S);
julia> b = [6., 7., 8.];
julia> ldltS \ b
3-element Vector{Float64}:
1.7906976744186047
0.627906976744186
1.3488372093023255
julia> S \ b
3-element Vector{Float64}:
1.7906976744186047
0.627906976744186
1.3488372093023255
ldlt(A::SparseMatrixCSC; shift = 0.0, check = true, perm=nothing) -> CHOLMOD.Factor
计算稀疏矩阵 A
的 $LDL'$ 分解。A
必须是 SparseMatrixCSC
或 SparseMatrixCSC
的 Symmetric
/Hermitian
视图。请注意,即使 A
没有类型标签,它仍然必须是对称或厄米的。使用填充减少的置换。F = ldlt(A)
最常用于求解方程组 A*x = b
,使用 F\b
。返回的分解对象 F
还支持方法 diag
、det
、logdet
和 inv
。您可以使用 F.L
从 F
中提取单个因子。然而,由于默认情况下启用了主元,分解在内部表示为 A == P'*L*D*L'*P
,其中 P
是置换矩阵;仅使用 L
而不考虑 P
将给出不正确的答案。为了包括置换的影响,通常更好地提取“组合”因子,如 PtL = F.PtL
(相当于 P'*L
)和 LtP = F.UP
(相当于 L'*P
)。支持的因子完整列表为 :L, :PtL, :D, :UP, :U, :LD, :DU, :PtLD, :DUP
。
当 check = true
时,如果分解失败,将抛出错误。当 check = false
时,检查分解有效性的责任(通过 issuccess
)由用户承担。
设置可选的 shift
关键字参数计算 A+shift*I
的分解,而不是 A
。如果提供了 perm
参数,它应该是 1:size(A,1)
的一个置换,给出要使用的顺序(而不是 CHOLMOD 的默认 AMD 顺序)。
此方法使用来自 SuiteSparse 的 CHOLMOD[ACM887][DavisHager2009] 库。CHOLMOD 仅支持单精度或双精度的实数或复数类型。输入矩阵如果不是这些元素类型,将根据需要转换为这些类型。
CHOLMOD 的许多其他函数被封装但未从 Base.SparseArrays.CHOLMOD
模块导出。
LinearAlgebra.lu
— Functionlu(A::AbstractSparseMatrixCSC; check = true, q = nothing, control = get_umfpack_control()) -> F::UmfpackLU
计算稀疏矩阵 A
的 LU 分解。
对于元素类型为实数或复数的稀疏 A
,返回类型 F
为 UmfpackLU{Tv, Ti}
,其中 Tv
= Float64
或 ComplexF64
,而 Ti
是整数类型(Int32
或 Int64
)。
当 check = true
时,如果分解失败,将抛出错误。当 check = false
时,检查分解有效性的责任(通过 issuccess
)由用户承担。
置换 q
可以是一个置换向量或 nothing
。如果未提供置换向量或 q
为 nothing
,则使用 UMFPACK 的默认值。如果置换不是零基的,则会制作一个零基的副本。
control
向量默认为 Julia SparseArrays 包的 UMFPACK 默认配置(注意:这已从 UMFPACK 默认值修改,以禁用迭代精炼),但可以通过传递长度为 UMFPACK_CONTROL
的向量进行更改,具体配置请参见 UMFPACK 手册。例如,要重新启用迭代精炼:
umfpack_control = SparseArrays.UMFPACK.get_umfpack_control(Float64, Int64) # 读取 Float64 稀疏矩阵的 Julia 默认配置
SparseArrays.UMFPACK.show_umf_ctrl(umfpack_control) # 可选 - 显示值
umfpack_control[SparseArrays.UMFPACK.JL_UMFPACK_IRSTEP] = 2.0 # 重新启用迭代精炼(2 是 UMFPACK 默认的最大迭代精炼步骤)
Alu = lu(A; control = umfpack_control)
x = Alu \ b # 解 Ax = b,包括 UMFPACK 迭代精炼
可以通过索引访问分解 F
的各个组件:
组件 | 描述 |
---|---|
L | LU 的 L (下三角)部分 |
U | LU 的 U (上三角)部分 |
p | 右置换 Vector |
q | 左置换 Vector |
Rs | 缩放因子的 Vector |
: | (L,U,p,q,Rs) 组件 |
F
和 A
之间的关系为
F.L*F.U == (F.Rs .* A)[F.p, F.q]
F
进一步支持以下函数:
另见 lu!
lu(A::AbstractSparseMatrixCSC)
使用的是 UMFPACK[ACM832] 库,该库是 SuiteSparse 的一部分。由于该库仅支持元素为 Float64
或 ComplexF64
的稀疏矩阵,lu
会将 A
转换为类型为 SparseMatrixCSC{Float64}
或 SparseMatrixCSC{ComplexF64}
的副本。
lu(A, pivot = RowMaximum(); check = true, allowsingular = false) -> F::LU
计算 A
的 LU 分解。
当 check = true
时,如果分解失败,将抛出错误。当 check = false
时,检查分解有效性的责任(通过 issuccess
)由用户承担。
默认情况下,当 check = true
时,如果分解产生有效因子,但上三角因子 U
的秩不足,也会抛出错误。可以通过传递 allowsingular = true
来更改此行为。
在大多数情况下,如果 A
是 AbstractMatrix{T}
的子类型 S
,且元素类型 T
支持 +
、-
、*
和 /
,则返回类型为 LU{T,S{T}}
。
一般来说,LU 分解涉及对矩阵行的排列(对应于下面描述的 F.p
输出),称为“主元选择”(因为它对应于选择哪个行包含“主元”,即 F.U
的对角元素)。可以通过可选的 pivot
参数选择以下主元选择策略:
RowMaximum()
(默认):标准主元选择策略;主元对应于剩余待分解行中绝对值最大的元素。此主元选择策略要求元素类型也支持abs
和<
。 (这通常是浮点矩阵的唯一数值稳定选项。)RowNonZero()
:主元对应于剩余待分解行中第一个非零元素。 (这对应于手动计算中的典型选择,对于支持iszero
但不支持abs
或<
的更一般的代数数类型也很有用。)NoPivot()
:关闭主元选择(如果在主元位置遇到零条目,将失败,即使allowsingular = true
)。
可以通过 getproperty
访问分解 F
的各个组成部分:
组件 | 描述 |
---|---|
F.L | L (下三角)部分的 LU |
F.U | U (上三角)部分的 LU |
F.p | (右)排列 Vector |
F.P | (右)排列 Matrix |
迭代分解会产生组件 F.L
、F.U
和 F.p
。
F
和 A
之间的关系是
F.L*F.U == A[F.p, :]
F
进一步支持以下函数:
支持的函数 | LU | LU{T,Tridiagonal{T}} |
---|---|---|
/ | ✓ | |
\ | ✓ | ✓ |
inv | ✓ | ✓ |
det | ✓ | ✓ |
logdet | ✓ | ✓ |
logabsdet | ✓ | ✓ |
size | ✓ | ✓ |
allowsingular
关键字参数是在 Julia 1.11 中添加的。
示例
julia> A = [4 3; 6 3]
2×2 Matrix{Int64}:
4 3
6 3
julia> F = lu(A)
LU{Float64, Matrix{Float64}, Vector{Int64}}
L factor:
2×2 Matrix{Float64}:
1.0 0.0
0.666667 1.0
U factor:
2×2 Matrix{Float64}:
6.0 3.0
0.0 1.0
julia> F.L * F.U == A[F.p, :]
true
julia> l, u, p = lu(A); # 通过迭代解构
julia> l == F.L && u == F.U && p == F.p
true
julia> lu([1 2; 1 2], allowsingular = true)
LU{Float64, Matrix{Float64}, Vector{Int64}}
L factor:
2×2 Matrix{Float64}:
1.0 0.0
1.0 1.0
U factor (rank-deficient):
2×2 Matrix{Float64}:
1.0 2.0
0.0 0.0
LinearAlgebra.qr
— Functionqr(A::SparseMatrixCSC; tol=_default_tol(A), ordering=ORDERING_DEFAULT) -> QRSparse
计算稀疏矩阵 A
的 QR
分解。使用填充减少的行和列置换,使得 F.R = F.Q'*A[F.prow,F.pcol]
。这种类型的主要应用是解决最小二乘或欠定问题,使用 \
。该函数调用 C 库 SPQR[ACM933]。
qr(A::SparseMatrixCSC)
使用的是 SuiteSparse 中的 SPQR 库。由于该库仅支持具有 Float64
或 ComplexF64
元素的稀疏矩阵,因此从 Julia v1.4 开始,qr
将 A
转换为适当类型的 SparseMatrixCSC{Float64}
或 SparseMatrixCSC{ComplexF64}
的副本。
示例
julia> A = sparse([1,2,3,4], [1,1,2,2], [1.0,1.0,1.0,1.0])
4×2 SparseMatrixCSC{Float64, Int64} with 4 stored entries:
1.0 ⋅
1.0 ⋅
⋅ 1.0
⋅ 1.0
julia> qr(A)
SparseArrays.SPQR.QRSparse{Float64, Int64}
Q factor:
4×4 SparseArrays.SPQR.QRSparseQ{Float64, Int64}
R factor:
2×2 SparseMatrixCSC{Float64, Int64} with 2 stored entries:
-1.41421 ⋅
⋅ -1.41421
Row permutation:
4-element Vector{Int64}:
1
3
4
2
Column permutation:
2-element Vector{Int64}:
1
2
qr(A, pivot = NoPivot(); blocksize) -> F
计算矩阵 A
的 QR 分解:一个正交(或如果 A
是复值则为单位)矩阵 Q
,以及一个上三角矩阵 R
,使得
\[A = Q R\]
返回的对象 F
以打包格式存储分解:
- 如果
pivot == ColumnNorm()
,则F
是一个QRPivoted
对象, - 否则如果
A
的元素类型是 BLAS 类型(Float32
,Float64
,ComplexF32
或ComplexF64
),则F
是一个QRCompactWY
对象, - 否则
F
是一个QR
对象。
可以通过属性访问器检索分解 F
的各个组成部分:
每次通过 F.R
引用上三角因子都会分配一个新数组。因此,建议缓存该数组,例如,通过 R = F.R
并继续使用 R
。
迭代分解会产生组件 Q
、R
,以及如果存在则为 p
。
以下函数可用于 QR
对象:inv
、size
和 \
。当 A
是矩形时,\
将返回一个最小二乘解,如果解不是唯一的,则返回范数最小的解。当 A
不是满秩时,需要进行(列)置换的分解以获得最小范数解。
允许与全/方形或非全/方形 Q
进行乘法,即支持 F.Q*F.R
和 F.Q*A
。可以使用 Matrix
将 Q
矩阵转换为常规矩阵。此操作返回“薄” Q 因子,即,如果 A
是 m
×n
且 m>=n
,则 Matrix(F.Q)
产生一个具有正交列的 m
×n
矩阵。要检索“完整” Q 因子,即一个 m
×m
的正交矩阵,请使用 F.Q*I
或 collect(F.Q)
。如果 m<=n
,则 Matrix(F.Q)
产生一个 m
×m
的正交矩阵。
QR 分解的块大小可以通过关键字参数 blocksize :: Integer
指定,当 pivot == NoPivot()
且 A isa StridedMatrix{<:BlasFloat}
时。如果 blocksize > minimum(size(A))
,则会被忽略。请参见 QRCompactWY
。
blocksize
关键字参数需要 Julia 1.4 或更高版本。
示例
julia> A = [3.0 -6.0; 4.0 -8.0; 0.0 1.0]
3×2 Matrix{Float64}:
3.0 -6.0
4.0 -8.0
0.0 1.0
julia> F = qr(A)
LinearAlgebra.QRCompactWY{Float64, Matrix{Float64}, Matrix{Float64}}
Q 因子:3×3 LinearAlgebra.QRCompactWYQ{Float64, Matrix{Float64}, Matrix{Float64}}
R 因子:
2×2 Matrix{Float64}:
-5.0 10.0
0.0 -1.0
julia> F.Q * F.R == A
true
qr
返回多种类型,因为 LAPACK 使用几种表示法来最小化 Householder 基本反射器的乘积的内存存储需求,以便 Q
和 R
矩阵可以紧凑地存储,而不是作为两个单独的密集矩阵。
Noteworthy External Sparse Packages
几个其他的 Julia 包提供了稀疏矩阵的实现,值得一提:
SuiteSparseGraphBLAS.jl 是一个快速的多线程 SuiteSparse:GraphBLAS C 库的封装。在 CPU 上,这通常是最快的选项,通常显著优于 MKLSparse。
SparseMatricesCSR.jl 提供了一个 Julia 原生实现的压缩稀疏行 (CSR) 格式。
MKLSparse.jl 加速了 SparseArrays 稀疏-密集矩阵操作,使用了英特尔的 MKL 库。
SparseArrayKit.jl 可用于多维稀疏数组。
LuxurySparse.jl 提供静态稀疏数组格式以及坐标格式。
ExtendableSparse.jl 通过对新存储索引的懒惰方法实现了对稀疏矩阵的快速插入。
Finch.jl 支持通过迷你张量语言和编译器进行广泛的多维稀疏数组格式和操作,全部使用原生 Julia。支持 COO、CSF、CSR、CSC 等格式,以及广播、归约等操作和自定义操作。
外部包提供稀疏直接求解器:
外部包提供用于特征系统和奇异值分解的迭代解法的求解器:
用于处理图形的外部包:
- ACM887Chen, Y., Davis, T. A., Hager, W. W., & Rajamanickam, S. (2008). Algorithm 887: CHOLMOD, Supernodal Sparse Cholesky Factorization and Update/Downdate. ACM Trans. Math. Softw., 35(3). doi:10.1145/1391989.1391995
- DavisHager2009Davis, Timothy A., & Hager, W. W. (2009). Dynamic Supernodes in Sparse Cholesky Update/Downdate and Triangular Solves. ACM Trans. Math. Softw., 35(4). doi:10.1145/1462173.1462176
- ACM832Davis, Timothy A. (2004b). Algorithm 832: UMFPACK V4.3–-an Unsymmetric-Pattern Multifrontal Method. ACM Trans. Math. Softw., 30(2), 196–199. doi:10.1145/992200.992206
- ACM933Foster, L. V., & Davis, T. A. (2013). Algorithm 933: Reliable Calculation of Numerical Rank, Null Space Bases, Pseudoinverse Solutions, and Basic Solutions Using SuitesparseQR. ACM Trans. Math. Softw., 40(1). doi:10.1145/2513109.2513116