From 3c0ed8f748b0c01874ee58800081f2538994c285 Mon Sep 17 00:00:00 2001 From: lkdvos Date: Tue, 28 Nov 2023 16:08:20 +0100 Subject: [PATCH] Rewrite the deduction of braidingtensor spaces 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 --- src/planar/preprocessors.jl | 134 +++++++++++++++--------------------- test/planar.jl | 18 +++++ 2 files changed, 74 insertions(+), 78 deletions(-) diff --git a/src/planar/preprocessors.jl b/src/planar/preprocessors.jl index 6c284ad9..006fdc1d 100644 --- a/src/planar/preprocessors.jl +++ b/src/planar/preprocessors.jl @@ -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) @@ -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 diff --git a/test/planar.jl b/test/planar.jl index 062e41b6..250bcf14 100644 --- a/test/planar.jl +++ b/test/planar.jl @@ -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