@@ -56,6 +56,8 @@ Base.kron(A::KroneckerMap, B::KroneckerMap) =
56
56
Base. kron (A:: ScaledMap , B:: LinearMap ) = A. λ * kron (A. lmap, B)
57
57
Base. kron (A:: LinearMap , B:: ScaledMap ) = kron (A, B. lmap) * B. λ
58
58
Base. kron (A:: ScaledMap , B:: ScaledMap ) = (A. λ * B. λ) * kron (A. lmap, B. lmap)
59
+ # reduce UniformScalingMaps
60
+ Base. kron (A:: UniformScalingMap , B:: UniformScalingMap ) = UniformScalingMap (A. λ * B. λ, A. M * B. M)
59
61
# disambiguation
60
62
Base. kron (A:: ScaledMap , B:: KroneckerMap ) = A. λ * kron (A. lmap, B)
61
63
Base. kron (A:: KroneckerMap , B:: ScaledMap ) = kron (A, B. lmap) * B. λ
@@ -112,44 +114,46 @@ Base.:(==)(A::KroneckerMap, B::KroneckerMap) = (eltype(A) == eltype(B) && A.maps
112
114
# multiplication helper functions
113
115
# ################
114
116
115
- @inline function _kronmul! (y, B, x, At , T)
116
- na, ma = size (At )
117
+ @inline function _kronmul! (y, B, x, A , T)
118
+ ma, na = size (A )
117
119
mb, nb = size (B)
118
120
X = reshape (x, (nb, na))
119
- v = zeros (T, ma)
120
- temp1 = similar (y, na)
121
- temp2 = similar (y, nb)
122
- @views @inbounds for i in 1 : ma
123
- v[i] = one (T)
124
- _unsafe_mul! (temp1, At, v)
125
- _unsafe_mul! (temp2, X, temp1)
126
- _unsafe_mul! (y[((i- 1 )* mb+ 1 ): i* mb], B, temp2)
127
- v[i] = zero (T)
121
+ Y = reshape (y, (mb, ma))
122
+ if B isa UniformScalingMap
123
+ _unsafe_mul! (Y, X, transpose (A))
124
+ lmul! (B. λ, y)
125
+ else
126
+ temp = similar (Y, (ma, nb))
127
+ _unsafe_mul! (temp, A, copy (transpose (X)))
128
+ _unsafe_mul! (Y, B, transpose (temp))
128
129
end
129
130
return y
130
131
end
131
- @inline function _kronmul! (y, B, x, At :: UniformScalingMap , _)
132
- na, ma = size (At )
132
+ @inline function _kronmul! (y, B, x, A :: UniformScalingMap , _)
133
+ ma, na = size (A )
133
134
mb, nb = size (B)
135
+ iszero (A. λ) && return fill! (y, zero (eltype (y)))
134
136
X = reshape (x, (nb, na))
135
137
Y = reshape (y, (mb, ma))
136
- _unsafe_mul! (Y, B, X, At. λ, false )
138
+ _unsafe_mul! (Y, B, X)
139
+ ! isone (A. λ) && rmul! (y, A. λ)
137
140
return y
138
141
end
139
- @inline function _kronmul! (y, B, x, At :: MatrixMap , _)
140
- na, ma = size (At )
142
+ @inline function _kronmul! (y, B, x, A :: MatrixMap , _)
143
+ ma, na = size (A )
141
144
mb, nb = size (B)
142
145
X = reshape (x, (nb, na))
143
146
Y = reshape (y, (mb, ma))
147
+ At = transpose (A. lmap)
144
148
if B isa UniformScalingMap
145
- # the following is (maybe due to the reshape?) faster than
146
- # _unsafe_mul!(Y, B * X, At.lmap )
147
- _unsafe_mul! (Y, X, At. lmap )
149
+ # the following is (perhaps due to the reshape?) faster than
150
+ # _unsafe_mul!(Y, B * X, At)
151
+ _unsafe_mul! (Y, X, At)
148
152
lmul! (B. λ, y)
149
153
elseif nb* ma <= mb* na
150
- _unsafe_mul! (Y, B, X * At. lmap )
154
+ _unsafe_mul! (Y, B, X * At)
151
155
else
152
- _unsafe_mul! (Y, Matrix (B* X), At. lmap )
156
+ _unsafe_mul! (Y, Matrix (B* X), At)
153
157
end
154
158
return y
155
159
end
@@ -163,14 +167,14 @@ const KroneckerMap2{T} = KroneckerMap{T, <:Tuple{LinearMap, LinearMap}}
163
167
function _unsafe_mul! (y:: AbstractVecOrMat , L:: KroneckerMap2 , x:: AbstractVector )
164
168
require_one_based_indexing (y)
165
169
A, B = L. maps
166
- _kronmul! (y, B, x, transpose (A) , eltype (L))
170
+ _kronmul! (y, B, x, A , eltype (L))
167
171
return y
168
172
end
169
173
function _unsafe_mul! (y:: AbstractVecOrMat , L:: KroneckerMap , x:: AbstractVector )
170
174
require_one_based_indexing (y)
171
175
A = first (L. maps)
172
176
B = kron (Base. tail (L. maps)... )
173
- _kronmul! (y, B, x, transpose (A) , eltype (L))
177
+ _kronmul! (y, B, x, A , eltype (L))
174
178
return y
175
179
end
176
180
# mixed-product rule, prefer the right if possible
0 commit comments