@@ -41,11 +41,13 @@ julia> Matrix(Δ)
41
41
0 1 1 -4
42
42
```
43
43
"""
44
- # Base.kron(A::LinearMap, B::LinearMap) = KroneckerMap{promote_type(eltype(A), eltype(B))}((A, B))
45
- # Base.kron(A::LinearMap{TA}, B::LinearMap{TB}) where {TA,TB} = KroneckerMap{promote_type(TA,TB)}((A, B))
46
- Base. kron (As:: LinearMap... ) = KroneckerMap {promote_type(map(eltype, As)...)} (tuple (As... ))
47
- Base. kron (A:: LinearMap , B:: AbstractArray ) = kron (A, LinearMap (B))
48
- Base. kron (A:: AbstractArray , B:: LinearMap ) = kron (LinearMap (A), B)
44
+ Base. kron (A:: LinearMap , B:: LinearMap ) = KroneckerMap {promote_type(eltype(A), eltype(B))} ((A, B))
45
+ Base. kron (A:: LinearMap , B:: KroneckerMap ) = KroneckerMap {promote_type(eltype(A), eltype(B))} (tuple (A, B. maps... ))
46
+ Base. kron (A:: KroneckerMap , B:: LinearMap ) = KroneckerMap {promote_type(eltype(A), eltype(B))} (tuple (A. maps... , B))
47
+ Base. kron (A:: KroneckerMap , B:: KroneckerMap ) = KroneckerMap {promote_type(eltype(A), eltype(B))} (tuple (A. maps... , B. maps... ))
48
+ Base. kron (A:: LinearMap , B:: LinearMap , Cs:: LinearMap... ) = KroneckerMap {promote_type(eltype(A), eltype(B), map(eltype, Cs)...)} (tuple (A, B, Cs... ))
49
+ Base. kron (A:: AbstractMatrix , B:: LinearMap ) = kron (LinearMap (A), B)
50
+ Base. kron (A:: LinearMap , B:: AbstractMatrix ) = kron (A, LinearMap (B))
49
51
# promote AbstractMatrix arguments to LinearMaps, then take LinearMap-Kronecker product
50
52
for k in 3 : 8 # is 8 sufficient?
51
53
Is = ntuple (n-> :($ (Symbol (:A ,n)):: AbstractMatrix ), Val (k- 1 ))
@@ -75,14 +77,6 @@ LinearAlgebra.ishermitian(A::KroneckerMap) = all(ishermitian, A.maps)
75
77
LinearAlgebra. adjoint (A:: KroneckerMap{T} ) where {T} = KroneckerMap {T} (map (adjoint, A. maps))
76
78
LinearAlgebra. transpose (A:: KroneckerMap{T} ) where {T} = KroneckerMap {T} (map (transpose, A. maps))
77
79
78
- function Base.:(* )(A:: KroneckerMap , B:: KroneckerMap )
79
- if length (A. maps) == length (B. maps) && all (M -> size (M[1 ], 2 ) == size (M[2 ], 1 ), zip (A. maps, B. maps))
80
- return kron (map (prod, zip (A. maps, B. maps))... )
81
- else
82
- return CompositeMap {T} (tuple (B, A))
83
- end
84
- end
85
-
86
80
Base.:(== )(A:: KroneckerMap , B:: KroneckerMap ) = (eltype (A) == eltype (B) && A. maps == B. maps)
87
81
88
82
function LinearMaps. A_mul_B! (y:: AbstractVector , L:: KroneckerMap{T,<:NTuple{2,LinearMap}} , x:: AbstractVector ) where {T}
@@ -102,6 +96,30 @@ function LinearMaps.A_mul_B!(y::AbstractVector, L::KroneckerMap{T}, x::AbstractV
102
96
_kronmul! (y, B, X, transpose (A), T)
103
97
return y
104
98
end
99
+ # mixed-product rule, prefer the right if possible
100
+ # (A₁ ⊗ A₂ ⊗ ... ⊗ Aᵣ) * (B₁ ⊗ B₂ ⊗ ... ⊗ Bᵣ) = (A₁B₁) ⊗ (A₂B₂) ⊗ ... ⊗ (AᵣBᵣ)
101
+ function A_mul_B! (y:: AbstractVector , L:: CompositeMap{<:Any,<:Tuple{KroneckerMap,KroneckerMap}} , x:: AbstractVector )
102
+ B, A = L. maps
103
+ if length (A. maps) == length (B. maps) && all (M -> check_dim_mul (M[1 ], M[2 ]), zip (A. maps, B. maps))
104
+ A_mul_B! (y, kron (map (prod, zip (A. maps, B. maps))... ), x)
105
+ else
106
+ A_mul_B! (y, LinearMap (A)* B, x)
107
+ end
108
+ end
109
+ # mixed-product rule, prefer the right if possible
110
+ # (A₁ ⊗ B₁)*(A₂⊗B₂)*...*(Aᵣ⊗Bᵣ) = (A₁*A₂*...*Aᵣ) ⊗ (B₁*B₂*...*Bᵣ)
111
+ function A_mul_B! (y:: AbstractVector , L:: CompositeMap {T,<: Tuple {Vararg{KroneckerMap{<: Any ,<: Tuple{LinearMap,LinearMap} }}}}, x:: AbstractVector ) where {T}
112
+ As = map (AB -> AB. maps[1 ], L. maps)
113
+ Bs = map (AB -> AB. maps[2 ], L. maps)
114
+ As1, As2 = Base. front (As), Base. tail (As)
115
+ Bs1, Bs2 = Base. front (Bs), Base. tail (Bs)
116
+ apply = all (A -> check_dim_mul (A... ), zip (As1, As2)) && all (A -> check_dim_mul (A... ), zip (Bs1, Bs2))
117
+ if apply
118
+ A_mul_B! (y, kron (prod (As), prod (Bs)), x)
119
+ else
120
+ A_mul_B! (y, CompositeMap {T} (map (LinearMap, L. maps)), x)
121
+ end
122
+ end
105
123
106
124
function _kronmul! (y, B, X, At, T)
107
125
na, ma = size (At)
0 commit comments