Skip to content

Commit

Permalink
Rewrite the deduction of braidingtensor spaces
Browse files Browse the repository at this point in the history
previously constructed indexmap, but this is ambiguous if an index appears on multiple braidingtensors.
This should now be fixed by contructing braidingtensors independently.
Fixes #93
  • Loading branch information
lkdvos committed Nov 28, 2023
1 parent 518e520 commit 3c0ed8f
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 78 deletions.
134 changes: 56 additions & 78 deletions src/planar/preprocessors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ function _construct_braidingtensors(ex::Expr)
return Expr(ex.head, map(_construct_braidingtensors, ex.args)...)
end

# create a mapping of tensor_expr => braiding_constructor_expr
i = 1
translatebraidings = Dict{Any,Any}()
while i <= length(list)
Expand All @@ -101,93 +102,70 @@ function _construct_braidingtensors(ex::Expr)
end
end

# loop over the braiding tensors and try to figure out the correct spaces
unresolved = Any[] # list of indices that we couldn't yet figure out
indexmap = Dict{Any,Any}()
# indexmap[i] contains the expression to resolve the space for index i
for (t, construct_expr) in translatebraidings
obj, leftind, rightind = TO.decomposetensor(t)
length(leftind) == length(rightind) == 2 ||
throw(ArgumentError("The name τ is reserved for the braiding, and should have two input and two output indices."))
if _is_adjoint(obj)
i1b, i2b, = leftind
i2a, i1a, = rightind
else
i2b, i1b, = leftind
i1a, i2a, = rightind
end

obj_and_pos1a = _findindex(i1a, list)
obj_and_pos2a = _findindex(i2a, list)
obj_and_pos1b = _findindex(i1b, list)
obj_and_pos2b = _findindex(i2b, list)

if !isnothing(obj_and_pos1a)
indexmap[i1b] = Expr(:call, :space, obj_and_pos1a...)
indexmap[i1a] = Expr(:call, :space, obj_and_pos1a...)
elseif !isnothing(obj_and_pos1b)
indexmap[i1b] = Expr(TO.prime, Expr(:call, :space, obj_and_pos1b...))
indexmap[i1a] = Expr(TO.prime, Expr(:call, :space, obj_and_pos1b...))
else
push!(unresolved, (i1a, i1b))
end
ischanged = true
pre = Expr(:block)
while ischanged
ischanged = false
unresolved = Any[]
for (t, construct_expr) in translatebraidings
obj, leftind, rightind = TO.decomposetensor(t)
length(leftind) == length(rightind) == 2 ||
throw(ArgumentError("The name τ is reserved for the braiding, and should have two input and two output indices."))
if _is_adjoint(obj)
i1b, i2b, = leftind
i2a, i1a, = rightind
else
i2b, i1b, = leftind
i1a, i2a, = rightind
end

if !isnothing(obj_and_pos2a)
indexmap[i2b] = Expr(:call, :space, obj_and_pos2a...)
indexmap[i2a] = Expr(:call, :space, obj_and_pos2a...)
elseif !isnothing(obj_and_pos2b)
indexmap[i2b] = Expr(TO.prime, Expr(:call, :space, obj_and_pos2b...))
indexmap[i2a] = Expr(TO.prime, Expr(:call, :space, obj_and_pos2b...))
else
push!(unresolved, (i2a, i2b))
end
end
# simple loop that tries to resolve as many indices as possible
changed = true
while changed == true
changed = false
i = 1
while i <= length(unresolved)
(i1, i2) = unresolved[i]
if i1 in keys(indexmap)
changed = true
indexmap[i2] = indexmap[i1]
deleteat!(unresolved, i)
elseif i2 in keys(indexmap)
changed = true
indexmap[i1] = indexmap[i2]
deleteat!(unresolved, i)
# attempt to deduce first space
obj_and_pos1a = _findindex(i1a, list)
obj_and_pos1b = _findindex(i1b, list)
if !isnothing(obj_and_pos1a)
V_i1b = Expr(:call, :space, obj_and_pos1a...)
elseif !isnothing(obj_and_pos1b)
V_i1b = Expr(TO.prime, Expr(:call, :space, obj_and_pos1b...))
else
i += 1
push!(unresolved, (i1a, i1b))
continue
end
end
end
!isempty(unresolved) &&
throw(ArgumentError("cannot determine the spaces of indices " *
string(tuple(unresolved...)) *
"for the braiding tensors in $(ex)"))

pre = Expr(:block)
for (t, construct_expr) in translatebraidings
obj, leftind, rightind = TO.decomposetensor(t)
if _is_adjoint(obj)
i1b, i2b, = leftind
i2a, i1a, = rightind
else
i2b, i1b, = leftind
i1a, i2a, = rightind
end
push!(construct_expr.args, indexmap[i1b])
push!(construct_expr.args, indexmap[i2b])
s = gensym()
push!(pre.args, :(@notensor $s = $construct_expr))
ex = TO.replacetensorobjects(ex) do o, l, r
if o == obj && l == leftind && r == rightind
return obj == ? s : Expr(TO.prime, s)
# attempt to deduce second space
obj_and_pos2a = _findindex(i2a, list)
obj_and_pos2b = _findindex(i2b, list)
if !isnothing(obj_and_pos2a)
V_i2b = Expr(:call, :space, obj_and_pos2a...)
elseif !isnothing(obj_and_pos2b)
V_i2b = Expr(TO.prime, Expr(:call, :space, obj_and_pos2b...))
else
return o
push!(unresolved, (i2a, i2b))
continue
end

# both spaces deduced, construct braidingtensor
push!(construct_expr.args, V_i1b)
push!(construct_expr.args, V_i2b)
s = gensym()
push!(pre.args, :(@notensor $s = $construct_expr))

# and insert into tensor expression
ex = TO.replacetensorobjects(ex) do o, l, r
if o == obj && l == leftind && r == rightind
return obj == ? s : Expr(TO.prime, s)
else
return o
end
end

delete!(translatebraidings, t)
ischanged = true
end
end

@assert isempty(unresolved) "could not figure out all spaces"
return Expr(:block, pre, ex)
end
_construct_braidingtensors(x) = x
Expand Down
18 changes: 18 additions & 0 deletions test/planar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,22 @@ end
end
@test C C′
end

@testset "Issue 93" begin
T = Float64
V1 =^2
V2 =^3
t1 = TensorMap(rand, T, V1 V2)
t2 = TensorMap(rand, T, V2 V1)

tr1 = @planar opt = true t1[a; b] * t2[b; a]
tr2 = @planar opt = true t1[d; a] * t2[b; c] * τ[c b; a d]
tr3 = @planar opt = true t1[d; a] * t2[b; c] * τ[a c; d b]
tr4 = @planar opt = true t1[f; a] * t2[c; d] * τ[d b; c e] * τ[e b; a f]
tr5 = @planar opt = true t1[f; a] * t2[c; d] * τ[d b; c e] * τ[a e; f b]
tr6 = @planar opt = true t1[f; a] * t2[c; d] * τ[c d; e b] * τ[e b; a f]
tr7 = @planar opt = true t1[f; a] * t2[c; d] * τ[c d; e b] * τ[a e; f b]

@test tr1 tr2 tr3 tr4 tr5 tr6 tr7
end
end

0 comments on commit 3c0ed8f

Please sign in to comment.