Skip to content

Commit 744800a

Browse files
authored
Correct isposdef for CompositeMap (#151)
1 parent 55823fa commit 744800a

File tree

4 files changed

+23
-8
lines changed

4 files changed

+23
-8
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "LinearMaps"
22
uuid = "7a12625a-238d-50fd-b39a-03d52299707e"
3-
version = "3.3.1"
3+
version = "3.4.0"
44

55
[deps]
66
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

src/composition.jl

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ Base.isreal(A::CompositeMap) = all(isreal, A.maps) # sufficient but not necessar
2121

2222
# the following rules are sufficient but not necessary
2323
for (f, _f, g) in ((:issymmetric, :_issymmetric, :transpose),
24-
(:ishermitian, :_ishermitian, :adjoint),
25-
(:isposdef, :_isposdef, :adjoint))
24+
(:ishermitian, :_ishermitian, :adjoint))
2625
@eval begin
2726
LinearAlgebra.$f(A::CompositeMap) = $_f(A.maps)
2827
$_f(maps::Tuple{}) = true
@@ -42,6 +41,15 @@ for (f, _f, g) in ((:issymmetric, :_issymmetric, :transpose),
4241
end
4342
end
4443

44+
# A * B * A and A * B * A' are positive definite if (sufficient condition) A & B are positive definite
45+
LinearAlgebra.isposdef(A::CompositeMap) = _isposdef(A.maps)
46+
_isposdef(maps::Tuple{}) = true # empty product is equivalent to "I" which is pos. def.
47+
_isposdef(maps::Tuple{<:LinearMap}) = isposdef(maps[1])
48+
function _isposdef(maps::Tuple{Vararg{LinearMap}})
49+
(maps[end] == adjoint(maps[1]) || maps[end] == maps[1]) &&
50+
isposdef(maps[1]) && _isposdef(Base.front(Base.tail(maps)))
51+
end
52+
4553
# scalar multiplication and division (non-commutative case)
4654
function Base.:(*)(α::Number, A::LinearMap)
4755
T = promote_type(typeof(α), eltype(A))

test/composition.jl

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays
2828
@test @inferred F4 * v == @inferred F * (F * (F * (F * v)))
2929
@test @inferred Matrix(M * transpose(M)) A * transpose(A)
3030
@test @inferred !isposdef(M * transpose(M))
31-
@test @inferred isposdef(M * M')
31+
@test @inferred isposdef(LinearMap(M * M', isposdef=true))
3232
@test @inferred issymmetric(N * N')
3333
@test @inferred ishermitian(N * N')
3434
@test @inferred !issymmetric(M' * M)
@@ -40,10 +40,10 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays
4040
@test @inferred !issymmetric(FC'FC)
4141
@test @inferred ishermitian(FC'FC)
4242
@test @inferred ishermitian(FC'*H*FC)
43-
@test @inferred isposdef(transpose(F) * F * 3)
44-
@test @inferred isposdef(transpose(F) * 3 * F)
43+
@test @inferred issymmetric(transpose(F) * F * 3)
44+
@test @inferred issymmetric(transpose(F) * 3 * F)
4545
@test @inferred !isposdef(-5*transpose(F) * F)
46-
@test @inferred isposdef((M * F)' * M * 4 * F)
46+
@test @inferred ishermitian((M * F)' * M * 4 * F)
4747
@test @inferred transpose(M * F) == @inferred transpose(F) * transpose(M)
4848
@test @inferred (4*((-3*M)*2)) == @inferred -12M*2
4949
@test @inferred (4*((3*(-M))*2)*(-5)) == @inferred -12M*(-10)
@@ -132,4 +132,10 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays
132132
X = rand(size(Ls, 2), 10)
133133
Y = similar(X, (size(Ls, 1), size(X, 2)))
134134
@test mul!(Y, Ls, X) L4.lmap * L3.lmap * L2.lmap * L1.lmap * X
135+
136+
# test isposdef on a case where sufficient conditions work
137+
B = LinearMap([1 0; 0 1], isposdef=true) # isposdef!
138+
C = B' * B * B * B * B # no B' at end on purpose
139+
@test @inferred isposdef(C)
140+
@test @inferred isposdef(B * B) # even case for empty tuple test
135141
end

test/scaledmap.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,10 @@ using Test, LinearMaps, LinearAlgebra, BenchmarkTools
7777
@test mul!(x2, C', y1) == x1
7878

7979
# check scale*conj(scale)
80-
A = LinearMap{Float32}(rand(N, 2)) # rank=2 w.p.1
80+
A = LinearMap{Float32}(rand(1, 2)) # rank=1 w.p.1
8181
B = @inferred β * A
8282
C = @inferred B' * B
83+
@test !isposdef(C)
8384
@test @inferred isposdef(C.λ)
8485

8586
N = 2^8

0 commit comments

Comments
 (0)