Skip to content

Commit 0e1b627

Browse files
committed
extend custom documentation
1 parent 95fb799 commit 0e1b627

File tree

2 files changed

+47
-2
lines changed

2 files changed

+47
-2
lines changed

docs/src/custom.jl

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,3 +229,48 @@ mul!(similar(x)', x', A)
229229
# corresponding 5-arg `mul!` methods. This may seem like a lot of methods to
230230
# be implemented, but note that adding such methods is only necessary/recommended
231231
# for performance.
232+
233+
# ## Computing a matrix representation
234+
235+
# In some cases, it might be necessary to compute a matrix representation of a `LinearMap`.
236+
# This is essentially done via the
237+
# `[LinearMaps._unsafe_mul!(::Matrix,::LinearMap,::Number)]`(@ref) method, for which a
238+
# generic fallback exists: it applies the `LinearMap` successively to the standard unit
239+
# vectors.
240+
241+
F = MyFillMap(5, (100,100))
242+
M = Matrix{eltype(F)}(undef, size(F))
243+
@benchmark Matrix($F)
244+
@benchmark LinearMaps._unsafe_mul!($(Matrix{Int}(undef, (100,100))), $(MyFillMap(5, (100,100))), true)
245+
246+
# If a more performant implementation exists, it is recommended to overwrite this method,
247+
# for instance (as before, size checks need not be included here since they are handled by
248+
# the corresponding `LinearAlgebra.mul!` method):
249+
250+
LinearMaps._unsafe_mul!(M::AbstractMatrix, A::MyFillMap, s::Number) = fill!(M, A.λ*s)
251+
@benchmark Matrix($F)
252+
@benchmark LinearMaps._unsafe_mul!($(Matrix{Int}(undef, (100,100))), $(MyFillMap(5, (100,100))), true)
253+
254+
# As one can see, the above runtimes are dominated by the allocation of the output matrix,
255+
# but still overwriting the multiplication kernel yields a speed-up of about factor 3 for
256+
# the matrix filling part.
257+
258+
# ## Slicing
259+
260+
# As usual, generic fallbacks for `LinearMap` slicing exist and are handled by the following
261+
# method hierarchy, where at least one of `I` and `J` has to be a `Colon`:
262+
#
263+
# Base.getindex(::LinearMap, I, J)
264+
# -> LinearMaps._getindex(::LinearMap, I, J)
265+
#
266+
# The method `Base.getindex` checks the validity of the the requested indices and calls
267+
# `LinearMaps._getindex`, which should be overloaded for custom `LinearMap`s subtypes.
268+
# For instance:
269+
270+
@benchmark F[1,:]
271+
272+
LinearMaps._getindex(A::MyFillMap, ::Integer, J::Base.Slice) = fill(A.λ, axes(J))
273+
@benchmark F[1,:]
274+
275+
# Note that in `Base.getindex` `Colon`s are converted to `Base.Slice` via
276+
# `Base.to_indices`, thus the dispatch must be on `Base.Slice` rather than on `Colon`.

src/conversion.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# Matrix: create matrix representation of LinearMap
22
function Base.Matrix{T}(A::LinearMap) where {T}
33
mat = Matrix{T}(undef, size(A))
4-
mul!(mat, A, one(T))
4+
_unsafe_mul!(mat, A, true)
55
end
66

77
function Base.AbstractMatrix{T}(A::LinearMap) where {T}
88
mat = similar(Array{T}, axes(A))
9-
mul!(mat, A, one(T))
9+
_unsafe_mul!(mat, A, true)
1010
end
1111

1212
Base.Matrix(A::LinearMap{T}) where {T} = Matrix{T}(A)

0 commit comments

Comments
 (0)