Skip to content

Commit

Permalink
Support conversion to/from ITensors.jl and ITensorNetworks.jl (#200)
Browse files Browse the repository at this point in the history
* Init extension

* Support conversion from `ITensor` to `Tensor`

* Support conversion from `Vector{ITensor}` to `TensorNetwork`

* Fix call to `id`

* Support conversion from `ITensorNetwork` to `Quantum`, `TensorNetwork`

* Lower compat bound of KrylovKit to v0.7

Required by ITensorNetworks

* Support conversion from `Tensor`, `TensorNetwork` to `ITensor`, `Vector{ITensor}`

* Rename `Tensor`, `TensorNetwork`, `Quantum` methods to `Base.convert` methods

* Support conversion from `AbstractTensorNetwork` to `ITensorNetwork`

* Fix some typos and problems

* Implement `sites` method for recovering site from `Symbol`

* Support conversion from `AbstractQuantum` to `ITensorNetwork`

* Comment future idea

* Test `ITensors`, `ITensorNetworks` integration

* Fix `Vector{ITensor}` to `TensorNetwork` conversion

* Fix tests

* Defer ITensorNetworks instantiation to test time

* Add Pkg package to test dependencies
  • Loading branch information
mofeing authored Sep 11, 2024
1 parent 280e5fb commit 03a6ad1
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 1 deletion.
8 changes: 7 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ Dagger = "d58978e5-989f-55fb-8d15-ea34adc7bf54"
FiniteDifferences = "26cc04aa-876d-5657-8c51-4c34ba976000"
GraphMakie = "1ecd5474-83a3-4783-bb4f-06765db800d2"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
ITensorNetworks = "2919e153-833c-4bdc-8836-1ea460a35fc7"
ITensors = "9136182c-28ba-11e9-034c-db9fb085ebd5"
KrylovKit = "0b1a1467-8014-51b9-945f-bf0ae24f4b77"
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
Expand All @@ -41,6 +43,8 @@ TenetChainRulesTestUtilsExt = ["ChainRulesCore", "ChainRulesTestUtils"]
TenetDaggerExt = "Dagger"
TenetFiniteDifferencesExt = "FiniteDifferences"
TenetGraphMakieExt = ["GraphMakie", "Makie"]
TenetITensorNetworksExt = "ITensorNetworks"
TenetITensorsExt = "ITensors"
TenetKrylovKitExt = ["KrylovKit"]
TenetPythonCallExt = "PythonCall"
TenetQuacExt = "Quac"
Expand All @@ -60,8 +64,10 @@ EinExprs = "0.5, 0.6"
FiniteDifferences = "0.12"
GraphMakie = "0.4,0.5"
Graphs = "1.7"
ITensorNetworks = "0.11"
ITensors = "0.6"
KeywordDispatch = "0.3"
KrylovKit = "0.8.1"
KrylovKit = "0.7, 0.8"
LinearAlgebra = "1.9"
Makie = "0.18,0.19,0.20, 0.21"
OMEinsum = "0.7, 0.8"
Expand Down
42 changes: 42 additions & 0 deletions ext/TenetITensorNetworksExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
module TenetITensorNetworksExt

using Tenet
using ITensorNetworks: ITensorNetworks, ITensorNetwork, ITensor, Index, siteinds, plev, vertices, rename_vertices
const ITensors = ITensorNetworks.ITensors
const DataGraphs = ITensorNetworks.DataGraphs
const TenetITensorsExt = Base.get_extension(Tenet, :TenetITensorsExt)

Base.convert(::Type{TensorNetwork}, tn::ITensorNetwork) = TensorNetwork([convert(Tensor, tn[v]) for v in vertices(tn)])

function Base.convert(::Type{ITensorNetwork}, tn::Tenet.AbstractTensorNetwork; inds=Dict{Symbol,Index}())
return ITensorNetwork(convert(Vector{ITensor}, tn; inds))
end

function Base.convert(::Type{Quantum}, tn::ITensorNetwork)
sitedict = Dict(
map(pairs(DataGraphs.vertex_data(siteinds(tn)))) do (loc, index)
index = only(index)
primelevel = plev(index)
@assert primelevel (0, 1)

# NOTE ITensors' Index's tag only has space for 16 characters
tag = ITensors.id(index)
Site(loc; dual=Bool(primelevel)) => TenetITensorsExt.symbolize(index)
end,
)
return Quantum(convert(TensorNetwork, tn), sitedict)
end

function Base.convert(::Type{ITensorNetwork}, tn::Tenet.AbstractQuantum)
itn = @invoke convert(ITensorNetwork, tn::Tenet.AbstractTensorNetwork)

return rename_vertices(itn) do v
itensor = itn[v]
indices = map(x -> Symbol(replace(x, "\"" => "")), string.(ITensors.tags.(ITensors.inds(itensor))))
tensor = only(tensors(tn; contains=indices))
physical_index = only(inds(tn; set=:physical) inds(tensor))
return sites(tn; at=physical_index).id
end
end

end
47 changes: 47 additions & 0 deletions ext/TenetITensorsExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
module TenetITensorsExt

using Tenet
using ITensors: ITensors, ITensor, Index

function symbolize(index::Index)
tag = string(ITensors.id(index))

# NOTE ITensors' Index's tag only has space for 16 characters
return Symbol(length(tag) > 16 ? tag[(end - 16 + 1):end] : tag)
end

function tagize(index::Symbol)
tag = string(index)

# NOTE ITensors' Index's tag only has space for 16 characters
return length(tag) > 16 ? tag[(end - 16 + 1):end] : tag
end

# TODO customize index names
function Base.convert(::Type{Tensor}, tensor::ITensor)
array = ITensors.array(tensor)
is = map(symbolize, ITensors.inds(tensor))
return Tensor(array, is)
end

function Base.convert(::Type{ITensor}, tensor::Tensor; inds=Dict{Symbol,Index}())
indices = map(Tenet.inds(tensor)) do i
haskey(inds, i) ? inds[i] : Index(size(tensor, i), tagize(i))
end
return ITensor(parent(tensor), indices)
end

Base.convert(::Type{TensorNetwork}, tn::Vector{ITensor}) = TensorNetwork(map(t -> convert(Tensor, t), tn))

function Base.convert(::Type{Vector{ITensor}}, tn::Tenet.AbstractTensorNetwork; inds=Dict{Symbol,Index}())
indices = merge(inds, Dict(
map(Iterators.filter(!Base.Fix1(haskey, inds), Tenet.inds(tn))) do i
i => Index(size(tn, i), tagize(i))
end,
))
return map(tensors(tn)) do tensor
ITensor(parent(tensor), map(i -> indices[i], Tenet.inds(tensor)))
end
end

end
5 changes: 5 additions & 0 deletions src/Quantum.jl
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,11 @@ end
end
end

@kwmethod function sites(tn::AbstractQuantum; at::Symbol)
tn = Quantum(tn)
return findfirst(==(at), tn.sites)
end

@deprecate Base.getindex(q::Quantum, site::Site) inds(q; at=site) false

function Base.replace!(tn::Quantum, old_new::Base.AbstractVecOrTuple{Pair{Symbol,Symbol}})
Expand Down
2 changes: 2 additions & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ Dagger = "d58978e5-989f-55fb-8d15-ea34adc7bf54"
DeltaArrays = "10b0fc19-5ccc-4427-889b-d75dd6306188"
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
GraphMakie = "1ecd5474-83a3-4783-bb4f-06765db800d2"
ITensors = "9136182c-28ba-11e9-034c-db9fb085ebd5"
KrylovKit = "0b1a1467-8014-51b9-945f-bf0ae24f4b77"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
NetworkLayout = "46757867-2c16-5918-afeb-47bfcb05e46a"
OMEinsum = "ebe7aa44-baf0-506c-a96f-8464559b3922"
Permutations = "2ae35dd2-176d-5d53-8349-f30d82d94d4f"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
Quac = "b9105292-1415-45cf-bff1-d6ccf71e6143"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Expand Down
29 changes: 29 additions & 0 deletions test/integration/ITensorNetworks_test.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# breaks in instantiation on Julia 1.9
using Pkg
Pkg.add("ITensorNetworks")

@testset "ITensorNetworks" begin
using ITensors: ITensors, ITensor, Index, array
using ITensorNetworks: ITensorNetwork, vertices

i = Index(2, "i")
j = Index(3, "j")
k = Index(4, "k")
l = Index(5, "l")
m = Index(6, "m")

a = ITensor(rand(2, 3), i, j)
b = ITensor(rand(3, 4, 5), j, k, l)
c = ITensor(rand(5, 6), l, m)
itn = ITensorNetwork([a, b, c])

tn = convert(TensorNetwork, itn)
@test tn isa TensorNetwork
@test issetequal(arrays(tn), array.([a, b, c]))

itn = convert(ITensorNetwork, tn)
@test itn isa ITensorNetwork
@test issetequal(map(v -> array(itn[v]), vertices(itn)), array.([a, b, c]))

# TODO test Quantum
end
32 changes: 32 additions & 0 deletions test/integration/ITensors_test.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
@testset "ITensors" begin
using ITensors: ITensors, ITensor, Index, array

i = Index(2, "i")
j = Index(3, "j")
k = Index(4, "k")

itensor = ITensor(rand(2, 3, 4), i, j, k)

tensor = convert(Tensor, itensor)
@test tensor isa Tensor
@test size(tensor) == (2, 3, 4)
@test parent(tensor) == array(itensor)

tensor = Tensor(rand(2, 3, 4), (:i, :j, :k))
itensor = convert(ITensor, tensor)
@test itensor isa ITensor
@test size(itensor) == (2, 3, 4)
@test array(itensor) == parent(tensor)
@test all(
splat(==),
zip(map(x -> replace(x, "\"" => ""), string.(ITensors.tags.(ITensors.inds(itensor)))), ["i", "j", "k"]),
)

tn = rand(TensorNetwork, 4, 3)
itensors = convert(Vector{ITensor}, tn)
@test itensors isa Vector{ITensor}

tnr = convert(TensorNetwork, itensors)
@test tnr isa TensorNetwork
@test issetequal(arrays(tn), arrays(tnr))
end
2 changes: 2 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ if VERSION >= v"1.10"
include("integration/Makie_test.jl")
include("integration/KrylovKit_test.jl")
include("integration/Quac_test.jl")
include("integration/ITensors_test.jl")
include("integration/ITensorNetworks_test.jl")
end
end

Expand Down

0 comments on commit 03a6ad1

Please sign in to comment.