Skip to content

Commit 4ef04f0

Browse files
committed
Merge branch 'myopnorm' into fixed-opnorm
2 parents d90c2e2 + a14e917 commit 4ef04f0

File tree

7 files changed

+140
-0
lines changed

7 files changed

+140
-0
lines changed

stdlib/LinearAlgebra/src/bidiag.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,18 @@ function svd(M::Bidiagonal; kw...)
248248
svd!(copy(M), kw...)
249249
end
250250

251+
###################
252+
# opnorm #
253+
###################
254+
255+
function _opnorm1Inf(B::Bidiagonal, p)
256+
size(B, 1) == 1 && return norm(first(B.dv))
257+
case = xor(p == 1, istriu(B))
258+
normd1, normdend = norm(first(B.dv)), norm(last(B.dv))
259+
normd1, normdend = case ? (zero(normd1), normdend) : (normd1, zero(normdend))
260+
return max(mapreduce(t -> sum(norm, t), max, zip(view(B.dv, (1:length(B.ev)) .+ !case), B.ev)), normdend)
261+
end
262+
251263
####################
252264
# Generic routines #
253265
####################

stdlib/LinearAlgebra/src/diagonal.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,16 @@ end
10361036
*(A::AbstractTriangular, D::Diagonal) = @invoke *(A::AbstractMatrix, D::Diagonal)
10371037
*(D::Diagonal, A::AbstractTriangular) = @invoke *(D::Diagonal, A::AbstractMatrix)
10381038

1039+
_opnorm12Inf(A::Diagonal, p) = maximum(opnorm(x, p) for x in A.diag)
1040+
1041+
function opnorm(A::Diagonal, p::Real=2)
1042+
if p == 1 || p == Inf || p == 2
1043+
return _opnorm12Inf(A, p)
1044+
else
1045+
throw(ArgumentError("invalid p-norm p=$p. Valid: 1, 2, Inf"))
1046+
end
1047+
end
1048+
10391049
dot(x::AbstractVector, D::Diagonal, y::AbstractVector) = _mapreduce_prod(dot, x, D, y)
10401050

10411051
dot(A::Diagonal, B::Diagonal) = dot(A.diag, B.diag)

stdlib/LinearAlgebra/src/special.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,19 @@ end
466466
==(A::Bidiagonal, B::SymTridiagonal) = iszero(_evview(B)) && iszero(A.ev) && A.dv == _diagview(B)
467467
==(B::SymTridiagonal, A::Bidiagonal) = A == B
468468

469+
# op norm for structured matrices other than diagonal
470+
# the _opnorm1Inf methods are housed in the structured type's respective files
471+
472+
function opnorm(A::Union{Bidiagonal,Tridiagonal,SymTridiagonal}, p::Real=2)
473+
if p == 2
474+
return opnorm2(A)
475+
elseif p == 1 || p == Inf
476+
return _opnorm1Inf(A, p)
477+
else
478+
throw(ArgumentError("invalid p-norm p=$p. Valid: 1, 2, Inf"))
479+
end
480+
end
481+
469482
# TODO: remove these deprecations (used by SparseArrays in the past)
470483
const _DenseConcatGroup = Union{}
471484
const _SpecialArrays = Union{}

stdlib/LinearAlgebra/src/tridiag.jl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,41 @@ function SymTridiagonal{T}(M::Tridiagonal) where T
886886
end
887887
end
888888

889+
###################
890+
# opnorms #
891+
###################
892+
893+
# Tridiagonal
894+
895+
function _opnorm1Inf(A::Tridiagonal, p)
896+
size(A, 1) == 1 && return norm(first(A.d))
897+
case = p == Inf
898+
lowerrange, upperrange = case ? (1:length(A.dl)-1, 2:length(A.dl)) : (2:length(A.dl), 1:length(A.dl)-1)
899+
normfirst, normend = case ? (norm(first(A.d))+norm(first(A.du)), norm(last(A.dl))+norm(last(A.d))) : (norm(first(A.d))+norm(first(A.dl)), norm(last(A.du))+norm(last(A.d)))
900+
901+
return max(
902+
mapreduce(t -> sum(norm, t),
903+
max,
904+
zip(view(A.d, (2:length(A.d)-1)), view(A.dl, lowerrange), view(A.du, upperrange))
905+
),
906+
normfirst, normend)
907+
end
908+
909+
# SymTridiagonal
910+
911+
function _opnorm1Inf(A::SymTridiagonal, p::Real)
912+
size(A, 1) == 1 && return norm(first(A.dv))
913+
lowerrange, upperrange = 1:length(A.ev)-1, 2:length(A.ev)
914+
normfirst, normend = norm(first(A.dv))+norm(first(A.ev)), norm(last(A.ev))+norm(last(A.dv))
915+
916+
return max(
917+
mapreduce(t -> sum(norm, t),
918+
max,
919+
zip(view(A.dv, (2:length(A.dv)-1)), view(A.ev, lowerrange), view(A.ev, upperrange))
920+
),
921+
normfirst, normend)
922+
end
923+
889924
Base._sum(A::Tridiagonal, ::Colon) = sum(A.d) + sum(A.dl) + sum(A.du)
890925
function Base._sum(A::SymTridiagonal, ::Colon)
891926
se = sum(_evview(A))

stdlib/LinearAlgebra/test/bidiag.jl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,4 +1138,30 @@ end
11381138
end
11391139
end
11401140

1141+
@testset "opnorms" begin
1142+
B = Bidiagonal([1,-2,3,-4], [1,2,3], 'U')
1143+
1144+
@test opnorm(B, 1) == opnorm(Matrix(B), 1)
1145+
@test opnorm(B, 2) opnorm(Matrix(B), 2)
1146+
@test opnorm(B, Inf) == opnorm(Matrix(B), Inf)
1147+
1148+
B = Bidiagonal([1,-2,3,-4], [1,2,3], 'L')
1149+
1150+
@test opnorm(B, 1) == opnorm(Matrix(B), 1)
1151+
@test opnorm(B, 2) opnorm(Matrix(B), 2)
1152+
@test opnorm(B, Inf) == opnorm(Matrix(B), Inf)
1153+
1154+
B = Bidiagonal([2], Int[], 'L')
1155+
1156+
@test opnorm(B, 1) == opnorm(Matrix(B), 1)
1157+
@test opnorm(B, 2) opnorm(Matrix(B), 2)
1158+
@test opnorm(B, Inf) == opnorm(Matrix(B), Inf)
1159+
1160+
B = Bidiagonal([2], Int[], 'U')
1161+
1162+
@test opnorm(B, 1) == opnorm(Matrix(B), 1)
1163+
@test opnorm(B, 2) opnorm(Matrix(B), 2)
1164+
@test opnorm(B, Inf) == opnorm(Matrix(B), Inf)
1165+
end
1166+
11411167
end # module TestBidiagonal

stdlib/LinearAlgebra/test/diagonal.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,26 @@ end
989989
end
990990
end
991991

992+
@testset "opnorms" begin
993+
D = Diagonal([1,-2,3,-4])
994+
995+
@test opnorm(D, 1) == opnorm(Matrix(D), 1)
996+
@test opnorm(D, 2) opnorm(Matrix(D), 2)
997+
@test opnorm(D, Inf) == opnorm(Matrix(D), Inf)
998+
999+
D = Diagonal([-11])
1000+
@test opnorm(D, 1) == opnorm(Matrix(D), 1)
1001+
@test opnorm(D, 2) opnorm(Matrix(D), 2)
1002+
@test opnorm(D, Inf) == opnorm(Matrix(D), Inf)
1003+
1004+
# block diagonal matrices
1005+
D = Diagonal([[1 2; 3 4], [5 6; 7 8]])
1006+
A = [1 2 0 0; 3 4 0 0; 0 0 5 6; 0 0 7 8] # full matrix of D
1007+
@test opnorm(D, 1) == opnorm(A, 1)
1008+
@test opnorm(D, 2) opnorm(A, 2)
1009+
@test opnorm(D, Inf) == opnorm(A, Inf)
1010+
end
1011+
9921012
@testset "(Sym)Tridiagonal division by Diagonal" begin
9931013
for K in (5, 1), elty in (Float64, ComplexF32), overlength in (1, 0)
9941014
S = SymTridiagonal(randn(elty, K), randn(elty, K-overlength))

stdlib/LinearAlgebra/test/tridiag.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,30 @@ end
602602
@test A90\b90 inv(A90)*b90
603603
end
604604

605+
@testset "opnorms" begin
606+
T = Tridiagonal([1,2,3], [1,-2,3,-4], [1,2,3])
607+
608+
@test opnorm(T, 1) == opnorm(Matrix(T), 1)
609+
@test_skip opnorm(T, 2) opnorm(Matrix(T), 2) # currently missing
610+
@test opnorm(T, Inf) == opnorm(Matrix(T), Inf)
611+
612+
S = SymTridiagonal([1,-2,3,-4], [1,2,3])
613+
614+
@test opnorm(S, 1) == opnorm(Matrix(S), 1)
615+
@test_skip opnorm(S, 2) opnorm(Matrix(S), 2) # currently missing
616+
@test opnorm(S, Inf) == opnorm(Matrix(S), Inf)
617+
618+
T = Tridiagonal(Int[], [-5], Int[])
619+
@test opnorm(T, 1) == opnorm(Matrix(T), 1)
620+
@test_skip opnorm(T, 2) opnorm(Matrix(T), 2) # currently missing
621+
@test opnorm(T, Inf) == opnorm(Matrix(T), Inf)
622+
623+
S = SymTridiagonal(T)
624+
@test opnorm(S, 1) == opnorm(Matrix(S), 1)
625+
@test_skip opnorm(S, 2) opnorm(Matrix(S), 2) # currently missing
626+
@test opnorm(S, Inf) == opnorm(Matrix(S), Inf)
627+
end
628+
605629
@testset "singular values of SymTridiag" begin
606630
@test svdvals(SymTridiagonal([-4,2,3], [0,0])) [4,3,2]
607631
@test svdvals(SymTridiagonal(collect(0.:10.), zeros(10))) reverse(0:10)

0 commit comments

Comments
 (0)