Skip to content

Commit aa54eb3

Browse files
authored
fix vector-based CompositeMap mul kernel (#175)
1 parent f8eaf98 commit aa54eb3

File tree

4 files changed

+49
-3
lines changed

4 files changed

+49
-3
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.6.0"
3+
version = "3.6.1"
44

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

docs/src/history.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
cases where these higher-order `LinearMap`s are constructed from many maps where a tuple
99
backend may get inefficient or impose hard work for the compiler at construction.
1010
The default behavior, however, does not change, and construction of vector-based
11-
`LinearMap`s requires usage of the unexported constructors ("expert usage").
11+
`LinearMap`s requires usage of the unexported constructors ("expert usage"), except for
12+
constructions like `sum([A, B, C])` or `prod([A, B, C])` (`== C*B*A`), where `A`, `B` and
13+
`C` are of some `LinearMap` type.
1214

1315
## What's new in v3.5
1416

src/composition.jl

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ function _resize(dest::AbstractMatrix, sz::Tuple{<:Integer,<:Integer})
205205
end
206206

207207
function _compositemul!(y::AbstractVecOrMat,
208-
A::CompositeMap,
208+
A::CompositeMap{<:Any,<:LinearMapTuple},
209209
x::AbstractVecOrMat,
210210
source = similar(y, (size(A.maps[1],1), size(x)[2:end]...)),
211211
dest = similar(y, (size(A.maps[2],1), size(x)[2:end]...)))
@@ -219,3 +219,40 @@ function _compositemul!(y::AbstractVecOrMat,
219219
_unsafe_mul!(y, A.maps[N], source)
220220
return y
221221
end
222+
223+
function _compositemul!(y::AbstractVecOrMat,
224+
A::CompositeMap{<:Any,<:LinearMapVector},
225+
x::AbstractVecOrMat)
226+
N = length(A.maps)
227+
if N == 1
228+
return _unsafe_mul!(y, A.maps[1], x)
229+
elseif N == 2
230+
return _compositemul2!(y, A, x)
231+
else
232+
return _compositemulN!(y, A, x)
233+
end
234+
end
235+
236+
function _compositemul2!(y::AbstractVecOrMat,
237+
A::CompositeMap{<:Any,<:LinearMapVector},
238+
x::AbstractVecOrMat,
239+
source = similar(y, (size(A.maps[1],1), size(x)[2:end]...)))
240+
_unsafe_mul!(source, A.maps[1], x)
241+
_unsafe_mul!(y, A.maps[2], source)
242+
return y
243+
end
244+
function _compositemulN!(y::AbstractVecOrMat,
245+
A::CompositeMap{<:Any,<:LinearMapVector},
246+
x::AbstractVecOrMat,
247+
source = similar(y, (size(A.maps[1],1), size(x)[2:end]...)),
248+
dest = similar(y, (size(A.maps[2],1), size(x)[2:end]...)))
249+
N = length(A.maps)
250+
_unsafe_mul!(source, A.maps[1], x)
251+
for n in 2:N-1
252+
dest = _resize(dest, (size(A.maps[n],1), size(x)[2:end]...))
253+
_unsafe_mul!(dest, A.maps[n], source)
254+
dest, source = source, dest # alternate dest and source
255+
end
256+
_unsafe_mul!(y, A.maps[N], source)
257+
return y
258+
end

test/composition.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,4 +148,11 @@ using LinearMaps: LinearMapVector, LinearMapTuple
148148
@test @inferred isposdef(LinearMaps.CompositeMap{Float64}([B, B, B, B, B']))
149149
@test @inferred isposdef(B * B) # even case for empty tuple test
150150
@test @inferred isposdef(LinearMaps.CompositeMap{Float64}([B, B]))
151+
152+
M = LinearMap(cumsum, 3)
153+
for i in 1:4
154+
P = prod(fill(M, i))
155+
@test P isa LinearMaps.CompositeMap{<:Any,<:LinearMapVector}
156+
@test P * ones(3) == (LowerTriangular(ones(3,3))^i) * ones(3)
157+
end
151158
end

0 commit comments

Comments
 (0)