Skip to content

Commit

Permalink
Inplace transpose for unit Triangular may skip diagonal (#53101)
Browse files Browse the repository at this point in the history
Since the diagonal elements of a `UnitUpperTriangular` are given by
`onelement`, these should be unchanged under `transpose/adjoint`, and we
don't need to access these elements in the parent array when performing
in-place operations.

Fixes
```julia
julia> using LinearAlgebra

julia> M = Matrix{BigFloat}(undef, 2, 2);

julia> M[1,2] = 3;

julia> U = UnitUpperTriangular(M)
2×2 UnitUpperTriangular{BigFloat, Matrix{BigFloat}}:
 1.0  3.0
  ⋅   1.0

julia> transpose!(U)
ERROR: UndefRefError: access to undefined reference
Stacktrace:
 [1] getindex
   @ ./essentials.jl:882 [inlined]
 [2] getindex
   @ ./array.jl:915 [inlined]
 [3] copytri!
   @ ~/packages/julias/julia-latest/share/julia/stdlib/v1.11/LinearAlgebra/src/matmul.jl:414 [inlined]
 [4] transpose!(A::UnitUpperTriangular{BigFloat, Matrix{BigFloat}})
   @ LinearAlgebra ~/packages/julias/julia-latest/share/julia/stdlib/v1.11/LinearAlgebra/src/triangular.jl:470
 [5] top-level scope
   @ REPL[5]:1
```
After this PR:
```julia
julia> transpose!(U)
2×2 UnitLowerTriangular{BigFloat, Matrix{BigFloat}}:
 1.0   ⋅
 3.0  1.0
```

(cherry picked from commit cc74d24)
  • Loading branch information
jishnub authored and KristofferC committed Feb 6, 2024
1 parent a1ad1ba commit 2ef3842
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 5 deletions.
8 changes: 4 additions & 4 deletions stdlib/LinearAlgebra/src/triangular.jl
Original file line number Diff line number Diff line change
Expand Up @@ -406,13 +406,13 @@ transpose(A::UnitLowerTriangular) = UnitUpperTriangular(transpose(A.data))
transpose(A::UnitUpperTriangular) = UnitLowerTriangular(transpose(A.data))

transpose!(A::LowerTriangular) = UpperTriangular(copytri!(A.data, 'L', false, true))
transpose!(A::UnitLowerTriangular) = UnitUpperTriangular(copytri!(A.data, 'L', false, true))
transpose!(A::UnitLowerTriangular) = UnitUpperTriangular(copytri!(A.data, 'L', false, false))
transpose!(A::UpperTriangular) = LowerTriangular(copytri!(A.data, 'U', false, true))
transpose!(A::UnitUpperTriangular) = UnitLowerTriangular(copytri!(A.data, 'U', false, true))
transpose!(A::UnitUpperTriangular) = UnitLowerTriangular(copytri!(A.data, 'U', false, false))
adjoint!(A::LowerTriangular) = UpperTriangular(copytri!(A.data, 'L' , true, true))
adjoint!(A::UnitLowerTriangular) = UnitUpperTriangular(copytri!(A.data, 'L' , true, true))
adjoint!(A::UnitLowerTriangular) = UnitUpperTriangular(copytri!(A.data, 'L' , true, false))
adjoint!(A::UpperTriangular) = LowerTriangular(copytri!(A.data, 'U' , true, true))
adjoint!(A::UnitUpperTriangular) = UnitLowerTriangular(copytri!(A.data, 'U' , true, true))
adjoint!(A::UnitUpperTriangular) = UnitLowerTriangular(copytri!(A.data, 'U' , true, false))

diag(A::LowerTriangular) = diag(A.data)
diag(A::UnitLowerTriangular) = fill(oneunit(eltype(A)), size(A,1))
Expand Down
10 changes: 9 additions & 1 deletion stdlib/LinearAlgebra/test/triangular.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ debug && println("Test basic type functionality")
@test LowerTriangular(randn(3, 3)) |> t -> [size(t, i) for i = 1:3] == [size(Matrix(t), i) for i = 1:3]

# The following test block tries to call all methods in base/linalg/triangular.jl in order for a combination of input element types. Keep the ordering when adding code.
for elty1 in (Float32, Float64, BigFloat, ComplexF32, ComplexF64, Complex{BigFloat}, Int)
@testset for elty1 in (Float32, Float64, BigFloat, ComplexF32, ComplexF64, Complex{BigFloat}, Int)
# Begin loop for first Triangular matrix
for (t1, uplo1) in ((UpperTriangular, :U),
(UnitUpperTriangular, :U),
Expand Down Expand Up @@ -871,4 +871,12 @@ end
end
end

@testset "transpose triangular diagonal" begin
M = Matrix{BigFloat}(undef, 2, 2);
M[1,2] = 3;
U = UnitUpperTriangular(M)
Ut = transpose(U)
@test transpose!(U) == Ut
end

end # module TestTriangular

0 comments on commit 2ef3842

Please sign in to comment.