Skip to content

Commit 89743c6

Browse files
authored
Get rid of A*_mul_B! (#97)
1 parent 3c2e531 commit 89743c6

21 files changed

+432
-379
lines changed

docs/src/types.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ SparseArrays.blockdiag
9292
Base.:*(::LinearMap,::AbstractVector)
9393
Base.:*(::LinearMap,::AbstractMatrix)
9494
Base.:*(::AbstractMatrix,::LinearMap)
95-
LinearAlgebra.mul!(::AbstractVector,::LinearMap,::AbstractVector)
96-
LinearAlgebra.mul!(::AbstractVector,::LinearMap,::AbstractVector,::Number,::Number)
95+
LinearAlgebra.mul!(::AbstractMatrix,::LinearMap,::AbstractMatrix)
96+
LinearAlgebra.mul!(::AbstractVecOrMat,::LinearMap,::AbstractVector,::Number,::Number)
9797
*(::LinearAlgebra.AdjointAbsVec,::LinearMap)
9898
*(::LinearAlgebra.TransposeAbsVec,::LinearMap)
9999
```

src/LinearMaps.jl

Lines changed: 70 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export LinearMap
44
export , kronsum,
55

66
using LinearAlgebra
7+
import LinearAlgebra: mul!
78
using SparseArrays
89

910
if VERSION < v"1.2-"
@@ -83,35 +84,9 @@ julia> A*x
8384
```
8485
"""
8586
function Base.:(*)(A::LinearMap, x::AbstractVector)
86-
size(A, 2) == length(x) || throw(DimensionMismatch("mul!"))
87-
return @inbounds A_mul_B!(similar(x, promote_type(eltype(A), eltype(x)), size(A, 1)), A, x)
88-
end
89-
"""
90-
mul!(Y, A::LinearMap, B) -> Y
91-
92-
Calculates the action of the linear map `A` on the vector or matrix `B` and stores the result in `Y`,
93-
overwriting the existing value of `Y`. Note that `Y` must not be aliased with either `A` or `B`.
94-
95-
## Examples
96-
```jldoctest; setup=(using LinearAlgebra, LinearMaps)
97-
julia> A=LinearMap([1.0 2.0; 3.0 4.0]); B=[1.0, 1.0]; Y = similar(B); mul!(Y, A, B);
98-
99-
julia> Y
100-
2-element Array{Float64,1}:
101-
3.0
102-
7.0
103-
104-
julia> A=LinearMap([1.0 2.0; 3.0 4.0]); B=[1.0 1.0; 1.0 1.0]; Y = similar(B); mul!(Y, A, B);
105-
106-
julia> Y
107-
2×2 Array{Float64,2}:
108-
3.0 3.0
109-
7.0 7.0
110-
```
111-
"""
112-
function LinearAlgebra.mul!(y::AbstractVector, A::LinearMap, x::AbstractVector)
113-
@boundscheck check_dim_mul(y, A, x)
114-
return @inbounds A_mul_B!(y, A, x)
87+
size(A, 2) == length(x) || throw(DimensionMismatch("linear map has dimensions ($mA,$nA), " *
88+
"vector has length $mB"))
89+
return _unsafe_mul!(similar(x, promote_type(eltype(A), eltype(x)), size(A, 1)), A, x)
11590
end
11691

11792
"""
@@ -143,14 +118,23 @@ julia> C
143118
730.0 740.0
144119
```
145120
"""
146-
function LinearAlgebra.mul!(y::AbstractVector, A::LinearMap, x::AbstractVector, α::Number, β::Number)
147-
@boundscheck check_dim_mul(y, A, x)
121+
function mul!(y::AbstractVecOrMat, A::LinearMap, x::AbstractVector)
122+
check_dim_mul(y, A, x)
123+
return _unsafe_mul!(y, A, x)
124+
end
125+
126+
function mul!(y::AbstractVecOrMat, A::LinearMap, x::AbstractVector, α::Number, β::Number)
127+
check_dim_mul(y, A, x)
128+
return _unsafe_mul!(y, A, x, α, β)
129+
end
130+
131+
function _generic_mapvec_mul!(y, A, x, α, β)
148132
if isone(α)
149-
iszero(β) && (A_mul_B!(y, A, x); return y)
133+
iszero(β) && (_unsafe_mul!(y, A, x); return y)
150134
isone(β) && (y .+= A * x; return y)
151135
# β != 0, 1
152-
rmul!(y, β)
153-
y .+= A * x
136+
z = A * x
137+
y .= y.*β .+ z
154138
return y
155139
elseif iszero(α)
156140
iszero(β) && (fill!(y, zero(eltype(y))); return y)
@@ -159,19 +143,53 @@ function LinearAlgebra.mul!(y::AbstractVector, A::LinearMap, x::AbstractVector,
159143
rmul!(y, β)
160144
return y
161145
else # α != 0, 1
162-
iszero(β) && (A_mul_B!(y, A, x); rmul!(y, α); return y)
163-
isone(β) && (y .+= rmul!(A * x, α); return y)
164-
# β != 0, 1
165-
rmul!(y, β)
166-
y .+= rmul!(A * x, α)
146+
iszero(β) && (_unsafe_mul!(y, A, x); rmul!(y, α); return y)
147+
z = A * x
148+
if isone(β)
149+
y .+= z .* α
150+
else
151+
y .= y .* β .+ z .* α
152+
end
167153
return y
168154
end
169155
end
156+
170157
# the following is of interest in, e.g., subspace-iteration methods
171-
Base.@propagate_inbounds function LinearAlgebra.mul!(Y::AbstractMatrix, A::LinearMap, X::AbstractMatrix, α::Number=true, β::Number=false)
172-
@boundscheck check_dim_mul(Y, A, X)
173-
@inbounds @views for i = 1:size(X, 2)
174-
mul!(Y[:, i], A, X[:, i], α, β)
158+
"""
159+
mul!(Y, A::LinearMap, B) -> Y
160+
161+
Calculates the action of the linear map `A` on the vector or matrix `B` and stores the result in `Y`,
162+
overwriting the existing value of `Y`. Note that `Y` must not be aliased with either `A` or `B`.
163+
164+
## Examples
165+
```jldoctest; setup=(using LinearAlgebra, LinearMaps)
166+
julia> A=LinearMap([1.0 2.0; 3.0 4.0]); B=[1.0, 1.0]; Y = similar(B); mul!(Y, A, B);
167+
168+
julia> Y
169+
2-element Array{Float64,1}:
170+
3.0
171+
7.0
172+
173+
julia> A=LinearMap([1.0 2.0; 3.0 4.0]); B=[1.0 1.0; 1.0 1.0]; Y = similar(B); mul!(Y, A, B);
174+
175+
julia> Y
176+
2×2 Array{Float64,2}:
177+
3.0 3.0
178+
7.0 7.0
179+
```
180+
"""
181+
function mul!(Y::AbstractMatrix, A::LinearMap, X::AbstractMatrix)
182+
check_dim_mul(Y, A, X)
183+
return _generic_mapmat_mul!(Y, A, X)
184+
end
185+
function mul!(Y::AbstractMatrix, A::LinearMap, X::AbstractMatrix, α::Number, β::Number)
186+
check_dim_mul(Y, A, X)
187+
return _generic_mapmat_mul!(Y, A, X, α, β)
188+
end
189+
190+
function _generic_mapmat_mul!(Y, A, X, α=true, β=false)
191+
@views for i in 1:size(X, 2)
192+
_unsafe_mul!(Y[:, i], A, X[:, i], α, β)
175193
end
176194
# starting from Julia v1.1, we could use the `eachcol` iterator
177195
# for (Xi, Yi) in zip(eachcol(X), eachcol(Y))
@@ -180,14 +198,19 @@ Base.@propagate_inbounds function LinearAlgebra.mul!(Y::AbstractMatrix, A::Linea
180198
return Y
181199
end
182200

183-
A_mul_B!(y::AbstractVector, A::AbstractMatrix, x::AbstractVector) = mul!(y, A, x)
184-
At_mul_B!(y::AbstractVector, A::AbstractMatrix, x::AbstractVector) = mul!(y, transpose(A), x)
185-
Ac_mul_B!(y::AbstractVector, A::AbstractMatrix, x::AbstractVector) = mul!(y, adjoint(A), x)
201+
_unsafe_mul!(y, A::MapOrMatrix, x) = mul!(y, A, x)
202+
_unsafe_mul!(y, A::AbstractMatrix, x, α, β) = mul!(y, A, x, α, β)
203+
function _unsafe_mul!(y::AbstractVecOrMat, A::LinearMap, x::AbstractVector, α, β)
204+
return _generic_mapvec_mul!(y, A, x, α, β)
205+
end
206+
function _unsafe_mul!(y::AbstractMatrix, A::LinearMap, x::AbstractMatrix, α, β)
207+
return _generic_mapmat_mul!(y, A, x, α, β)
208+
end
186209

187210
include("left.jl") # left multiplication by a transpose or adjoint vector
211+
include("transpose.jl") # transposing linear maps
188212
include("wrappedmap.jl") # wrap a matrix of linear map in a new type, thereby allowing to alter its properties
189213
include("uniformscalingmap.jl") # the uniform scaling map, to be able to make linear combinations of LinearMap objects and multiples of I
190-
include("transpose.jl") # transposing linear maps
191214
include("linearcombination.jl") # defining linear combinations of linear maps
192215
include("scaledmap.jl") # multiply by a (real or complex) scalar
193216
include("composition.jl") # composition of linear maps

0 commit comments

Comments
 (0)