bsc-quantic / Qrochet.jl

Quantum Tensor Networks
https://bsc-quantic.github.io/Qrochet.jl/
Apache License 2.0
1 stars 0 forks source link

Fix `canonize` function and enhance index semantics #8

Closed jofrevalles closed 4 months ago

jofrevalles commented 4 months ago

Summary

This PR fixes the canonize function, enabling it to correctly canonize a desired Tensor within a Site of a Chain. We have enhanced this function to allow users to choose the mode (:qr or :svd) in which the canonization is applied. By default, the :qr option is selected, preserving the total number of tensors in the TensorNetwork. The :svd mode, on the other hand, introduces a new tensor which is connected by a hyperindex to the bond between sites, and it contains the Schmidt values. Additionally, we have created a comprehensive test set to ensure the function's reliability and performance.

Furthermore, we have refactored the logic inside leftindex and rightindex. Now, these indices are determined by the intersection of the indices with those of the adjacent tensor in the Chain, rather than relying on the order of inds in the tensors. This enhancement is expected to make our library more robust and error-resistant, as changes in the tensor order will no longer have unintended side effects.

Example

Here we show how we create a Chain and we canonize the middle tensor:

julia> function is_left_canonical(qtn, s::Site)
          label_r = rightindex(qtn, s)
          A = select(qtn, :tensor, s)
          try
              contracted = contract(A, replace(conj(A), label_r => :new_ind_name))
              return isapprox(contracted, Matrix{Float64}(I, size(A, label_r), size(A, label_r)), atol=1e-12)
          catch
              return false
          end
       end
is_left_canonical (generic function with 1 method)

julia> function is_right_canonical(qtn, s::Site)
          label_l = leftindex(qtn, s)
          A = select(qtn, :tensor, s)
          try
              contracted = contract(A, replace(conj(A), label_l => :new_ind_name))
              return isapprox(contracted, Matrix{Float64}(I, size(A, label_l), size(A, label_l)), atol=1e-12)
          catch
              return false
          end
       end
is_right_canonical (generic function with 1 method)

julia> qtn  = Chain(State(), Open(), [rand(4, 4), rand(4, 4, 4), rand(4, 4)])
MPS (inputs=0, outputs=3)

julia> canonized = canonize(qtn, Site(2); direction=:left, mode=:qr) # We left-canonize the tensor on the second site
MPS (inputs=0, outputs=3)

julia> is_left_canonical(canonized, Site(2))
true

julia> canonized = canonize(qtn, Site(2); direction=:right, mode=:svd) # We right-canonize the tensor on the second site using svd
MPS (inputs=0, outputs=3)

julia> length(tensors(canonized))
4

julia> contract(transform(TensorNetwork(canonized), HyperindConverter())) |> inds^C

julia> isapprox(contract(transform(TensorNetwork(canonized), Tenet.HyperindConverter())), contract(TensorNetwork(qtn)))
true
jofrevalles commented 4 months ago

Mmmm... This did not fail on my machine...

mofeing commented 4 months ago

I think it fails because some of this features require Tenet on master. Maybe we can release a new "patch" version of Tenet with this changes?

jofrevalles commented 4 months ago

I think it fails because some of this features require Tenet on master. Maybe we can release a new "patch" version of Tenet with this changes?

Ahh, it has to be that. Yes, that would be great, @mofeing !