Skip to content

Commit 7d3fd12

Browse files
authored
Removal of the evil hacks (#42)
* remove evil hack * remove unnecessary overload * rework TensorOperations implementations * remove unnecessary functions * add VectorInterface specializations * add `compose_dest` specializations * bump version
1 parent 68c83b8 commit 7d3fd12

4 files changed

Lines changed: 62 additions & 166 deletions

File tree

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "BlockTensorKit"
22
uuid = "5f87ffc2-9cf1-4a46-8172-465d160bd8cd"
3-
version = "0.3.5"
3+
version = "0.3.6"
44
authors = ["Lukas Devos <ldevos98@gmail.com> and contributors"]
55

66
[deps]
@@ -25,7 +25,7 @@ MatrixAlgebraKit = "0.6"
2525
Random = "1"
2626
SafeTestsets = "0.1"
2727
Strided = "2"
28-
TensorKit = "0.16"
28+
TensorKit = "0.16.1"
2929
TensorOperations = "5"
3030
Test = "1"
3131
TestExtras = "0.2, 0.3"

src/linalg/linalg.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,23 @@ function LinearAlgebra.mul!(C::BlockTensorMap, α::Number, A::BlockTensorMap)
5151
return C
5252
end
5353

54+
for TA in (:AbstractBlockTensorMap, :(TK.DiagonalTensorMap), :(TK.AdjointTensorMap), :TensorMap),
55+
TB in (:AbstractBlockTensorMap, :(TK.DiagonalTensorMap), :(TK.AdjointTensorMap), :TensorMap)
56+
(TA === :AbstractBlockTensorMap || TB === :AbstractBlockTensorMap) || continue
57+
@eval function TK.compose_dest(A::$TA, B::$TB)
58+
S = TK.check_spacetype(A, B)
59+
TC = TO.promote_contract(scalartype(A), scalartype(B), One)
60+
M = TK.promote_storagetype(TK.similarstoragetype(A, TC), TK.similarstoragetype(B, TC))
61+
TTC = if issparse(A) && issparse(B)
62+
sparseblocktensormaptype(S, numout(A), numin(B), M)
63+
else
64+
blocktensormaptype(S, numout(A), numin(B), M)
65+
end
66+
structure = codomain(A) domain(B)
67+
return TO.tensoralloc(TTC, structure, Val(false))
68+
end
69+
end
70+
5471
# This is a generic implementation of `mul!` for BlockTensors that is used to make it easier
5572
# to work with abstract element types, that might not support in-place operations.
5673
# For now, the implementation might not be hyper-optimized, but the assumption is that we

src/tensors/tensoroperations.jl

Lines changed: 21 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,14 @@
1-
@noinline function _check_spacetype(
2-
::Type{S₁}, ::Type{S₂}
3-
) where {S₁ <: ElementarySpace, S₂ <: ElementarySpace}
4-
S₁ === S₂ ||
5-
S₁ === SumSpace{S₂} ||
6-
SumSpace{S₁} === S₂ ||
7-
throw(SpaceMismatch(lazy"incompatible spacetypes: $S₁ and $S₂"))
8-
return nothing
9-
end
10-
111
# TensorOperations
122
# ----------------
133
function TO.tensoradd_type(
144
TC, A::AbstractBlockTensorMap, ::Index2Tuple{N₁, N₂}, ::Bool
155
) where {N₁, N₂}
16-
TA = eltype(A)
17-
I = sectortype(A)
18-
Tnew = sectorscalartype(I) <: Real ? TC : complex(TC)
19-
if TA isa Union
20-
M = Union{TK.similarstoragetype(TA.a, Tnew), TK.similarstoragetype(TA.b, Tnew)}
21-
else
22-
M = TK.similarstoragetype(TA, Tnew)
23-
end
6+
S = spacetype(A)
7+
M = TK.similarstoragetype(A, TK.promote_permute(TC, sectortype(S)))
248
return if issparse(A)
25-
sparseblocktensormaptype(spacetype(A), N₁, N₂, M)
9+
sparseblocktensormaptype(S, N₁, N₂, M)
2610
else
27-
blocktensormaptype(spacetype(A), N₁, N₂, M)
11+
blocktensormaptype(S, N₁, N₂, M)
2812
end
2913
end
3014
function TO.tensoradd_type(TC, A::AdjointBlockTensorMap, pA::Index2Tuple, conjA::Bool)
@@ -33,58 +17,22 @@ end
3317

3418
# tensoralloc_contract
3519
# --------------------
36-
function TO.tensorcontract_type(
37-
TC,
38-
A::AbstractBlockTensorMap, ::Index2Tuple, ::Bool,
39-
B::AbstractBlockTensorMap, ::Index2Tuple, ::Bool,
40-
::Index2Tuple{N₁, N₂},
41-
) where {N₁, N₂}
42-
_check_spacetype(spacetype(A), spacetype(B))
43-
44-
I = sectortype(A)
45-
Tnew = sectorscalartype(I) <: Real ? TC : complex(TC)
46-
M = promote_storagetype(Tnew, eltype(A), eltype(B))
47-
48-
return if issparse(A) && issparse(B)
49-
sparseblocktensormaptype(spacetype(A), N₁, N₂, M)
50-
else
51-
blocktensormaptype(spacetype(A), N₁, N₂, M)
52-
end
53-
end
54-
function TO.tensorcontract_type(
55-
TC,
56-
A::AbstractTensorMap, pA::Index2Tuple, conjA::Bool,
57-
B::AbstractBlockTensorMap, pB::Index2Tuple, conjB::Bool,
58-
pAB::Index2Tuple{N₁, N₂},
59-
) where {N₁, N₂}
60-
_check_spacetype(spacetype(A), spacetype(B))
61-
62-
I = sectortype(A)
63-
Tnew = sectorscalartype(I) <: Real ? TC : complex(TC)
64-
M = promote_storagetype(Tnew, typeof(A), eltype(B))
65-
66-
return if issparse(A) && issparse(B)
67-
sparseblocktensormaptype(spacetype(A), N₁, N₂, M)
68-
else
69-
blocktensormaptype(spacetype(A), N₁, N₂, M)
70-
end
71-
end
72-
function TO.tensorcontract_type(
73-
TC,
74-
A::AbstractBlockTensorMap, ::Index2Tuple, ::Bool,
75-
B::AbstractTensorMap, ::Index2Tuple, ::Bool,
76-
::Index2Tuple{N₁, N₂},
77-
) where {N₁, N₂}
78-
_check_spacetype(spacetype(A), spacetype(B))
79-
80-
I = sectortype(A)
81-
Tnew = sectorscalartype(I) <: Real ? TC : complex(TC)
82-
M = promote_storagetype(Tnew, eltype(A), typeof(B))
83-
84-
return if issparse(A) && issparse(B)
85-
sparseblocktensormaptype(spacetype(A), N₁, N₂, M)
86-
else
87-
blocktensormaptype(spacetype(A), N₁, N₂, M)
20+
for TTA in (:AbstractTensorMap, :AbstractBlockTensorMap), TTB in (:AbstractTensorMap, :AbstractBlockTensorMap)
21+
TTA == TTB == :AbstractTensorMap && continue
22+
@eval function TO.tensorcontract_type(
23+
TC,
24+
A::$TTA, ::Index2Tuple, ::Bool,
25+
B::$TTB, ::Index2Tuple, ::Bool,
26+
::Index2Tuple{N₁, N₂},
27+
) where {N₁, N₂}
28+
S = TK.check_spacetype(A, B)
29+
TC′ = TK.promote_permute(TC, sectortype(S))
30+
M = TK.promote_storagetype(TK.similarstoragetype(A, TC′), TK.similarstoragetype(B, TC′))
31+
return if issparse(A) && issparse(B)
32+
sparseblocktensormaptype(S, N₁, N₂, M)
33+
else
34+
blocktensormaptype(S, N₁, N₂, M)
35+
end
8836
end
8937
end
9038

@@ -117,23 +65,6 @@ function TO.tensoralloc_contract(
11765
end
11866
end
11967

120-
function promote_storagetype(::Type{T}, ::Type{T₁}, ::Type{T₂}) where {T, T₁, T₂}
121-
if T₁ isa Union
122-
M₁ = Union{TK.similarstoragetype(T₁.a, T), TK.similarstoragetype(T₁.b, T)}
123-
else
124-
M₁ = TK.similarstoragetype(T₁, T)
125-
end
126-
if T₂ isa Union
127-
M₂ = Union{TK.similarstoragetype(T₂.a, T), TK.similarstoragetype(T₂.b, T)}
128-
else
129-
M₂ = TK.similarstoragetype(T₂, T)
130-
end
131-
return Union{M₁, M₂}
132-
end
133-
134-
# EVIL HACK!!!
135-
TK.storagetype(::Type{AbstractTensorMap{TT, S, N₁, N₂}}) where {TT, S, N₁, N₂} = Vector{TT}
136-
13768
function promote_blocktype(::Type{TT}, ::Type{A₁}, ::Type{A₂}) where {TT, A₁, A₂}
13869
N = similarblocktype(A₁, TT)
13970
@assert N === similarblocktype(A₂, TT) "incompatible block types"
@@ -154,80 +85,6 @@ function TO.tensoralloc(
15485
return C
15586
end
15687

157-
# unfortunate overlaod until TK fix
158-
function TK.blas_contract!(
159-
C::AbstractBlockTensorMap,
160-
A::AbstractTensorMap, pA::Index2Tuple,
161-
B::AbstractTensorMap, pB::Index2Tuple,
162-
pAB::Index2Tuple, α, β,
163-
backend, allocator
164-
)
165-
bstyle = BraidingStyle(sectortype(C))
166-
bstyle isa SymmetricBraiding ||
167-
throw(SectorMismatch("only tensors with symmetric braiding rules can be contracted; try `@planar` instead"))
168-
TC = scalartype(C)
169-
170-
# check which tensors have to be permuted/copied
171-
copyA = !(TO.isblascontractable(A, pA) && eltype(A) === TC)
172-
copyB = !(TO.isblascontractable(B, pB) && eltype(B) === TC)
173-
174-
if bstyle isa Fermionic && any(isdual Base.Fix1(space, B), pB[1])
175-
# twist smallest object if neither or both already have to be permuted
176-
# otherwise twist the one that already is copied
177-
if !(copyA copyB)
178-
twistA = dim(A) < dim(B)
179-
else
180-
twistA = copyA
181-
end
182-
twistB = !twistA
183-
copyA |= twistA
184-
copyB |= twistB
185-
else
186-
twistA = false
187-
twistB = false
188-
end
189-
190-
# Bring A in the correct form for BLAS contraction
191-
if copyA
192-
Anew = TO.tensoralloc_add(TC, A, pA, false, Val(true), allocator)
193-
Anew = TO.tensoradd!(Anew, A, pA, false, One(), Zero(), backend, allocator)
194-
twistA && twist!(Anew, filter(!isdual Base.Fix1(space, Anew), domainind(Anew)))
195-
else
196-
Anew = permute(A, pA)
197-
end
198-
pAnew = (codomainind(Anew), domainind(Anew))
199-
200-
# Bring B in the correct form for BLAS contraction
201-
if copyB
202-
Bnew = TO.tensoralloc_add(TC, B, pB, false, Val(true), allocator)
203-
Bnew = TO.tensoradd!(Bnew, B, pB, false, One(), Zero(), backend, allocator)
204-
twistB && twist!(Bnew, filter(isdual Base.Fix1(space, Bnew), codomainind(Bnew)))
205-
else
206-
Bnew = permute(B, pB)
207-
end
208-
pBnew = (codomainind(Bnew), domainind(Bnew))
209-
210-
# Bring C in the correct form for BLAS contraction
211-
ipAB = TO.oindABinC(pAB, pAnew, pBnew)
212-
copyC = !TO.isblasdestination(C, ipAB)
213-
214-
if copyC
215-
Cnew = TO.tensoralloc_add(TC, C, ipAB, false, Val(true), allocator)
216-
mul!(Cnew, Anew, Bnew)
217-
TO.tensoradd!(C, Cnew, pAB, false, α, β, backend, allocator)
218-
TO.tensorfree!(Cnew, allocator)
219-
else
220-
Cnew = permute(C, ipAB)
221-
mul!(Cnew, Anew, Bnew, α, β)
222-
end
223-
224-
copyA && TO.tensorfree!(Anew, allocator)
225-
copyB && TO.tensorfree!(Bnew, allocator)
226-
227-
return C
228-
end
229-
230-
23188
# tensorfree!
23289
# -----------
23390
function TO.tensorfree!(t::BlockTensorMap, allocator = TO.DefaultAllocator())
@@ -248,7 +105,7 @@ function TK.trace_permute!(
248105
backend::AbstractBackend = TO.DefaultBackend(),
249106
)
250107
# some input checks
251-
_check_spacetype(spacetype(tdst), spacetype(tsrc))
108+
TK.check_spacetype(tdst, tsrc)
252109
if !(BraidingStyle(sectortype(tdst)) isa SymmetricBraiding)
253110
throw(
254111
SectorMismatch(

src/tensors/vectorinterface.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,28 @@ end
3939

4040
# add
4141
# ---
42+
function VI.add(ty::AbstractBlockTensorMap, tx::AbstractBlockTensorMap, α::Number, β::Number)
43+
S = TK.check_spacetype(ty, tx)
44+
space(ty) == space(tx) || throw(SpaceMismatch("$(space(ty))$(space(tx))"))
45+
46+
# result type defaults to TensorMap if the types don't match to avoid assymmetric
47+
# implementation via zerovector(ty, T) vs zerovector(tx, T)
48+
# This would give issues for example with DiagonalTensorMap + TensorMap
49+
T = VectorInterface.promote_add(ty, tx, α, β)
50+
tdst = if typeof(ty) === typeof(tx)
51+
zerovector(ty, T)
52+
else
53+
M = TK.promote_storagetype(TK.similarstoragetype(ty, T), TK.similarstoragetype(tx, T))
54+
if issparse(ty) && issparse(tx)
55+
sparseblocktensormaptype(S, numout(ty), numin(ty), M)(undef, space(ty))
56+
else
57+
blocktensormaptype(S, numout(ty), numin(ty), M)(undef, space(ty))
58+
end
59+
end
60+
61+
return add!(scale!(tdst, ty, β), tx, α)
62+
end
63+
4264
function VI.add!(ty::BlockTensorMap, tx::BlockTensorMap, α::Number, β::Number)
4365
space(ty) == space(tx) || throw(SpaceMismatch("$(space(ty))$(space(tx))"))
4466
add!(parent(ty), parent(tx), α, β)

0 commit comments

Comments
 (0)