Skip to content

Commit 8c1e9b9

Browse files
authored
Fix order of multiplication in mixed-product rule (#231)
1 parent 37cf32d commit 8c1e9b9

File tree

5 files changed

+14
-7
lines changed

5 files changed

+14
-7
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.11.2"
3+
version = "3.11.3"
44

55
[deps]
66
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"

src/LinearMaps.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ _combine(As::LinearMapVector, Bs::LinearMapTuple) = Base.vect(As..., Bs...)
9999
_combine(As::LinearMapTuple, Bs::LinearMapVector) = Base.vect(As..., Bs...)
100100
_combine(As::LinearMapVector, Bs::LinearMapVector) = Base.vect(As..., Bs...)
101101

102+
_reverse!(As::LinearMapTuple) = reverse(As)
103+
_reverse!(As::LinearMapVector) = reverse!(As)
104+
102105
# The (internal) multiplication logic is as follows:
103106
# - `*(A, x)` calls `mul!(y, A, x)` for appropriately-sized y
104107
# - `mul!` checks consistency of the sizes, and calls `_unsafe_mul!`,

src/composition.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ end
1515
CompositeMap{T}(maps::As) where {T, As<:LinearMapTupleOrVector} = CompositeMap{T, As}(maps)
1616

1717
Base.mapreduce(::typeof(identity), ::typeof(Base.mul_prod), maps::LinearMapTupleOrVector) =
18-
CompositeMap{promote_type(map(eltype, maps)...)}(reverse(maps))
18+
CompositeMap{promote_type(map(eltype, maps)...)}(_reverse!(maps))
1919
Base.mapreduce(::typeof(identity), ::typeof(Base.mul_prod), maps::AbstractVector{<:LinearMap{T}}) where {T} =
20-
CompositeMap{T}(reverse(maps))
20+
CompositeMap{T}(reverse!(maps))
2121

2222
MulStyle(A::CompositeMap) = MulStyle(A.maps...) === TwoArg() ? TwoArg() : ThreeArg()
2323

@@ -158,9 +158,9 @@ Base.:(*)(A₁::CompositeMap, A₂::ScaledMap) = (A₁ * A₂.lmap) * A₂.λ
158158

159159
# special transposition behavior
160160
LinearAlgebra.transpose(A::CompositeMap{T}) where {T} =
161-
CompositeMap{T}(map(transpose, reverse(A.maps)))
161+
CompositeMap{T}(map(transpose, _reverse!(A.maps)))
162162
LinearAlgebra.adjoint(A::CompositeMap{T}) where {T} =
163-
CompositeMap{T}(map(adjoint, reverse(A.maps)))
163+
CompositeMap{T}(map(adjoint, _reverse!(A.maps)))
164164

165165
# comparison of CompositeMap objects
166166
Base.:(==)(A::CompositeMap, B::CompositeMap) =
@@ -169,7 +169,7 @@ Base.:(==)(A::CompositeMap, B::CompositeMap) =
169169
# multiplication with vectors/matrices
170170
function Base.:(*)(A::CompositeMap, x::AbstractVector)
171171
MulStyle(A) === TwoArg() ?
172-
foldr(*, reverse(A.maps), init=x) :
172+
foldr(*, _reverse!(A.maps), init=x) :
173173
invoke(*, Tuple{LinearMap, AbstractVector}, A, x)
174174
end
175175

src/kronecker.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ function _unsafe_mul!(y,
272272
Bs1, Bs2 = _front(Bs), _tail(Bs)
273273
apply = all(_iscompatible, zip(As1, As2)) && all(_iscompatible, zip(Bs1, Bs2))
274274
if apply
275-
_unsafe_mul!(y, kron(prod(As), prod(Bs)), x)
275+
_unsafe_mul!(y, kron(prod(_reverse!(As)), prod(_reverse!(Bs))), x)
276276
else
277277
_unsafe_mul!(y, CompositeMap{T}(map(LinearMap, L.maps)), x)
278278
end

test/kronecker.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays
8686
Kv = LinearMaps.CompositeMap{ComplexF64}(fill(LA LB, 3))
8787
@test kron(A, B)^3 * ones(6) Kv * ones(6)
8888
@test Matrix(K) kron(A, B)^3
89+
A = [0 1; 0 0]
90+
B = [0 0; 1 0]
91+
J = LinearMap(I, 1)
92+
@test Matrix(kron(J, A*B)) == Matrix(kron(J, A) * kron(J, B))
8993
# example that doesn't use mixed-product rule
9094
A = rand(3, 2); B = rand(2, 3)
9195
K = @inferred kron(A, LinearMap(B))

0 commit comments

Comments
 (0)