Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 33 additions & 8 deletions src/algorithms/bp/beliefpropagation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ $(TYPEDFIELDS)
"Toggle for projecting messages onto the hermitian subspace immediately after update through BP equation"
project_hermitian::Bool = true

"When true, preserve bipartite structure of BPEnv inherited from input network"
bipartite::Bool = false

"Output verbosity level"
verbosity::Int = 2
end
Expand Down Expand Up @@ -54,21 +57,43 @@ function leading_boundary(env₀::BPEnv, network::InfiniteSquareNetwork, alg::Be
return env, ϵ
end
end
function leading_boundary(env₀::BPEnv, state, args...)
return leading_boundary(env₀, InfiniteSquareNetwork(state), args...)
function leading_boundary(env₀::BPEnv, state::InfiniteState, alg::BeliefPropagation)
if alg.bipartite
@assert _state_bipartite_check(state)
end
return leading_boundary(env₀, InfiniteSquareNetwork(state), alg)
end

"""
One iteration to update the BP environment.
"""
function bp_iteration(network::InfiniteSquareNetwork, env::BPEnv, alg::BeliefPropagation)
messages = map(eachindex(env)) do I
M = update_message(I, network, env)
normalize!(M)
alg.project_hermitian && (M = project_hermitian!!(M))
return M
if alg.bipartite
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it's not easier to follow if we just write this out manually, calling similar and writing out the coordinates like that.
It probably doesn't matter all that much but I'd like to avoid the double map call, which allocates twice

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Performance suggestions are always welcome :) But this way, if we want to differentiate through BP, I guess we must use Mooncake/Enzyme (with mutation support)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah good point! I guess already the normalize! call might be a problem, but then maybe it's just fine to merge as is

@assert size(network, 1) == size(network, 2) == 2
messages = similar(env.messages)
for (d, r) in Iterators.product(1:4, 1:2)
# update BP env around 1st column of state
# [N/S, 1:2, 1], [E/W, 1:2, 2]
c = (d == NORTH || d == SOUTH) ? 1 : 2
I = CartesianIndex(d, r, c)
M = update_message(I, network, env)
normalize!(M)
alg.project_hermitian && (M = project_hermitian!!(M))
messages[I] = M
# copy to the other column
I′ = CartesianIndex(d, _next(r, 2), _next(c, 2))
messages[I′] = copy(M)
end
return BPEnv(messages)
else
messages = map(eachindex(env)) do I
M = update_message(I, network, env)
normalize!(M)
alg.project_hermitian && (M = project_hermitian!!(M))
return M
end
return BPEnv(messages)
end
return BPEnv(messages)
end

"""
Expand Down
18 changes: 18 additions & 0 deletions src/algorithms/bp/gaugefix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ Algorithm for gauging PEPS with belief propagation fixed point messages.
# TODO: add options
end

function _bpenv_bipartite_check(env::BPEnv)
for (r, c) in Iterators.product(1:2, 1:2)
r′, c′ = _next(r, 2), _next(c, 2)
if !all(env[:, r, c] .== env[:, r′, c′])
return false
end
end
return true
end

"""
gauge_fix(psi::Union{InfinitePEPS, InfinitePEPO}, alg::BPGauge, env::BPEnv)

Expand All @@ -15,11 +25,19 @@ an [`InfinitePEPO`](@ref) interpreted as purified state with two physical legs)
using fixed point environment `env` of belief propagation.
"""
function gauge_fix(psi::InfinitePEPS, alg::BPGauge, env::BPEnv)
bipartite = _state_bipartite_check(psi) && _bpenv_bipartite_check(env)
psi′ = copy(psi)
XXinv = map(eachcoordinate(psi, 1:2)) do I
_, X, Xinv = _bp_gauge_fix!(CartesianIndex(I), psi′, env)
return X, Xinv
end
if bipartite
# copy 1st column to 2nd column to eliminate differences
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried not to do the useless update of the 2nd column before copying from the 1st column. But then constinferred of gauge_fix is broken.

# caused by order of applying gauge transformations
for r in 1:2
psi′[_next(r, 2), 2] = copy(psi′[r, 1])
end
end
return psi′, XXinv
end
function gauge_fix(psi::InfinitePEPO, alg::BPGauge, env::BPEnv)
Expand Down
6 changes: 3 additions & 3 deletions src/algorithms/time_evolution/gaugefix_su.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ function _trivial_gates(elt::Type{<:Number}, lattice::Matrix{S}) where {S <: Ele
end

"""
$(SIGNATURES)
gauge_fix(psi::Union{InfinitePEPS, InfinitePEPO}, alg::SUGauge)

Fix the gauge of `psi` using trivial simple update.
"""
function gauge_fix(psi::InfinitePEPS, alg::SUGauge)
function gauge_fix(psi::InfiniteState, alg::SUGauge)
gates = _trivial_gates(scalartype(psi), physicalspace(psi))
su_alg = SimpleUpdate(; trunc = FixedSpaceTruncation())
su_alg = SimpleUpdate(; trunc = FixedSpaceTruncation(), bipartite = _state_bipartite_check(psi))
wts0 = SUWeight(psi)
# use default constructor to avoid calculation of exp(-H * 0)
evolver = TimeEvolver(su_alg, 0.0, alg.maxiter, gates, SUState(0, 0.0, psi, wts0))
Expand Down
2 changes: 1 addition & 1 deletion src/algorithms/time_evolution/simpleupdate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ $(TYPEDFIELDS)
imaginary_time::Bool = true
"When true, force the usage of 3-site simple update"
force_3site::Bool = false
"(Only applicable to InfinitePEPS) When true, assume bipartite unit cell structure"
"When true, assume bipartite unit cell structure"
bipartite::Bool = false
"(Only applicable to InfinitePEPO)
When true, the PEPO is regarded as a purified PEPS, and updated as
Expand Down
18 changes: 17 additions & 1 deletion src/algorithms/time_evolution/time_evolve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@ end

Base.iterate(it::TimeEvolver) = iterate(it, it.state)

function _state_bipartite_check(psi::InfiniteState)
if isa(psi, InfinitePEPO)
@assert size(psi, 3) == 1 "Input InfinitePEPO is expected to have only one layer."
end
if !(size(psi, 1) == size(psi, 2) == 2)
return false
end
for (r, c) in Iterators.product(1:2, 1:2)
r′, c′ = _next(r, 2), _next(c, 2)
if psi[r, c] != psi[r′, c′]
return false
end
end
return true
end

function _timeevol_sanity_check(
ψ₀::InfiniteState, Pspaces::M, alg::A
) where {A <: TimeEvolution, M <: AbstractMatrix{<:ElementarySpace}}
Expand All @@ -40,7 +56,7 @@ function _timeevol_sanity_check(
@assert ψ₀ isa InfinitePEPO "alg.purified = false is only applicable to PEPO."
end
if hasfield(typeof(alg), :bipartite) && alg.bipartite
@assert Nr == Nc == 2 "`bipartite = true` requires 2 x 2 unit cell size."
@assert _state_bipartite_check(ψ₀) "Input state is not bipartite with 2 x 2 unit cell."
end
return nothing
end
6 changes: 5 additions & 1 deletion test/timeevol/cluster_projectors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ using PEPSKit
using LinearAlgebra
using Random
import MPSKitModels: hubbard_space
using PEPSKit: sdiag_pow, _cluster_truncate!, _flip_virtuals!
using PEPSKit: sdiag_pow, _cluster_truncate!, _flip_virtuals!, _next
using MPSKit: GenericMPSTensor, MPSBondTensor
include("cluster_tools.jl")

Expand Down Expand Up @@ -112,6 +112,10 @@ end
trunc_env0 = truncerror(; atol = 1.0e-12) & truncrank(4)
trunc_env = truncerror(; atol = 1.0e-12) & truncrank(16)
peps = InfinitePEPS(rand, Float64, Pspace, Vspace, Vspace'; unitcell = (Nr, Nc))
# make state bipartite
for r in 1:2
peps.A[_next(r, 2), 2] = copy(peps.A[r, 1])
end
wts = SUWeight(peps)
ham = real(
hubbard_model(
Expand Down
6 changes: 5 additions & 1 deletion test/timeevol/sitedep_truncation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ using LinearAlgebra
using Random
using TensorKit
using PEPSKit
using PEPSKit: NORTH, EAST
using PEPSKit: NORTH, EAST, _next

function get_bonddims(peps::InfinitePEPS)
xdims = collect(dim(domain(t, EAST)) for t in peps.A)
Expand All @@ -22,6 +22,10 @@ end
ham = real(heisenberg_XYZ(InfiniteSquare(Nr, Nc); Jx = 1.0, Jy = 1.0, Jz = 1.0))
Random.seed!(100)
peps0 = InfinitePEPS(rand, Float64, ℂ^2, ℂ^10; unitcell = (Nr, Nc))
# make state bipartite
for r in 1:2
peps0.A[_next(r, 2), 2] = copy(peps0.A[r, 1])
end
env0 = SUWeight(peps0)
normalize!.(peps0.A, Inf)
# set trunc to be compatible with bipartite structure
Expand Down
6 changes: 6 additions & 0 deletions test/timeevol/tf_ising_finiteT.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ dt, nstep = 1.0e-3, 400
# PEPO approach: results at β, or T = 2.5
alg = SimpleUpdate(; trunc = trunc_pepo, purified = false, bipartite)
pepo, wts, info = time_evolve(pepo0, ham, dt, nstep, alg, wts0)

## BP gauge fixing
bp_alg = BeliefPropagation(; maxiter = 100, tol = 1.0e-9, bipartite)
bp_env, = leading_boundary(BPEnv(ones, Float64, pepo), pepo, bp_alg)
pepo, = gauge_fix(pepo, BPGauge(), bp_env)

env = converge_env(InfinitePartitionFunction(pepo), 16)
result_β = measure_mag(pepo, env)
@info "tr(σ(x,z)ρ) at T = $(1 / β): $(result_β)."
Expand Down