Skip to content
This repository has been archived by the owner on Jul 7, 2024. It is now read-only.

Add mixed_canonize function #10

Merged
merged 9 commits into from
Feb 20, 2024
22 changes: 11 additions & 11 deletions src/Ansatz/Chain.jl
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,11 @@ function rightindex(::Union{Open, Periodic}, tn::Chain, site::Site)
end
end

canonize(tn::Chain, args...; kwargs...) = canonize!(deepcopy(tn), args...; kwargs...)
canonize!(tn::Chain, args...; kwargs...) = canonize!(boundary(tn), tn, args...; kwargs...)
canonize_site(tn::Chain, args...; kwargs...) = canonize_site!(deepcopy(tn), args...; kwargs...)
canonize_site!(tn::Chain, args...; kwargs...) = canonize_site!(boundary(tn), tn, args...; kwargs...)

# NOTE: in mode == :svd the spectral weights are stored in a vector connected to the now virtual hyperindex!
function canonize!(::Open, tn::Chain, site::Site; direction::Symbol, mode = :qr)
function canonize_site!(::Open, tn::Chain, site::Site; direction::Symbol, mode = :qr)
left_inds = Symbol[]
right_inds = Symbol[]

Expand Down Expand Up @@ -187,32 +187,32 @@ function canonize!(::Open, tn::Chain, site::Site; direction::Symbol, mode = :qr)
return tn
end

mixed_canonical_form(tn::Chain, args...; kwargs...) = mixed_canonical_form!(deepcopy(tn), args...; kwargs...)
mixed_canonical_form!(tn::Chain, args...; kwargs...) = mixed_canonical_form!(boundary(tn), tn, args...; kwargs...)
mixed_canonize(tn::Chain, args...; kwargs...) = mixed_canonize!(deepcopy(tn), args...; kwargs...)
mixed_canonize!(tn::Chain, args...; kwargs...) = mixed_canonize!(boundary(tn), tn, args...; kwargs...)

"""
mixed_canonical_form!(boundary::Boundary, tn::Chain, center::Site)
mixed_canonize!(boundary::Boundary, tn::Chain, center::Site)
jofrevalles marked this conversation as resolved.
Show resolved Hide resolved

Transform a `Chain` tensor network into the mixed-canonical form, that is,
for i < center the tensors are left-canonical and for i > center the tensors are right-canonical,
and in the center there is a matrix with singular values.
"""
function mixed_canonical_form!(::Open, tn::Chain, center::Site) # TODO: center could be a range of sites
function mixed_canonize!(::Open, tn::Chain, center::Site) # TODO: center could be a range of sites
N = length(sites(tn))

# Left-to-right QR sweep -> get left-canonical tensors
for i in 1:N-1
canonize!(tn, Site(i); direction = :left, mode = :qr)
canonize_site!(tn, Site(i); direction = :left, mode = :qr)
end

# Right-to-left QR sweep -> get left-canonical tensors for i > center
for i in N:-1:1
if i > center.id
canonize!(tn, Site(i); direction = :right, mode = :qr)
canonize_site!(tn, Site(i); direction = :right, mode = :qr)
elseif i == center.id
canonize!(tn, Site(i); direction = :left, mode = :svd)
canonize_site!(tn, Site(i); direction = :left, mode = :svd)
else
canonize!(tn, Site(i); direction = :left, mode = :qr)
canonize_site!(tn, Site(i); direction = :left, mode = :qr)
end
end

Expand Down
16 changes: 8 additions & 8 deletions test/Ansatz/Chain_test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
@test rightsite(qtn, Site(1)) == Site(2)
end

@testset "Canonical forms" begin
@testset "Canonization" begin
using Tenet

function is_left_canonical(qtn, s::Site)
Expand All @@ -76,33 +76,33 @@
end
end

@testset "canonize" begin
@testset "canonize_site" begin
qtn = Chain(State(), Open(), [rand(4, 4), rand(4, 4, 4), rand(4, 4)])

@test_throws ArgumentError canonize!(qtn, Site(1); direction=:right)
@test_throws ArgumentError canonize!(qtn, Site(3); direction=:left)
@test_throws ArgumentError canonize_site!(qtn, Site(1); direction=:right)
@test_throws ArgumentError canonize_site!(qtn, Site(3); direction=:left)

for mode in [:qr, :svd]
for i in 1:length(sites(qtn))
if i != 1
canonized = canonize(qtn, Site(i); direction=:right, mode=mode)
canonized = canonize_site(qtn, Site(i); direction=:right, mode=mode)
@test is_right_canonical(canonized, Site(i))
@test isapprox(contract(transform(TensorNetwork(canonized), Tenet.HyperindConverter())), contract(TensorNetwork(qtn)))
elseif i != length(sites(qtn))
canonized = canonize(qtn, Site(i); direction=:left, mode=mode)
canonized = canonize_site(qtn, Site(i); direction=:left, mode=mode)
@test is_left_canonical(canonized, Site(i))
@test isapprox(contract(transform(TensorNetwork(canonized), Tenet.HyperindConverter())), contract(TensorNetwork(qtn)))
end
end
end

# Ensure that svd creates a new tensor
@test length(tensors(canonize(qtn, Site(2); direction=:right, mode=:svd))) == 4
@test length(tensors(canonize_site(qtn, Site(2); direction=:right, mode=:svd))) == 4
end

@testset "mixed_canonical_form" begin
qtn = Chain(State(), Open(), [rand(4, 4), rand(4, 4, 4), rand(4, 4, 4), rand(4, 4, 4), rand(4, 4)])
canonized = mixed_canonical_form(qtn, Site(3))
canonized = mixed_canonize(qtn, Site(3))

@test is_left_canonical(canonized, Site(1))
@test is_left_canonical(canonized, Site(2))
Expand Down
Loading