diff --git a/Project.toml b/Project.toml index f47fde213..110450ad5 100644 --- a/Project.toml +++ b/Project.toml @@ -4,7 +4,6 @@ authors = ["Sergio Sánchez Ramírez "] version = "0.2.0" [deps] -Bijections = "e2ed5e7c-b2de-5872-ae92-c73ca462fb04" Classes = "1a9c1350-211b-5766-99cd-4544d885a0d1" Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" DeltaArrays = "10b0fc19-5ccc-4427-889b-d75dd6306188" @@ -35,7 +34,6 @@ TenetMakieExt = "Makie" TenetQuacExt = "Quac" [compat] -Bijections = "0.1" ChainRulesCore = "1.0" Combinatorics = "1.0" DeltaArrays = "0.1.1" diff --git a/src/Quantum/Quantum.jl b/src/Quantum/Quantum.jl index 9522da68a..6b5df73af 100644 --- a/src/Quantum/Quantum.jl +++ b/src/Quantum/Quantum.jl @@ -1,256 +1,170 @@ using LinearAlgebra using UUIDs: uuid4 using ValSplit -using Bijections -using EinExprs: inds +using Classes """ - Quantum <: Ansatz + QuantumTensorNetwork Tensor Network `Ansatz` that has a notion of sites and directionality (input/output). """ -abstract type Quantum <: Arbitrary end - -# NOTE Storing `Plug` type on type parameters is not compatible with `Composite` ansatz. Use Holy traits instead. -metadata(::Type{Quantum}) = merge(metadata(supertype(Quantum)), @NamedTuple begin - plug::Type{<:Plug} - interlayer::Vector{Bijection{Int,Symbol}} -end) - -function checkmeta(::Type{Quantum}, tn::TensorNetwork) - # TODO run this check depending if State or Operator - length(tn.interlayer) >= 1 || return false - - # meta's indices exist - all(bij -> values(bij) ⊆ inds(tn), tn.interlayer) || return false - - return true +@class QuantumTensorNetwork <: TensorNetwork begin + input::Vector{Symbol} + output::Vector{Symbol} end -abstract type Boundary end -abstract type Open <: Boundary end -abstract type Periodic <: Boundary end -abstract type Infinite <: Boundary end - -""" - boundary(::TensorNetwork) - boundary(::Type{<:TensorNetwork}) - -Return the `Boundary` type of the [`TensorNetwork`](@ref). The following `Boundary`s are defined in `Tenet`: - - - `Open` - - `Periodic` - - `Infinite` -""" -function boundary end -boundary(::T) where {T<:TensorNetwork} = boundary(T) -boundary(::Type{T}) where {T<:TensorNetwork} = boundary(ansatz(T)) - -abstract type Plug end -abstract type Property <: Plug end -abstract type State <: Plug end -abstract type Operator <: Plug end - -""" - plug(::TensorNetwork{<:Quantum}) - plug(::Type{<:TensorNetwork}) - -Return the `Plug` type of the [`TensorNetwork`](@ref). The following `Plug`s are defined in `Tenet`: - - - `State` Only outputs. - - `Operator` Inputs and outputs. - - `Property` No inputs nor outputs. -""" -function plug end -plug(tn::TensorNetwork{<:Quantum}) = tn.plug -plug(T::Type{<:TensorNetwork}) = plug(ansatz(T)) +inds(tn::absclass(QuantumTensorNetwork), ::Val{:in}) = tuple(tn.input...) +inds(tn::absclass(QuantumTensorNetwork), ::Val{:in}, site) = tn.input[site] +inds(tn::absclass(QuantumTensorNetwork), ::Val{:out}) = tuple(tn.output...) +inds(tn::absclass(QuantumTensorNetwork), ::Val{:out}, site) = tn.output[site] +inds(tn::absclass(QuantumTensorNetwork), ::Val{:physical}) = ∪(tn.input, tn.output) +inds(tn::absclass(QuantumTensorNetwork), ::Val{:virtual}) = setdiff(inds(tn, Val(:all)), inds(tn, Val(:physical))) """ - sites(tn::TensorNetwork{<:Quantum}) + sites(tn::AbstractQuantumTensorNetwork, dir) Return the sites in which the [`TensorNetwork`](@ref) acts. """ -sites(tn::TensorNetwork) = collect(mapreduce(keys, ∪, tn.interlayer)) - -EinExprs.inds(tn::TensorNetwork, ::Val{:plug}) = unique(Iterators.flatten(Iterators.map(values, tn.interlayer))) -EinExprs.inds(tn::TensorNetwork, ::Val{:plug}, site) = last(tn.interlayer)[site] # inds(tn, Val(:in), site) ∪ inds(tn, Val(:out), site) -EinExprs.inds(tn::TensorNetwork, ::Val{:virtual}) = setdiff(inds(tn, Val(:all)), inds(tn, Val(:plug))) +sites(tn::absclass(QuantumTensorNetwork)) = sites(tn, :in) ∪ sites(tn, :out) +function sites(tn::absclass(QuantumTensorNetwork), dir) + if dir === :in + firstindex(tn.input):lastindex(tn.input) + elseif dir === :out + firstindex(tn.output):lastindex(tn.output) + else + throw(MethodError("unknown dir=$dir")) + end +end -""" - tensors(tn::TensorNetwork{<:Quantum}, site::Integer) +function Base.replace!(tn::absclass(QuantumTensorNetwork), old_new::Pair{Symbol,Symbol}) + Base.@invoke replace!(tn::absclass(TensorNetwork), old_new::Pair{Symbol,Symbol}) -Return the `Tensor` connected to the [`TensorNetwork`](@ref) on `site`. - -See also: [`sites`](@ref). -""" -tensors(tn::TensorNetwork{<:Quantum}, site::Integer, args...) = tensors(plug(tn), tn, site, args...) -tensors(::Type{State}, tn::TensorNetwork{<:Quantum}, site) = select(tn, inds(tn, :plug, site)) |> only -@valsplit 4 tensors(T::Type{Operator}, tn::TensorNetwork{<:Quantum}, site, dir::Symbol) = - throw(MethodError(sites, "dir=$dir not recognized")) - -function Base.replace!(tn::TensorNetwork{<:Quantum}, old_new::Pair{Symbol,Symbol}) - # replace indices in tensor network - Base.@invoke replace!(tn::TensorNetwork, old_new::Pair{Symbol,Symbol}) - - old, new = old_new - - # replace indices in interlayers (quantum-specific) - for interlayer in Iterators.filter(∋(old) ∘ image, tn.interlayer) - site = interlayer(old) - delete!(interlayer, site) - interlayer[site] = new - end + replace!(tn.input, old_new) + replace!(tn.output, old_new) return tn end -## `Composite` type """ - Composite <: Quantum + adjoint(tn::AbstractQuantumTensorNetwork) -A [`Quantum`](@ref) ansatz that represents several connected layers of [`Quantum`](@ref) [`TensorNetwork`](@ref)s. +Return the adjoint [`TensorNetwork`](@ref). # Implementation details -Introduces a field named `layermeta` that stores the metadata of each layer. - -See also: [`hcat`](@ref). +The tensors are not transposed, just `conj!` is applied to them. """ -abstract type Composite{Ts<:Tuple} <: Quantum end -Composite(@nospecialize(Ts::Type{<:Quantum}...)) = Composite{Tuple{Ts...}} -Base.fieldtypes(::Type{Composite{Ts}}) where {Ts} = fieldtypes(Ts) - -metadata(::Type{<:Composite}) = merge(metadata(Quantum), @NamedTuple begin - layermeta::Vector{Dict{Symbol,Any}} -end) - -function checkmeta(As::Type{<:Composite}, tn::TensorNetwork) - for (i, A) in enumerate(fieldtypes(As)) - tn_view = layers(tn, i) - checkansatz(tn_view) - end +function Base.adjoint(tn::absclass(QuantumTensorNetwork)) + tn = deepcopy(tn) - return true -end + # swap input/output + temp = copy(tn.input) + resize!(tn.input, length(tn.output)) + copy!(tn.input, tn.output) + resize!(tn.output, length(temp)) + copy!(tn.output, temp) -Base.length(@nospecialize(T::Type{<:Composite})) = length(fieldtypes(T)) + foreach(conj!, tensors(tn)) -# TODO create view of TN -""" - layers(tn::TensorNetwork{<:Composite}, i) + return tn +end -Return a [`TensorNetwork`](@ref) that is shallow copy of the ``i``-th layer of a `Composite` Tensor Network. -""" -function layers(tn::TensorNetwork{As}, i) where {As<:Composite} - A = fieldtypes(As)[i] - layer_plug = tn.layermeta[i][:plug] # TODO more programmatic access (e.g. plug(tn, i)?) - meta = tn.layermeta[i] +function Base.merge!(self::absclass(QuantumTensorNetwork), other::absclass(QuantumTensorNetwork)) + sites(self, :out) == sites(other, :in) || + throw(DimensionMismatch("both `QuantumTensorNetwork`s must contain the same set of sites")) - if layer_plug <: State && 1 < i < length(fieldtypes(As)) - throw(ErrorException("Layer #$i is a state but it is not a extreme layer")) + # copy to avoid mutation if reindex is needed + # TODO deepcopy because `indices` are not correctly copied and it mutates + other = deepcopy(other) + + # reindex other if needed + if inds(self, set = :out) != inds(other, set = :in) + replace!(other, map(splat(=>), zip(inds(other, set = :in), inds(self, set = :out)))) end - interlayer = if layer_plug <: State - i == 1 ? [first(tn.interlayer)] : [last(tn.interlayer)] - elseif layer_plug <: Operator - # shift if first layer is a state - tn.layermeta[1][:plug] <: State && (i = i - 1) - tn.interlayer[i:i+1] + # reindex inner indices of `other` to avoid accidental hyperindices + conflict = inds(self, set = :virtual) ∩ inds(other, set = :virtual) + if !isempty(conflict) + replace!(other, map(i -> i => Symbol(uuid4()), conflict)) end - return TensorNetwork{A}( - # TODO revise this - #filter(tensor -> get(tensor.meta, :layer, nothing) == i, tensors(tn)); - tensors(tn); - plug = layer_plug, - interlayer, - meta..., - ) + @invoke merge!(self::absclass(TensorNetwork), other::absclass(TensorNetwork)) + + # update i/o + copy!(self.output, other.output) + + self end -Base.merge(::Type{State}, ::Type{State}) = Property -Base.merge(::Type{State}, ::Type{Operator}) = State -Base.merge(::Type{Operator}, ::Type{State}) = State -Base.merge(::Type{Operator}, ::Type{Operator}) = Operator +function contract(a::absclass(QuantumTensorNetwork), b::absclass(QuantumTensorNetwork); kwargs...) + contract(merge(a, b); kwargs...) +end -# TODO implement hcat when QA or QB <: Composite -""" - hcat(A::TensorNetwork{<:Quantum}, B::TensorNetwork{<:Quantum}...)::TensorNetwork{<:Composite} +# Plug trait +abstract type Plug end +struct Property <: Plug end +struct State <: Plug end +struct Dual <: Plug end +struct Operator <: Plug end -Join [`TensorNetwork`](@ref)s into one by matching sites. """ -function Base.hcat(A::TensorNetwork{QA}, B::TensorNetwork{QB}) where {QA<:Quantum,QB<:Quantum} - issetequal(sites(A), sites(B)) || - throw(DimensionMismatch("A and B must contain the same set of sites in order to connect them")) + plug(::QuantumTensorNetwork) - # rename connector indices - newinds = Dict([s => Symbol(uuid4()) for s in sites(A)]) - - B = copy(B) +Return the `Plug` type of the [`TensorNetwork`](@ref). The following `Plug`s are defined in `Tenet`: - for site in sites(B) - a = inds(A, :plug, site) - b = inds(B, :plug, site) - if a != b && a ∉ inds(B) - replace!(B, b => a) - end + - `Property` No inputs nor outputs. + - `State` Only outputs. + - `Dual` Only inputs. + - `Operator` Inputs and outputs. +""" +function plug(tn) + if isempty(tn.input) && isempty(tn.output) + Property() + elseif isempty(tn.input) + State() + elseif isempty(tn.output) + Dual() + else + Operator() end - - # rename inner indices of B to avoid hyperindices - replace!(B, [i => Symbol(uuid4()) for i in inds(B, :inner)]...) - - combined_plug = merge(plug(A), plug(B)) - - # merge tensors and indices - interlayer = [A.interlayer..., collect(Iterators.drop(B.interlayer, 1))...] - - # TODO merge metadata? - layermeta = Dict{Symbol,Any}[ - Dict(Iterators.filter(((k, v),) -> k !== :interlayer, pairs(A.metadata))), - Dict(Iterators.filter(((k, v),) -> k !== :interlayer, pairs(B.metadata))), - ] - - return TensorNetwork{Composite(QA, QB)}([tensors(A)..., tensors(B)...]; plug = combined_plug, interlayer, layermeta) end -Base.hcat(tns::TensorNetwork...) = reduce(hcat, tns) +# Boundary trait +abstract type Boundary end +struct Open <: Boundary end +struct Periodic <: Boundary end +struct Infinite <: Boundary end """ - adjoint(tn::TensorNetwork{<:Quantum}) - -Return the adjoint [`TensorNetwork`](@ref). + boundary(::QuantumTensorNetwork) -# Implementation details +Return the `Boundary` type of the [`TensorNetwork`](@ref). The following `Boundary`s are defined in `Tenet`: -The tensors are not transposed, just `conj!` is applied to them. + - `Open` + - `Periodic` + - `Infinite` """ -function Base.adjoint(tn::TensorNetwork{<:Quantum}) - tn = deepcopy(tn) - - reverse!(tn.interlayer) - foreach(conj!, tensors(tn)) - - return tn -end - -contract(a::TensorNetwork{<:Quantum}, b::TensorNetwork{<:Quantum}; kwargs...) = contract(hcat(a, b); kwargs...) +function boundary end # TODO look for more stable ways """ - norm(ψ::TensorNetwork{<:Quantum}, p::Real=2) + norm(ψ::AbstractQuantumTensorNetwork, p::Real=2) Compute the ``p``-norm of a [`Quantum`](@ref) [`TensorNetwork`](@ref). See also: [`normalize!`](@ref). """ -function LinearAlgebra.norm(ψ::TensorNetwork{<:Quantum}, p::Real = 2; kwargs...) - p != 2 && throw(ArgumentError("p=$p is not implemented yet")) +function LinearAlgebra.norm(ψ::absclass(QuantumTensorNetwork), p::Real = 2; kwargs...) + p == 2 || throw(ArgumentError("p=$p is not implemented yet")) + + tn = merge(ψ, ψ') + all(isempty, [tn.input, tn.output]) || throw("unimplemented if <ψ|ψ> is an operator") - return contract(hcat(ψ, ψ'); kwargs...) |> only |> sqrt |> abs + return contract(tn; kwargs...) |> only |> sqrt |> abs end """ - normalize!(ψ::TensorNetwork{<:Quantum}, p::Real = 2; insert::Union{Nothing,Int} = nothing) + normalize!(ψ::AbstractQuantumTensorNetwork, p::Real = 2; insert::Union{Nothing,Int} = nothing) In-place normalize the [`TensorNetwork`](@ref). @@ -266,12 +180,12 @@ In-place normalize the [`TensorNetwork`](@ref). See also: [`norm`](@ref). """ function LinearAlgebra.normalize!( - ψ::TensorNetwork{<:Quantum}, + ψ::absclass(QuantumTensorNetwork), p::Real = 2; insert::Union{Nothing,Int} = nothing, kwargs..., ) - norm = LinearAlgebra.norm(ψ; kwargs...) + norm = LinearAlgebra.norm(ψ, p; kwargs...) if isnothing(insert) # method 1: divide all tensors by (√v)^(1/n) @@ -282,7 +196,7 @@ function LinearAlgebra.normalize!( end else # method 2: divide only one tensor - tensor = tensors(ψ, insert) + tensor = ψ.tensors[insert] # tensors(ψ, insert) # TODO fix this to match site? tensor ./= norm end end @@ -300,10 +214,9 @@ fidelity(a, b; kwargs...) = abs(only(contract(a, b'; kwargs...)))^2 Return the marginal quantum state of site. """ function marginal(ψ, site) - tensor = tensors(ψ, site) - index = inds(ψ, :plug, site) - sum(tensor, inds = setdiff(inds(tensor), [index])) -end + plug(ψ) == State() || throw("unimplemented") -include("MP.jl") -include("PEP.jl") + siteindex = inds(ψ, :out, site) + tensor = only(select(tn, siteindex)) + sum(tensor, inds = setdiff(inds(tensor), [siteindex])) +end diff --git a/src/Tenet.jl b/src/Tenet.jl index b9b92b07f..49ec6486e 100644 --- a/src/Tenet.jl +++ b/src/Tenet.jl @@ -12,19 +12,14 @@ include("Numerics.jl") include("TensorNetwork.jl") export TensorNetwork, tensors, arrays, select, slice! export contract, contract! -export Ansatz, ansatz, Arbitrary include("Transformations.jl") export transform, transform! include("Quantum/Quantum.jl") -export Quantum +export QuantumTensorNetwork, sites, fidelity +export Plug, plug, Property, State, Dual, Operator export Boundary, boundary, Open, Periodic, Infinite -export Plug, plug, Property, State, Operator -export sites, fidelity - -export MatrixProduct, MPS, MPO -export ProjectedEntangledPair, PEPS, PEPO # reexports from LinearAlgebra export norm, normalize! diff --git a/test/Project.toml b/test/Project.toml index 32241a300..f186cef76 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,6 +1,5 @@ [deps] Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" -Bijections = "e2ed5e7c-b2de-5872-ae92-c73ca462fb04" BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" diff --git a/test/Quantum_test.jl b/test/Quantum_test.jl index 451ca7d62..522a3ca12 100644 --- a/test/Quantum_test.jl +++ b/test/Quantum_test.jl @@ -1,50 +1,38 @@ @testset "Quantum" begin - using Bijections - - struct MockState <: Quantum end - Tenet.plug(::Type{MockState}) = State - Tenet.metadata(::Type{MockState}) = Tenet.metadata(Quantum) - - struct MockOperator <: Quantum end - Tenet.plug(::Type{MockOperator}) = Operator - Tenet.metadata(::Type{MockOperator}) = Tenet.metadata(Quantum) - - state = TensorNetwork{MockState}( - [Tensor(rand(2, 2), (:i, :k)), Tensor(rand(3, 2, 4), (:j, :k, :l))]; - plug = State, - interlayer = [Bijection(Dict([1 => :i, 2 => :j]))], + state = QuantumTensorNetwork( + TensorNetwork(Tensor[Tensor(rand(2, 2), (:i, :k)), Tensor(rand(3, 2, 4), (:j, :k, :l))]), + Symbol[], # input + [:i, :j], # output ) - operator = TensorNetwork{MockOperator}( - [Tensor(rand(2, 4, 2), (:a, :c, :d)), Tensor(rand(3, 4, 3, 5), (:b, :c, :e, :f))]; - plug = Operator, - interlayer = [Bijection(Dict([1 => :a, 2 => :b])), Bijection(Dict([1 => :d, 2 => :e]))], + operator = QuantumTensorNetwork( + TensorNetwork(Tensor[Tensor(rand(2, 4, 2), (:a, :c, :d)), Tensor(rand(3, 4, 3, 5), (:b, :c, :e, :f))]), + [:a, :b], # input + [:d, :e], # output ) - @testset "metadata" begin + @testset "adjoint" begin @testset "State" begin - @test Tenet.checkmeta(state) - @test hasproperty(state, :interlayer) - @test only(state.interlayer) == Bijection(Dict([1 => :i, 2 => :j])) + adj = adjoint(state) + @test adj.input == state.output + @test adj.output == state.input + @test all(((a, b),) -> a == conj(b), zip(tensors(state), tensors(adj))) end @testset "Operator" begin - @test Tenet.checkmeta(operator) - @test hasproperty(operator, :interlayer) - @test operator.interlayer == [Bijection(Dict([1 => :a, 2 => :b])), Bijection(Dict([1 => :d, 2 => :e]))] + adj = adjoint(operator) + @test adj.input == operator.output + @test adj.output == operator.input + @test all(((a, b),) -> a == conj(b), zip(tensors(operator), tensors(adj))) end end @testset "plug" begin - @test plug(state) === State - - @test plug(operator) === Operator + @test plug(state) == State() + @test plug(state') == Dual() + @test plug(operator) == Operator() end - # TODO write tests for - # - boundary - # - tensors - @testset "sites" begin @test issetequal(sites(state), [1, 2]) @test issetequal(sites(operator), [1, 2]) @@ -54,88 +42,100 @@ @testset "State" begin @test issetequal(inds(state), [:i, :j, :k, :l]) @test issetequal(inds(state, set = :open), [:i, :j, :l]) - @test issetequal(inds(state, set = :plug), [:i, :j]) @test issetequal(inds(state, set = :inner), [:k]) @test isempty(inds(state, set = :hyper)) + @test isempty(inds(state, set = :in)) + @test issetequal(inds(state, set = :out), [:i, :j]) + @test issetequal(inds(state, set = :physical), [:i, :j]) @test issetequal(inds(state, set = :virtual), [:k, :l]) end - # TODO change the indices @testset "Operator" begin @test issetequal(inds(operator), [:a, :b, :c, :d, :e, :f]) @test issetequal(inds(operator, set = :open), [:a, :b, :d, :e, :f]) - @test issetequal(inds(operator, set = :plug), [:a, :b, :d, :e]) @test issetequal(inds(operator, set = :inner), [:c]) @test isempty(inds(operator, set = :hyper)) - @test_broken issetequal(inds(operator, set = :virtual), [:c]) + @test issetequal(inds(operator, set = :in), [:a, :b]) + @test issetequal(inds(operator, set = :out), [:d, :e]) + @test issetequal(inds(operator, set = :physical), [:a, :b, :d, :e]) + @test issetequal(inds(operator, set = :virtual), [:c, :f]) end end - @testset "adjoint" begin - @testset "State" begin - adj = adjoint(state) - - @test issetequal(sites(state), sites(adj)) - @test all(i -> inds(state, :plug, i) == inds(adj, :plug, i), sites(state)) - end + @testset "merge" begin + @testset "(State, State)" begin + tn = merge(state, state') - @testset "Operator" begin - adj = adjoint(operator) + @test plug(tn) == Property() - @test issetequal(sites(operator), sites(adj)) - @test_broken all(i -> inds(operator, :plug, i) == inds(adj, :plug, i), sites(operator)) - @test all(i -> first(operator.interlayer)[i] == last(adj.interlayer)[i], sites(operator)) - @test all(i -> last(operator.interlayer)[i] == first(adj.interlayer)[i], sites(operator)) - end - end + @test isempty(sites(tn, :in)) + @test isempty(sites(tn, :out)) - @testset "hcat" begin - @testset "(State, State)" begin - expectation = hcat(state, state) - @test issetequal(sites(expectation), sites(state)) - @test issetequal(inds(expectation, set = :plug), inds(state, set = :plug)) - @test isempty(inds(expectation, set = :open)) - @test issetequal(inds(expectation, set = :inner), inds(expectation, set = :all)) + @test isempty(inds(tn, set = :in)) + @test isempty(inds(tn, set = :out)) + @test isempty(inds(tn, set = :physical)) + @test issetequal(inds(tn), inds(tn, set = :virtual)) end @testset "(State, Operator)" begin - expectation = hcat(state, operator) - @test issetequal(sites(expectation), sites(state)) - @test_broken issetequal(inds(expectation, set = :plug), inds(operator, set = :plug)) - @test_broken isempty(inds(expectation, set = :open)) - @test_broken issetequal(inds(expectation, set = :inner), inds(expectation, set = :all)) + tn = merge(state, operator) + + @test plug(tn) == State() + + @test isempty(sites(tn, :in)) + @test issetequal(sites(tn, :out), sites(operator, :out)) + + @test isempty(inds(tn, set = :in)) + @test issetequal(inds(tn, set = :out), inds(operator, :out)) + @test issetequal(inds(tn, set = :physical), inds(operator, :out)) + @test issetequal(inds(tn, set = :virtual), inds(state) ∪ inds(operator, :virtual)) end @testset "(Operator, State)" begin - expectation = hcat(operator, state) - @test issetequal(sites(expectation), sites(state)) - @test_broken issetequal(inds(expectation, set = :plug), inds(state, set = :plug)) - @test_broken isempty(inds(expectation, set = :open)) - @test_broken issetequal(inds(expectation, set = :inner), inds(expectation, set = :all)) + tn = merge(operator, state') + + @test plug(tn) == Dual() + + @test issetequal(sites(tn, :in), sites(operator, :in)) + @test isempty(sites(tn, :out)) + + @test issetequal(inds(tn, set = :in), inds(operator, :in)) + @test isempty(inds(tn, set = :out)) + @test issetequal(inds(tn, set = :physical), inds(operator, :in)) + @test issetequal( + inds(tn, set = :virtual), + inds(state, :virtual) ∪ inds(operator, :virtual) ∪ inds(operator, :out), + ) end @testset "(Operator, Operator)" begin - expectation = hcat(operator, operator) - @test issetequal(sites(expectation), sites(state)) - @test issetequal(inds(expectation, set = :plug), inds(operator, set = :plug)) - @test isempty(inds(expectation, set = :open)) - @test issetequal(inds(expectation, set = :inner), inds(expectation, set = :all)) + tn = merge(operator, operator) + + @test plug(tn) == Operator() + + @test issetequal(sites(tn, :in), sites(operator, :in)) + @test issetequal(sites(tn, :out), sites(operator, :out)) + + @test issetequal(inds(tn, set = :in), inds(operator, :in)) + @test issetequal(inds(tn, set = :out), inds(operator, :out)) + @test issetequal(inds(tn, set = :physical), inds(operator, :physical)) + @test_broken issetequal(inds(tn, set = :virtual), inds(operator, :virtual)) end # @testset "(State, Operator, State)" begin - # expectation = hcat(state, operator, state') - # @test_broken issetequal(sites(expectation), sites(state)) - # @test_broken issetequal(inds(expectation, set = :plug), inds(operator, set = :plug)) - # @test_broken isempty(inds(expectation, set = :open)) - # @test_broken issetequal(inds(expectation, set = :inner), inds(expectation, set = :all)) + # tn = merge(state, operator, state') + # @test_broken issetequal(sites(tn), sites(state)) + # @test_broken issetequal(inds(tn, set = :plug), inds(operator, set = :plug)) + # @test_broken isempty(inds(tn, set = :open)) + # @test_broken issetequal(inds(tn, set = :inner), inds(tn, set = :all)) # end # @testset "(Operator, Operator, Operator)" begin - # expectation = hcat(operator, operator, operator) - # @test_broken issetequal(sites(expectation), sites(state)) - # @test_broken issetequal(inds(expectation, set = :plug), inds(operator, set = :plug)) - # @test_broken isempty(inds(expectation, set = :open)) - # @test_broken issetequal(inds(expectation, set = :inner), inds(expectation, set = :all)) + # tn = merge(operator, operator, operator) + # @test_broken issetequal(sites(tn), sites(state)) + # @test_broken issetequal(inds(tn, set = :plug), inds(operator, set = :plug)) + # @test_broken isempty(inds(tn, set = :open)) + # @test_broken issetequal(inds(tn, set = :inner), inds(tn, set = :all)) # end end end diff --git a/test/runtests.jl b/test/runtests.jl index 032113af5..f14a7ab0e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,23 +2,26 @@ using Test using Tenet using OMEinsum -@testset "Unit tests" verbose = true begin +@testset "Core tests" verbose = true begin include("Helpers_test.jl") include("Tensor_test.jl") include("Numerics_test.jl") include("TensorNetwork_test.jl") - include("Quantum_test.jl") include("Transformations_test.jl") +end + +@testset "Quantum tests" verbose = true begin + include("Quantum_test.jl") # Ansatz Tensor Networks - include("MatrixProductState_test.jl") - include("MatrixProductOperator_test.jl") + # include("MatrixProductState_test.jl") + # include("MatrixProductOperator_test.jl") end @testset "Integration tests" verbose = true begin include("integration/ChainRules_test.jl") include("integration/BlockArray_test.jl") - include("integration/Quac_test.jl") + # include("integration/Quac_test.jl") include("integration/Makie_test.jl") end