Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Confusing ITensor(::ITensorNetwork) behavior #98

Open
mtfishman opened this issue Jul 6, 2023 · 5 comments
Open

Confusing ITensor(::ITensorNetwork) behavior #98

mtfishman opened this issue Jul 6, 2023 · 5 comments

Comments

@mtfishman
Copy link
Member

The behavior of ITensor(::ITensorNetwork) is confusing, since it outputs a Vector{ITensor}:

julia> tn = randomITensorNetwork(named_grid((2, 2)); link_space=2)
ITensorNetwork{Tuple{Int64, Int64}} with 4 vertices:
4-element Vector{Tuple{Int64, Int64}}:
 (1, 1)
 (2, 1)
 (1, 2)
 (2, 2)

and 4 edge(s):
(1, 1) => (2, 1)
(1, 1) => (1, 2)
(2, 1) => (2, 2)
(1, 2) => (2, 2)

with vertex data:
4-element Dictionaries.Dictionary{Tuple{Int64, Int64}, Any}
 (1, 1) │ ((dim=2|id=727|"1×1↔2×1"), (dim=2|id=273|"1×1↔1×2"))
 (2, 1) │ ((dim=2|id=727|"1×1↔2×1"), (dim=2|id=845|"2×1↔2×2"))
 (1, 2) │ ((dim=2|id=273|"1×1↔1×2"), (dim=2|id=145|"1×2↔2×2"))
 (2, 2) │ ((dim=2|id=845|"2×1↔2×2"), (dim=2|id=145|"1×2↔2×2"))

julia> ITensor(tn)
4-element Vector{ITensor}:
 ITensor ord=2
Dim 1: (dim=2|id=727|"1×1↔2×1")
Dim 2: (dim=2|id=273|"1×1↔1×2")
NDTensors.Dense{Float64, Vector{Float64}}
 2×2
  1.291668655610816    0.5147066921592675
 -0.9207966219752203  -0.687320048765168
 ITensor ord=2
Dim 1: (dim=2|id=727|"1×1↔2×1")
Dim 2: (dim=2|id=845|"2×1↔2×2")
NDTensors.Dense{Float64, Vector{Float64}}
 2×2
 -1.482610874323555   0.2997297254174642
  1.2362723189696732  1.8881470232421553
 ITensor ord=2
Dim 1: (dim=2|id=273|"1×1↔1×2")
Dim 2: (dim=2|id=145|"1×2↔2×2")
NDTensors.Dense{Float64, Vector{Float64}}
 2×2
 -0.3620519644906389  -0.8149107592460717
 -0.6007286129069581  -1.794450655933629
 ITensor ord=2
Dim 1: (dim=2|id=845|"2×1↔2×2")
Dim 2: (dim=2|id=145|"1×2↔2×2")
NDTensors.Dense{Float64, Vector{Float64}}
 2×2
  0.7163493122261674   0.880775856816735
 -0.7909478596586718  -0.5341080305805886

I would have expected it would output an ITensor.

@JoeyT1994
Copy link
Contributor

This is coming from the following in src/itensornetwork.jl:

  function ITensors.ITensor(ψ::ITensorNetwork)
    vs = vertices(ψ)
    if length(vs) == 1
      return ψ[first(vs)]
    else
      return ITensor[ψ[v] for v in vertices(ψ)]
    end
  end

which I believe I added in one of my BP PRs in order to boil the message tensors and local tensors into a single ITensorNetwork, i.e.

mts_itensors = reduce(vcat, ITensor.(mts); init=ITensor[])

  contract_list = ITensor[mts_itensors; ITensor[tn[v] for v in subgraph_vertices]]
  tn = if isone(length(contract_list))
    copy(only(contract_list))
  else
    ITensorNetwork(contract_list)
  end
``` (line 45 in `beliefpropagation.jl`)

which can then be passed to `approx_itensornetwork` for turning into a specific network?
Would you rather `ITensor(::ITensorNetwork)` contracts the network down to a single `ITensor`? The above function I added is helpful for BP but perhaps there is a better way to name it?

@mtfishman
Copy link
Member Author

Yeah, we should come up with a better name for that functionality, or just use ITensorNetwork there.

Functions that are the same name as a type (and with the same capitalization as the type) are considered to be type constructors, and as a rule/convention should return an object of that type, i.e. they should satisfy T(args...) isa T.

I'm not sure what ITensor(tn::ITensorNetwork) should actually do, it could make sense for it to just call contract on that network, though that could be a bit surprising since that can be very expensive in general. Otherwise, it could be restricted to networks that only have one ITensor (i.e. isone(ne(tn))) and return that single ITensor, and otherwise throw an error.

@JoeyT1994
Copy link
Contributor

Yeah I am not sure why I wasn't using ITensorNetwork there. Probably to avoid the expense of doing multiple graph unions and instead only doing it once?

I suppose we could call the function that returns a vector of ITensors get_ITensors?
That makes sense about the type convention!

@mtfishman
Copy link
Member Author

You should be able to just use Vector{ITensor} or collect, those are the standard ways to get a Vector of a certain type of object.

@mtfishman
Copy link
Member Author

If those don't work for certain objects (like Vector{ITensor}(::ITensorNetwork)) then we should make them work.

b-kloss added a commit to b-kloss/ITensorNetworks.jl that referenced this issue Jan 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants