diff --git a/src/auxiliary.jl b/src/auxiliary.jl index 6ed53605..3d7f0ec5 100644 --- a/src/auxiliary.jl +++ b/src/auxiliary.jl @@ -13,10 +13,23 @@ function _kron(A, B) end return C end -_kron_promote(A::Number, B::Number, _, _) = A * B -function _kron_promote(A₁, B₁, sz₁, sz₂) - return _kron(A₁ isa Number ? fill(A₁, sz₁) : A₁, B₁ isa Number ? fill(B₁, sz₂) : B₁) +# combine the symbols `A` and `B` of the factors `a` and `b` of product sectors; a scalar symbol +# is promoted to an array of the same kind as the other symbol, with the size given by the +# multiplicities of its sectors, unless these are all one: then it just scales the other symbol, +# which is returned as is for a scalar one (symbols are not mutated, and may already be shared +# with a cache); the type of the result thus only depends on the types of the symbols +_kron_promote(A::Number, B::Number, a, b) = A * B +function _kron_promote(A::Number, B::AbstractArray, a, b) + sz = _symbol_size(a) + all(isone, sz) || return _kron(fill!(similar(B, typeof(A), sz), A), B) + return isone(A) && promote_type(typeof(A), eltype(B)) === eltype(B) ? B : A * B end +function _kron_promote(A::AbstractArray, B::Number, a, b) + sz = _symbol_size(b) + all(isone, sz) || return _kron(A, fill!(similar(A, typeof(B), sz), B)) + return isone(B) && promote_type(eltype(A), typeof(B)) === eltype(A) ? A : A * B +end +_kron_promote(A::AbstractArray, B::AbstractArray, a, b) = _kron(A, B) # Manhattan based distance enumeration: I is supposed to be one-based index # TODO: is there any way to make this faster? diff --git a/src/product.jl b/src/product.jl index b0ed5554..6848b617 100644 --- a/src/product.jl +++ b/src/product.jl @@ -96,82 +96,80 @@ _symbol_size((a, b, c, d, e, f)::NTuple{6, Sector}) = (Nsymbol(a, b, e), Nsymbol @inline function _kron_promote_inputs(sectors) heads = map(_firstsector, sectors) tails = map(_tailsector, sectors) - sz₁ = _symbol_size(heads) - sz₂ = _symbol_size(tails) - return heads, tails, sz₁, sz₂ + return heads, tails end function Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: ProductSector} - heads, tails, sz₁, sz₂ = _kron_promote_inputs((a, b, c, d, e, f)) + heads, tails = _kron_promote_inputs((a, b, c, d, e, f)) V₁ = Fsymbol(heads...) V₂ = Fsymbol(tails...) - return _kron_promote(V₁, V₂, sz₁, sz₂) + return _kron_promote(V₁, V₂, heads, tails) end function Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: ProductSector{<:Tuple{Sector}}} return Fsymbol(map(_firstsector, (a, b, c, d, e, f))...) end function Fsymbol_from_fusiontensor(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: ProductSector} - heads, tails, sz₁, sz₂ = _kron_promote_inputs((a, b, c, d, e, f)) + heads, tails = _kron_promote_inputs((a, b, c, d, e, f)) V₁ = Fsymbol_from_fusiontensor(heads...) V₂ = Fsymbol_from_fusiontensor(tails...) - return _kron_promote(V₁, V₂, sz₁, sz₂) + return _kron_promote(V₁, V₂, heads, tails) end function Fsymbol_from_fusiontensor(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: ProductSector{<:Tuple{Sector}}} return Fsymbol_from_fusiontensor(map(_firstsector, (a, b, c, d, e, f))...) end function Rsymbol(a::I, b::I, c::I) where {I <: ProductSector} - heads, tails, sz₁, sz₂ = _kron_promote_inputs((a, b, c)) + heads, tails = _kron_promote_inputs((a, b, c)) V₁ = Rsymbol(heads...) V₂ = Rsymbol(tails...) - return _kron_promote(V₁, V₂, sz₁, sz₂) + return _kron_promote(V₁, V₂, heads, tails) end function Rsymbol(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Rsymbol(map(_firstsector, (a, b, c))...) end function Rsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector} - heads, tails, sz₁, sz₂ = _kron_promote_inputs((a, b, c)) + heads, tails = _kron_promote_inputs((a, b, c)) V₁ = Rsymbol_from_fusiontensor(heads...) V₂ = Rsymbol_from_fusiontensor(tails...) - return _kron_promote(V₁, V₂, sz₁, sz₂) + return _kron_promote(V₁, V₂, heads, tails) end function Rsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Rsymbol_from_fusiontensor(map(_firstsector, (a, b, c))...) end function Bsymbol(a::I, b::I, c::I) where {I <: ProductSector} - heads, tails, sz₁, sz₂ = _kron_promote_inputs((a, b, c)) + heads, tails = _kron_promote_inputs((a, b, c)) V₁ = Bsymbol(heads...) V₂ = Bsymbol(tails...) - return _kron_promote(V₁, V₂, sz₁, sz₂) + return _kron_promote(V₁, V₂, heads, tails) end function Bsymbol(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Bsymbol(map(_firstsector, (a, b, c))...) end function Bsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector} - heads, tails, sz₁, sz₂ = _kron_promote_inputs((a, b, c)) + heads, tails = _kron_promote_inputs((a, b, c)) V₁ = Bsymbol_from_fusiontensor(heads...) V₂ = Bsymbol_from_fusiontensor(tails...) - return _kron_promote(V₁, V₂, sz₁, sz₂) + return _kron_promote(V₁, V₂, heads, tails) end function Bsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Bsymbol_from_fusiontensor(map(_firstsector, (a, b, c))...) end function Asymbol(a::I, b::I, c::I) where {I <: ProductSector} - heads, tails, sz₁, sz₂ = _kron_promote_inputs((a, b, c)) + heads, tails = _kron_promote_inputs((a, b, c)) V₁ = Asymbol(heads...) V₂ = Asymbol(tails...) - return _kron_promote(V₁, V₂, sz₁, sz₂) + return _kron_promote(V₁, V₂, heads, tails) end function Asymbol(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Asymbol(map(_firstsector, (a, b, c))...) end function Asymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector} - heads, tails, sz₁, sz₂ = _kron_promote_inputs((a, b, c)) + heads, tails = _kron_promote_inputs((a, b, c)) V₁ = Asymbol_from_fusiontensor(heads...) V₂ = Asymbol_from_fusiontensor(tails...) - return _kron_promote(V₁, V₂, sz₁, sz₂) + return _kron_promote(V₁, V₂, heads, tails) end function Asymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Asymbol_from_fusiontensor(map(_firstsector, (a, b, c))...)