Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions ext/TensorAlgebraTensorKitExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,29 @@ end
struct TensorKitMatricize <: TensorAlgebra.MatricizeStyle end
TensorAlgebra.MatricizeStyle(::Type{<:AbstractTensorMap}) = TensorKitMatricize()

function TensorAlgebra.matricize(
# `permute` at the tensor's own codomain/domain split is trivial and returns `t` itself, so
# the matching split is the one memory-sharing matricization (TensorKit's own
# `has_shared_permute` notion); any other split regroups into a fresh `TensorMap`.
function TensorAlgebra.ismatricizeview(
::TensorKitMatricize, ::AbstractTensorMap{<:Any, <:Any, K}, ::Val{K}
) where {K}
return true
end
TensorAlgebra.ismatricizeview(::TensorKitMatricize, ::AbstractTensorMap, ::Val) = false
function TensorAlgebra.matricizeview(
::TensorKitMatricize, t::AbstractTensorMap{<:Any, <:Any, K}, ::Val{K}
) where {K}
return t
end
function TensorAlgebra.matricizecopy(
::TensorKitMatricize, t::AbstractTensorMap, ndims_codomain::Val{K}
) where {K}
N = numind(t)
return permute(t, (ntuple(identity, Val(K)), ntuple(i -> K + i, Val(N - K))))
return permute(
t,
(ntuple(identity, Val(K)), ntuple(i -> K + i, Val(N - K)));
copy = true
)
end

# The identity fill on the regrouped map is TensorKit's own `one!` (MatrixAlgebraKit's
Expand Down
34 changes: 13 additions & 21 deletions src/contract/contract_matricize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,24 @@ function contractopadd!(
algorithm.right_matricize_style, op2, a2, biperm2_codomain, biperm2_domain
)
output_style = algorithm.output_matricize_style
if iszero(β) && !matricizepermaliases(output_style, invperm_codomain, invperm_domain)
# `β` is a strong zero and matricizing `a_dest` would only build a detached copy that
# `mul!` immediately overwrites, so skip that gather: let the matmul allocate its matrix
# result directly and scatter it into `a_dest`. Every coupled-sector block is
# materialized (the matmul zeros the ones it does not reach), so the scatter overwrites
# `a_dest` in full.
if ismatricizeview(output_style, a_dest, invperm_codomain, invperm_domain)
# The matricization shares `a_dest`'s memory, so the matmul is the whole operation.
a_dest_mat = matricizeview(output_style, a_dest, Val(length(invperm_codomain)))
mul!(a_dest_mat, a1_mat, a2_mat, α, β)
elseif iszero(β)
# `β` is a strong zero, so `a_dest`'s current data is irrelevant: let the matmul
# allocate its matrix result and scatter it into `a_dest`. Every coupled-sector block
# is materialized (the matmul zeros the ones it does not reach), so the scatter
# overwrites `a_dest` in full.
a_dest_mat = a1_mat * a2_mat
isone(α) || scale!(a_dest_mat, α)
unmatricizeperm!(output_style, a_dest, a_dest_mat, invperm_codomain, invperm_domain)
else
# Matricize the destination and multiply straight into it: a no-op for an aligned or
# transposed dense output (a view aliasing `a_dest`, so `mul!` writes through and we
# are done), a fresh permuted copy otherwise. Either way `matricize` seeds `a_dest_mat`
# with `a_dest`'s current contents, so `β` rides on the `mul!` and a detached copy is
# written back with a plain overwrite.
a_dest_mat = matricizeperm(output_style, a_dest, invperm_codomain, invperm_domain)
# `a_dest`'s data contributes through `β`, so gather it, multiply into the gathered
# copy, and scatter back.
a_dest_mat = matricizecopy(output_style, a_dest, invperm_codomain, invperm_domain)
mul!(a_dest_mat, a1_mat, a2_mat, α, β)
if !Base.mightalias(a_dest_mat, a_dest)
unmatricizeperm!(
output_style,
a_dest,
a_dest_mat,
invperm_codomain,
invperm_domain
)
end
unmatricizeperm!(output_style, a_dest, a_dest_mat, invperm_codomain, invperm_domain)
end
return a_dest
end
5 changes: 3 additions & 2 deletions src/diagonal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ function allocate_output(
end

# A `Diagonal` is already a matrix; the `(1 codomain, 1 domain)` matricization is the identity
# reshape, so return it directly (maybe-alias, matching `matricize`'s general contract).
matricize(::ReshapeMatricize, a::Diagonal, ::Val{1}) = a
# reshape, so the memory-sharing matricization is `a` itself (keeping it a `Diagonal` for the
# `Diagonal`-specialized consumers downstream).
matricizeview(::ReshapeMatricize, a::Diagonal, ::Val{1}) = a
# A `{1,1}` unmatricize (one codomain axis, one domain axis) is the endomorphism identity: the
# result stays `Diagonal`, so return `m` directly. The generic `check_input(unmatricize, ...)`
# validates the axis lengths against `m`'s size.
Expand Down
Loading
Loading