Skip to content

JuliaLinearAlgebra/RectangularFullPacked.jl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

56 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RectangularFullPacked

CI codecov

A Julia package for the Rectangular Full Packed (RFP) matrix storage format.

The RFP format stores a triangular or Symmetric/Hermitian matrix of size n in (n * (n + 1))/2 storage locations consisting of three blocks from the original matrix. The exact sizes and orientations of the blocks in the underlying parent array depend on whether the lower or upper triangle is stored and whether the parent array is transposed. It also depends on whether the size of the matrix is even or odd as shown in Fig. 5 (p. 12) of LAPACK Working Notes 199.

For example, starting with a 6 by 6 matrix whose elements are numbered 1 to 36 in column-major order

julia> using LinearAlgebra, RectangularFullPacked

julia> A = reshape(1:36, (6, 6))
6×6 reshape(::UnitRange{Int64}, 6, 6) with eltype Int64:
 1   7  13  19  25  31
 2   8  14  20  26  32
 3   9  15  21  27  33
 4  10  16  22  28  34
 5  11  17  23  29  35
 6  12  18  24  30  36

the lower triangular matrix AL is constructed by replacing the elements above the diagonal with zero.

julia> AL = tril!(collect(A))
6×6 Matrix{Int64}:
 1   0   0   0   0   0
 2   8   0   0   0   0
 3   9  15   0   0   0
 4  10  16  22   0   0
 5  11  17  23  29   0
 6  12  18  24  30  36

AL requires the same amount of storage as does A even though there are only 21 potential non-zeros in AL. The RFP version of the lower triangular matrix

julia> ArfpL = Int.(TriangularRFP(float.(A), :L))
6×6 Matrix{Int64}:
1   0   0   0   0   0
2   8   0   0   0   0
3   9  15   0   0   0
4  10  16  22   0   0
5  11  17  23  29   0
6  12  18  24  30  36

provides the same displayed form but the underlying, "parent" array is 7 by 3

julia> ALparent = Int.(ArfpL.data)
7×3 Matrix{Int64}:
22  23  24
 1  29  30
 2   8  36
 3   9  15
 4  10  16
 5  11  17
 6  12  18

The three blocks of AL are the lower triangle of AL[1:3, 1:3], stored as the lower triangle of ALparent[2:4, :]; the square block AL[4:6, 1:3] stored in ALparent[5:7, :]; and the lower triangle of AL[4:6, 4:6] stored transposed in ALparent[1:3, :].

For odd values of n, the parent is of size (n, div(n + 1, 2)) and the non-zeros in the first (n+1)/2 columns are in the same positions in ALparent.

For example,

julia> AL = tril!(collect(reshape(1:25, 5, 5)))
5×5 Matrix{Int64}:
 1   0   0   0   0
 2   7   0   0   0
 3   8  13   0   0
 4   9  14  19   0
 5  10  15  20  25

julia> ArfpL = Int.(TriangularRFP(float(AL), :L).data)
5×3 Matrix{Int64}:
 1  19  20
 2   7  25
 3   8  13
 4   9  14
 5  10  15

RFP storage is especially useful for large positive definite Hermitian matrices because the Cholesky factor can be evaluated nearly as quickly (by applying Level-3 BLAS to the blocks) as in full storage mode but requiring about half the storage.

A trivial example is

julia> A = [2 1 2; 1 2 0; 1 0 2]
3×3 Matrix{Int64}:
2  1  2
1  2  0
1  0  2

julia> cholesky(Hermitian(A, :L))
Cholesky{Float64, Matrix{Float64}}
L factor:
3×3 LowerTriangular{Float64, Matrix{Float64}}:
1.41421               
0.707107   1.22474     
0.707107  -0.408248  1.1547

julia> ArfpL = HermitianRFP(TriangularRFP(float.(A), :L))
3×3 HermitianRFP{Float64}:
2.0  1.0  1.0
1.0  2.0  0.0
1.0  0.0  2.0

julia> cholesky!(ArfpL).data
3×2 Matrix{Float64}:
1.41421    1.1547
0.707107   1.22474
0.707107  -0.408248