|
13 | 13 |
|
14 | 14 | LinearCombination{T}(maps::As) where {T, As} = LinearCombination{T, As}(maps) |
15 | 15 |
|
| 16 | +MulStyle(A::LinearCombination) = MulStyle(A.maps...) |
| 17 | + |
16 | 18 | # basic methods |
17 | 19 | Base.size(A::LinearCombination) = size(A.maps[1]) |
18 | 20 | LinearAlgebra.issymmetric(A::LinearCombination) = all(issymmetric, A.maps) # sufficient but not necessary |
@@ -61,84 +63,50 @@ Base.:(==)(A::LinearCombination, B::LinearCombination) = (eltype(A) == eltype(B) |
61 | 63 | LinearAlgebra.transpose(A::LinearCombination) = LinearCombination{eltype(A)}(map(transpose, A.maps)) |
62 | 64 | LinearAlgebra.adjoint(A::LinearCombination) = LinearCombination{eltype(A)}(map(adjoint, A.maps)) |
63 | 65 |
|
64 | | -# multiplication with vectors |
65 | | -if VERSION < v"1.3.0-alpha.115" |
66 | | - |
67 | | -function A_mul_B!(y::AbstractVector, A::LinearCombination, x::AbstractVector) |
68 | | - # no size checking, will be done by individual maps |
69 | | - A_mul_B!(y, A.maps[1], x) |
70 | | - l = length(A.maps) |
71 | | - if l>1 |
72 | | - z = similar(y) |
73 | | - for n in 2:l |
74 | | - A_mul_B!(z, A.maps[n], x) |
75 | | - y .+= z |
| 66 | +# multiplication with vectors & matrices |
| 67 | +for Atype in (AbstractVector, AbstractMatrix) |
| 68 | + @eval Base.@propagate_inbounds function LinearAlgebra.mul!(y::$Atype, A::LinearCombination, x::$Atype, |
| 69 | + α::Number=true, β::Number=false) |
| 70 | + @boundscheck check_dim_mul(y, A, x) |
| 71 | + if iszero(α) # trivial cases |
| 72 | + iszero(β) && (fill!(y, zero(eltype(y))); return y) |
| 73 | + isone(β) && return y |
| 74 | + # β != 0, 1 |
| 75 | + rmul!(y, β) |
| 76 | + return y |
| 77 | + else |
| 78 | + mul!(y, first(A.maps), x, α, β) |
| 79 | + return _mul!(MulStyle(A), y, A, x, α, β) |
76 | 80 | end |
77 | 81 | end |
78 | | - return y |
79 | 82 | end |
80 | 83 |
|
81 | | -else # 5-arg mul! is available for matrices |
82 | | - |
83 | | -# map types that have an allocation-free 5-arg mul! implementation |
84 | | -const FreeMap = Union{MatrixMap,UniformScalingMap} |
85 | | - |
86 | | -function A_mul_B!(y::AbstractVector, A::LinearCombination{T,As}, x::AbstractVector) where {T, As<:Tuple{Vararg{FreeMap}}} |
87 | | - # no size checking, will be done by individual maps |
88 | | - A_mul_B!(y, A.maps[1], x) |
89 | | - for n in 2:length(A.maps) |
90 | | - mul!(y, A.maps[n], x, true, true) |
91 | | - end |
92 | | - return y |
93 | | -end |
94 | | -function A_mul_B!(y::AbstractVector, A::LinearCombination, x::AbstractVector) |
95 | | - # no size checking, will be done by individual maps |
96 | | - A_mul_B!(y, A.maps[1], x) |
97 | | - l = length(A.maps) |
98 | | - if l>1 |
99 | | - z = similar(y) |
100 | | - for n in 2:l |
101 | | - An = A.maps[n] |
102 | | - if An isa FreeMap |
103 | | - mul!(y, An, x, true, true) |
104 | | - else |
105 | | - A_mul_B!(z, A.maps[n], x) |
106 | | - y .+= z |
107 | | - end |
108 | | - end |
109 | | - end |
110 | | - return y |
| 84 | +@inline _mul!(::FiveArg, y, A::LinearCombination, x, α::Number, β::Number) = |
| 85 | + __mul!(y, Base.tail(A.maps), x, α, nothing) |
| 86 | +@inline function _mul!(::ThreeArg, y, A::LinearCombination, x, α::Number, β::Number) |
| 87 | + z = similar(y) |
| 88 | + __mul!(y, Base.tail(A.maps), x, α, z) |
111 | 89 | end |
112 | 90 |
|
113 | | -function LinearAlgebra.mul!(y::AbstractVector, A::LinearCombination{T,As}, x::AbstractVector, α::Number=true, β::Number=false) where {T, As<:Tuple{Vararg{FreeMap}}} |
114 | | - length(y) == size(A, 1) || throw(DimensionMismatch("mul!")) |
115 | | - if isone(α) |
116 | | - iszero(β) && (A_mul_B!(y, A, x); return y) |
117 | | - !isone(β) && rmul!(y, β) |
118 | | - elseif iszero(α) |
119 | | - iszero(β) && (fill!(y, zero(eltype(y))); return y) |
120 | | - isone(β) && return y |
121 | | - # β != 0, 1 |
122 | | - rmul!(y, β) |
123 | | - return y |
124 | | - else # α != 0, 1 |
125 | | - if iszero(β) |
126 | | - A_mul_B!(y, A, x) |
127 | | - rmul!(y, α) |
128 | | - return y |
129 | | - elseif !isone(β) |
130 | | - rmul!(y, β) |
131 | | - end # β-cases |
132 | | - end # α-cases |
| 91 | +@inline __mul!(y, As::Tuple{Vararg{LinearMap}}, x, α, z) = |
| 92 | + __mul!(__mul!(y, first(As), x, α, z), Base.tail(As), x, α, z) |
| 93 | +@inline __mul!(y, A::Tuple{LinearMap}, x, α, z) = __mul!(y, first(A), x, α, z) |
| 94 | +@inline __mul!(y, A::LinearMap, x, α, z) = muladd!(MulStyle(A), y, A, x, α, z) |
133 | 95 |
|
134 | | - for An in A.maps |
135 | | - mul!(y, An, x, α, true) |
| 96 | +@inline muladd!(::FiveArg, y, A, x, α, _) = mul!(y, A, x, α, true) |
| 97 | +@inline function muladd!(::ThreeArg, y, A, x, α, z) |
| 98 | + # TODO: replace by mul!(z, A, x) |
| 99 | + A_mul_B!(z, A, x) |
| 100 | + if isone(α) |
| 101 | + y .+= z |
| 102 | + else |
| 103 | + y .+= z .* α |
136 | 104 | end |
137 | 105 | return y |
138 | 106 | end |
139 | 107 |
|
140 | | -end # VERSION |
| 108 | +A_mul_B!(y::AbstractVector, A::LinearCombination, x::AbstractVector) = mul!(y, A, x) |
141 | 109 |
|
142 | | -At_mul_B!(y::AbstractVector, A::LinearCombination, x::AbstractVector) = A_mul_B!(y, transpose(A), x) |
| 110 | +At_mul_B!(y::AbstractVector, A::LinearCombination, x::AbstractVector) = mul!(y, transpose(A), x) |
143 | 111 |
|
144 | | -Ac_mul_B!(y::AbstractVector, A::LinearCombination, x::AbstractVector) = A_mul_B!(y, adjoint(A), x) |
| 112 | +Ac_mul_B!(y::AbstractVector, A::LinearCombination, x::AbstractVector) = mul!(y, adjoint(A), x) |
0 commit comments