-
-
Notifications
You must be signed in to change notification settings - Fork 30
Description
In LinearAlgebra
, often there are shortcuts taken depending on whether a matrix has a particular structure (e.g. if it is Diagonal
), which lets us evaluate certain functions by acting only on the non-zero elements. This may be either be explicitly evaluating the structure of the matrix and acting only on filled elements, or by forwarding an operation to a parent which is structured. This, however, assumes that the action of the function on the other elements doesn't change the structure, which may not be the case.
E.g.:
julia> B = Bidiagonal(zeros(4), zeros(3), :U)
4×4 Bidiagonal{Float64, Vector{Float64}}:
0.0 0.0 ⋅ ⋅
⋅ 0.0 0.0 ⋅
⋅ ⋅ 0.0 0.0
⋅ ⋅ ⋅ 0.0
julia> U = UpperTriangular(B)
4×4 UpperTriangular{Float64, Bidiagonal{Float64, Vector{Float64}}}:
0.0 0.0 0.0 0.0
⋅ 0.0 0.0 0.0
⋅ ⋅ 0.0 0.0
⋅ ⋅ ⋅ 0.0
julia> U * NaN
4×4 UpperTriangular{Float64, Bidiagonal{Float64, Vector{Float64}}}:
NaN NaN 0.0 0.0
⋅ NaN NaN 0.0
⋅ ⋅ NaN NaN
⋅ ⋅ ⋅ NaN
julia> VERSION
v"1.12.0-DEV.935"
In this case, the zeros in the upper triangular part of the matrix should be all equivalent, irrespective of the parent. By forwarding the operation to the parent, we are privileging some of the zeros over the others, which seems inconsistent. This behavior is also different if the parent is fully materialized, in which case we obtain:
julia> UpperTriangular(Matrix(B)) * NaN
4×4 Matrix{Float64}:
NaN NaN NaN NaN
NaN NaN NaN NaN
NaN NaN NaN NaN
NaN NaN NaN NaN
In this, even the structural zeros of an UpperTriangular
lose their privileged status on being multiplied by NaN
.
The result should ideally only depend on the structure of the outermost wrapper, which, in this case, is an UpperTriangular
.
The other class of operations is:
julia> T = Tridiagonal(zeros(3), zeros(4), zeros(3))
4×4 Tridiagonal{Float64, Vector{Float64}}:
0.0 0.0 ⋅ ⋅
0.0 0.0 0.0 ⋅
⋅ 0.0 0.0 0.0
⋅ ⋅ 0.0 0.0
julia> T ^ NaN
4×4 Tridiagonal{Float64, Vector{Float64}}:
NaN 0.0 ⋅ ⋅
0.0 NaN 0.0 ⋅
⋅ 0.0 NaN 0.0
⋅ ⋅ 0.0 NaN
In this, the method determines that T
is diagonal, and only acts on the diagonal elements. However, the result seems a bit nonsensical as certain zeros are being privileged over others (although I'm unsure what result to expect here). This extends to fully materialized matrices as well:
julia> zeros(4,4) ^ NaN
4×4 Matrix{Float64}:
NaN 0.0 0.0 0.0
0.0 NaN 0.0 0.0
0.0 0.0 NaN 0.0
0.0 0.0 0.0 NaN
It seems a bit weird that only the diagonal is filled with NaN
, while the other elements aren't touched.