From ec7ec3b7aff67fe54f1bc55cf94babe2b7989065 Mon Sep 17 00:00:00 2001 From: Joseph Tindall Date: Mon, 6 May 2024 16:17:37 -0400 Subject: [PATCH 01/27] New BP alternating update --- src/ITensorNetworks.jl | 1 + src/formnetworks/quadraticformnetwork.jl | 2 +- .../alternating_update_bp.jl | 43 +++++++++++++++++++ test/test_belief_propagation_dmrg.jl | 27 ++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 src/solvers/alternating_update/alternating_update_bp.jl create mode 100644 test/test_belief_propagation_dmrg.jl diff --git a/src/ITensorNetworks.jl b/src/ITensorNetworks.jl index 2eca4ad4..5ab9bbc1 100644 --- a/src/ITensorNetworks.jl +++ b/src/ITensorNetworks.jl @@ -50,6 +50,7 @@ include("solvers/defaults.jl") include("solvers/insert/insert.jl") include("solvers/extract/extract.jl") include("solvers/alternating_update/alternating_update.jl") +include("solvers/alternating_update/alternating_update_bp.jl") include("solvers/alternating_update/region_update.jl") include("solvers/tdvp.jl") include("solvers/dmrg.jl") diff --git a/src/formnetworks/quadraticformnetwork.jl b/src/formnetworks/quadraticformnetwork.jl index d0254501..c8150fe9 100644 --- a/src/formnetworks/quadraticformnetwork.jl +++ b/src/formnetworks/quadraticformnetwork.jl @@ -59,7 +59,7 @@ function QuadraticFormNetwork( kwargs..., ) blf = BilinearFormNetwork( - bra, + ket, ket; dual_site_index_map=dual_index_map, dual_link_index_map=dual_index_map, diff --git a/src/solvers/alternating_update/alternating_update_bp.jl b/src/solvers/alternating_update/alternating_update_bp.jl new file mode 100644 index 00000000..b0afdec1 --- /dev/null +++ b/src/solvers/alternating_update/alternating_update_bp.jl @@ -0,0 +1,43 @@ +using ITensors: state +using ITensors.ITensorMPS: linkind +using NamedGraphs.GraphsExtensions: GraphsExtensions +using NamedGraphs.PartitionedGraphs: partitionvertices + +default_vertex_sequence(ψ::AbstractITensorNetwork) = vertices(ψ) + +function alternating_update( + alg::Algorithm"bp_onesite", A::AbstractITensorNetwork, + ψ::AbstractITensorNetwork; start_vertex = GraphsExtensions.default_root_vertex(ψ), nsweeps = 1, nsites =1, kwargs...) + + ψAψ = QuadraticFormNetwork(A, ψ) + ψIψ = QuadraticFormNetwork(ψ) + ψAψ_bpc = BeliefPropagationCache(ψAψ) + ψIψ_bpc = BeliefPropagationCache(ψIψ) + + sweep_plans = default_sweep_plans(nsweeps,ψ;root_vertex = start_vertex, nsites, extracter = default_extracter(), extracter_kwargs=(;), updater = eigsolve_updater, updater_kwargs=(;), transform_operator_kwargs=(;), inserter = default_inserter(), inserter_kwargs = (;), transform_operator=default_transform_operator()) + for which_sweep in eachindex(sweep_plans) + sweep_plan = sweep_plans[which_sweep] + for which_region_update in eachindex(sweep_plan) + ψAψ_bpc = update(ψAψ_bpc) + ψIψ_bpc = update(ψIψ_bpc) + (region, region_kwargs) = sweep_plan[which_region_update] + v = only(region) + form_v = ket_vertex(ψAψ, v) + ∂ψAψ_bpc_∂r = environment(ψAψ_bpc, [form_v]) + state = ψAψ[form_v] + #Now get incoming messages to V + messages = environment(ψIψ_bpc, partitionvertices(ψIψ_bpc, [form_v])) + #Square root and put onto state + + #eigsolve + + #Inv square root onto new state + + #Update wavefuncion + + end + end + + + return 0 +end \ No newline at end of file diff --git a/test/test_belief_propagation_dmrg.jl b/test/test_belief_propagation_dmrg.jl new file mode 100644 index 00000000..87157884 --- /dev/null +++ b/test/test_belief_propagation_dmrg.jl @@ -0,0 +1,27 @@ +@eval module $(gensym()) + +using NamedGraphs.NamedGraphGenerators: named_grid +using ITensors: ITensors, Algorithm +using ITensors: siteinds +using ITensorNetworks: alternating_update, random_tensornetwork, ttn +using ITensorNetworks.ModelHamiltonians: heisenberg +using ITensorNetworks: ITensorNetwork + +using Random: Random + +using Test: @test, @testset + +@testset "belief_propagation dmrg" begin + ITensors.disable_warn_order() + + g = named_grid((3, 1)) + s = siteinds("S=1/2", g) + χ = 2 + Random.seed!(1234) + ψ = random_tensornetwork(s; link_space=χ) + A = ITensorNetwork(ttn(heisenberg(g), s)) + + @show alternating_update(Algorithm("bp_onesite"), A, ψ) + +end +end From bd05519776dadb3f4aec54a4ca7c80381129e171 Mon Sep 17 00:00:00 2001 From: Joey Date: Thu, 9 May 2024 12:00:53 -0400 Subject: [PATCH 02/27] Working BP DMRG Solver --- src/ITensorNetworks.jl | 1 - src/abstractindsnetwork.jl | 10 ++-- .../alternating_update/alternating_update.jl | 15 +++++- .../alternating_update_bp.jl | 43 ---------------- .../alternating_update/region_update.jl | 49 ++++++++++++++++++- src/solvers/dmrg.jl | 24 ++++++++- src/solvers/extract/extract.jl | 15 ++++++ src/solvers/insert/insert.jl | 40 +++++++++++++++ src/solvers/local_solvers/eigsolve.jl | 23 +++++++++ test/test_belief_propagation_dmrg.jl | 18 ++++--- 10 files changed, 181 insertions(+), 57 deletions(-) delete mode 100644 src/solvers/alternating_update/alternating_update_bp.jl diff --git a/src/ITensorNetworks.jl b/src/ITensorNetworks.jl index 5ab9bbc1..2eca4ad4 100644 --- a/src/ITensorNetworks.jl +++ b/src/ITensorNetworks.jl @@ -50,7 +50,6 @@ include("solvers/defaults.jl") include("solvers/insert/insert.jl") include("solvers/extract/extract.jl") include("solvers/alternating_update/alternating_update.jl") -include("solvers/alternating_update/alternating_update_bp.jl") include("solvers/alternating_update/region_update.jl") include("solvers/tdvp.jl") include("solvers/dmrg.jl") diff --git a/src/abstractindsnetwork.jl b/src/abstractindsnetwork.jl index d25f5abb..eda958f6 100644 --- a/src/abstractindsnetwork.jl +++ b/src/abstractindsnetwork.jl @@ -138,9 +138,13 @@ function insert_linkinds( for e in edges # TODO: Change to check if it is empty. if !isassigned(indsnetwork, e) - iₑ = Index(link_space, edge_tag(e)) - # TODO: Allow setting with just `Index`. - indsnetwork[e] = [iₑ] + if !isnothing(link_space) + iₑ = Index(link_space, edge_tag(e)) + # TODO: Allow setting with just `Index`. + indsnetwork[e] = [iₑ] + else + indsnetwork[e] = [] + end end end return indsnetwork diff --git a/src/solvers/alternating_update/alternating_update.jl b/src/solvers/alternating_update/alternating_update.jl index 160e68f9..156b983a 100644 --- a/src/solvers/alternating_update/alternating_update.jl +++ b/src/solvers/alternating_update/alternating_update.jl @@ -4,7 +4,7 @@ using NamedGraphs.GraphsExtensions: GraphsExtensions function alternating_update( operator, - init_state::AbstractTTN; + init_state; nsweeps, # define default for each solver implementation nsites, # define default for each level of solver implementation updater, # this specifies the update performed locally @@ -52,7 +52,7 @@ end function alternating_update( projected_operator, - init_state::AbstractTTN, + init_state, sweep_plans; outputlevel=default_outputlevel(), checkdone=default_checkdone(), # @@ -102,6 +102,17 @@ function alternating_update(operator::AbstractTTN, init_state::AbstractTTN; kwar return alternating_update(projected_operator, init_state; kwargs...) end +function alternating_update(operator::AbstractITensorNetwork, init_state::AbstractITensorNetwork, sweep_plans; kwargs...) + ψOψ = QuadraticFormNetwork(operator, init_state) + ψIψ = QuadraticFormNetwork(init_state) + ψOψ_bpc = BeliefPropagationCache(ψOψ) + ψIψ_bpc = BeliefPropagationCache(ψIψ) + ψOψ_bpc = update(ψOψ_bpc) + ψIψ_bpc = update(ψIψ_bpc) + projected_operator = (ψOψ_bpc, ψIψ_bpc) + return alternating_update(projected_operator, init_state, sweep_plans; kwargs...) +end + function alternating_update( operator::AbstractTTN, init_state::AbstractTTN, sweep_plans; kwargs... ) diff --git a/src/solvers/alternating_update/alternating_update_bp.jl b/src/solvers/alternating_update/alternating_update_bp.jl deleted file mode 100644 index b0afdec1..00000000 --- a/src/solvers/alternating_update/alternating_update_bp.jl +++ /dev/null @@ -1,43 +0,0 @@ -using ITensors: state -using ITensors.ITensorMPS: linkind -using NamedGraphs.GraphsExtensions: GraphsExtensions -using NamedGraphs.PartitionedGraphs: partitionvertices - -default_vertex_sequence(ψ::AbstractITensorNetwork) = vertices(ψ) - -function alternating_update( - alg::Algorithm"bp_onesite", A::AbstractITensorNetwork, - ψ::AbstractITensorNetwork; start_vertex = GraphsExtensions.default_root_vertex(ψ), nsweeps = 1, nsites =1, kwargs...) - - ψAψ = QuadraticFormNetwork(A, ψ) - ψIψ = QuadraticFormNetwork(ψ) - ψAψ_bpc = BeliefPropagationCache(ψAψ) - ψIψ_bpc = BeliefPropagationCache(ψIψ) - - sweep_plans = default_sweep_plans(nsweeps,ψ;root_vertex = start_vertex, nsites, extracter = default_extracter(), extracter_kwargs=(;), updater = eigsolve_updater, updater_kwargs=(;), transform_operator_kwargs=(;), inserter = default_inserter(), inserter_kwargs = (;), transform_operator=default_transform_operator()) - for which_sweep in eachindex(sweep_plans) - sweep_plan = sweep_plans[which_sweep] - for which_region_update in eachindex(sweep_plan) - ψAψ_bpc = update(ψAψ_bpc) - ψIψ_bpc = update(ψIψ_bpc) - (region, region_kwargs) = sweep_plan[which_region_update] - v = only(region) - form_v = ket_vertex(ψAψ, v) - ∂ψAψ_bpc_∂r = environment(ψAψ_bpc, [form_v]) - state = ψAψ[form_v] - #Now get incoming messages to V - messages = environment(ψIψ_bpc, partitionvertices(ψIψ_bpc, [form_v])) - #Square root and put onto state - - #eigsolve - - #Inv square root onto new state - - #Update wavefuncion - - end - end - - - return 0 -end \ No newline at end of file diff --git a/src/solvers/alternating_update/region_update.jl b/src/solvers/alternating_update/region_update.jl index b92adc8c..14364ec9 100644 --- a/src/solvers/alternating_update/region_update.jl +++ b/src/solvers/alternating_update/region_update.jl @@ -41,7 +41,7 @@ end function region_update( projected_operator, - state; + state::AbstractTTN; outputlevel, which_sweep, sweep_plan, @@ -118,3 +118,50 @@ function region_update( !(isnothing(region_printer)) && region_printer(; all_kwargs...) return state, projected_operator end + +function region_update(projected_operator, state; outputlevel, + which_sweep, + sweep_plan, + which_region_update, + region_printer, + (region_observer!)) + + (region, region_kwargs) = sweep_plan[which_region_update] + (; + extracter, + extracter_kwargs, + updater, + updater_kwargs, + inserter, + inserter_kwargs, + transform_operator, + transform_operator_kwargs, + internal_kwargs, + ) = region_kwargs + ψOψ_bpc, ψIψ_bpc = projected_operator + + local_state, ∂ψOψ_bpc_∂r, sqrt_mts, inv_sqrt_mts = extracter(state, ψOψ_bpc, ψIψ_bpc, region; extracter_kwargs...) + + local_state, _ = updater(local_state, ∂ψOψ_bpc_∂r, sqrt_mts, inv_sqrt_mts; updater_kwargs...) + + state, ψOψ_bpc, ψIψ_bpc, spec, info = inserter(state, ψOψ_bpc, ψIψ_bpc, local_state, region; inserter_kwargs...) + + all_kwargs = (; + which_region_update, + sweep_plan, + total_sweep_steps=length(sweep_plan), + end_of_sweep=(which_region_update == length(sweep_plan)), + state, + region, + which_sweep, + spec, + outputlevel, + info..., + region_kwargs..., + internal_kwargs..., + ) + update_observer!(region_observer!; all_kwargs...) + !(isnothing(region_printer)) && region_printer(; all_kwargs...) + + return state, (ψOψ_bpc, ψIψ_bpc) +end diff --git a/src/solvers/dmrg.jl b/src/solvers/dmrg.jl index 85bfa678..320c3204 100644 --- a/src/solvers/dmrg.jl +++ b/src/solvers/dmrg.jl @@ -6,7 +6,7 @@ Overload of `ITensors.ITensorMPS.dmrg`. """ function ITensorMPS.dmrg( operator, - init_state; + init_state::AbstractTTN; nsweeps, nsites=2, updater=eigsolve_updater, @@ -24,6 +24,28 @@ function ITensorMPS.dmrg( return eigval, state end +function ITensorMPS.dmrg( + operator, + init_state; + nsweeps, + nsites=2, + updater=bp_eigsolve_updater, + inserter = bp_inserter, + extracter = bp_extracter, + (region_observer!)=nothing, + kwargs..., +) + eigvals_ref = Ref{Any}() + region_observer! = compose_observers( + region_observer!, ValuesObserver((; eigvals=eigvals_ref)) + ) + state = alternating_update( + operator, init_state; nsweeps, nsites, updater, region_observer!, inserter, extracter, kwargs... + ) + eigval = only(eigvals_ref[]) + return eigval, state +end + """ Overload of `KrylovKit.eigsolve`. """ diff --git a/src/solvers/extract/extract.jl b/src/solvers/extract/extract.jl index feb57c2f..64a3fae5 100644 --- a/src/solvers/extract/extract.jl +++ b/src/solvers/extract/extract.jl @@ -24,3 +24,18 @@ function default_extracter(state, projected_operator, region, ortho; internal_kw projected_operator = position(projected_operator, state, region) return state, projected_operator, local_tensor end + +function bp_extracter(ψ::AbstractITensorNetwork, ψAψ_bpc::BeliefPropagationCache, ψIψ_bpc::BeliefPropagationCache, region; + regularization = 10*eps(scalartype(ψ))) + form_network = unpartitioned_graph(partitioned_tensornetwork(ψAψ_bpc)) + form_ket_vertices, form_bra_vertices = ket_vertices(form_network, region), bra_vertices(form_network, region) + ∂ψAψ_bpc_∂r = environment(ψAψ_bpc, [form_ket_vertices; form_bra_vertices]) + state = prod(ψ[v] for v in region) + messages = environment(ψIψ_bpc, partitionvertices(ψIψ_bpc, form_ket_vertices)) + f_sqrt = sqrt ∘ (x -> x + regularization) + f_inv_sqrt = inv ∘ sqrt ∘ (x -> x + regularization) + sqrt_mts = [ITensorsExtensions.map_eigvals(f_sqrt, mt, inds(mt)[1], inds(mt)[2]; ishermitian=true) for mt in messages] + inv_sqrt_mts = [ITensorsExtensions.map_eigvals(f_inv_sqrt, mt, inds(mt)[1], inds(mt)[2]; ishermitian=true) for mt in messages] + + return state, ∂ψAψ_bpc_∂r, sqrt_mts, inv_sqrt_mts +end \ No newline at end of file diff --git a/src/solvers/insert/insert.jl b/src/solvers/insert/insert.jl index a0250c95..f78ec8ec 100644 --- a/src/solvers/insert/insert.jl +++ b/src/solvers/insert/insert.jl @@ -48,3 +48,43 @@ function default_inserter( state = set_ortho_region(state, [v]) return state, nothing end + +function bp_inserter(ψ::AbstractITensorNetwork, ψAψ_bpc::BeliefPropagationCache, + ψIψ_bpc::BeliefPropagationCache, state::ITensor, region; cache_update_kwargs = (;), kwargs...) + + spec = nothing + + form_network = unpartitioned_graph(partitioned_tensornetwork(ψAψ_bpc)) + if length(region) == 1 + states = [state] + elseif length(region) == 2 + v1, v2 = region[1], region[2] + e = edgetype(ψ)(v1, v2) + pe = partitionedge(ψAψ_bpc, ket_vertex(form_network, v1) => bra_vertex(form_network, v2)) + stateᵥ₁, stateᵥ₂, spec = factorize_svd(state,uniqueinds(ψ[v1], ψ[v2]); ortho="none", tags=edge_tag(e),kwargs...) + states = noprime.([stateᵥ₁, stateᵥ₂]) + delete!(messages(ψAψ_bpc), pe) + delete!(messages(ψIψ_bpc), pe) + delete!(messages(ψAψ_bpc), reverse(pe)) + delete!(messages(ψIψ_bpc), reverse(pe)) + end + + for (i, v) in enumerate(region) + state = states[i] + form_bra_v, form_ket_v = bra_vertex(form_network, v), ket_vertex(form_network, v) + ψ[v] =state + state_dag = replaceinds(dag(state), inds(state), dual_index_map(form_network).(inds(state))) + ψAψ_bpc = update_factor(ψAψ_bpc, form_ket_v, state) + ψAψ_bpc = update_factor(ψAψ_bpc, form_bra_v, state_dag) + ψIψ_bpc = update_factor(ψIψ_bpc, form_ket_v, state) + ψIψ_bpc = update_factor(ψIψ_bpc, form_bra_v, state_dag) + end + + ψAψ_bpc = update(ψAψ_bpc; cache_update_kwargs...) + ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) + updated_ψAψ = unpartitioned_graph(partitioned_tensornetwork(ψAψ_bpc)) + updated_ψIψ = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) + eigval = scalar(updated_ψAψ; cache! = Ref(ψAψ_bpc), alg = "bp") / scalar(updated_ψIψ; cache! = Ref(ψIψ_bpc), alg = "bp") + + return ψ, ψAψ_bpc, ψIψ_bpc, spec, (; eigvals=[eigval]) +end \ No newline at end of file diff --git a/src/solvers/local_solvers/eigsolve.jl b/src/solvers/local_solvers/eigsolve.jl index ed993d80..824fa038 100644 --- a/src/solvers/local_solvers/eigsolve.jl +++ b/src/solvers/local_solvers/eigsolve.jl @@ -32,3 +32,26 @@ function eigsolve_updater( ) return vecs[1], (; info, eigvals=vals) end + +function bp_eigsolve_updater(init::ITensor, ∂ψAψ_bpc_∂r, sqrt_mts, inv_sqrt_mts; kwargs...) + + #TODO: Put inv_sqrt_mts onto ∂ψAψ_bpc_∂r beforehand. Need to do this in an efficient way without + #precontracting ∂ψAψ_bpc_∂r + function get_new_state(∂ψAψ_bpc_∂r, inv_sqrt_mts, state::ITensor; sequence = "automatic") + state = noprime(contract([state; inv_sqrt_mts])) + state = dag(noprime(contract([state; ∂ψAψ_bpc_∂r]; sequence))) + return noprime(contract([state; (inv_sqrt_mts)])) + end + + init = noprime(contract([init; sqrt_mts])) + sequence = optimal_contraction_sequence([init; ∂ψAψ_bpc_∂r]) + get_new_state_partial = partial(get_new_state, ∂ψAψ_bpc_∂r, inv_sqrt_mts; sequence) + howmany = 1 + + vals, vecs, info = eigsolve(get_new_state_partial,init,howmany,:SR; ishermitian = true, kwargs...) + + state = first(vecs) + state = noprime(contract([state; inv_sqrt_mts])) + + return state, (; info, eigvals=vals) +end \ No newline at end of file diff --git a/test/test_belief_propagation_dmrg.jl b/test/test_belief_propagation_dmrg.jl index 87157884..0350d950 100644 --- a/test/test_belief_propagation_dmrg.jl +++ b/test/test_belief_propagation_dmrg.jl @@ -1,9 +1,10 @@ @eval module $(gensym()) -using NamedGraphs.NamedGraphGenerators: named_grid +using NamedGraphs: nv +using NamedGraphs.NamedGraphGenerators: named_grid, named_comb_tree, named_binary_tree using ITensors: ITensors, Algorithm -using ITensors: siteinds -using ITensorNetworks: alternating_update, random_tensornetwork, ttn +using ITensors: dmrg, siteinds +using ITensorNetworks: alternating_update, bp_inserter, bp_extracter, bp_eigsolve_updater, random_tensornetwork, ttn, inner, maxlinkdim using ITensorNetworks.ModelHamiltonians: heisenberg using ITensorNetworks: ITensorNetwork @@ -14,14 +15,19 @@ using Test: @test, @testset @testset "belief_propagation dmrg" begin ITensors.disable_warn_order() - g = named_grid((3, 1)) + g = named_binary_tree(4) s = siteinds("S=1/2", g) - χ = 2 + χ, χmax = 1, 10 Random.seed!(1234) ψ = random_tensornetwork(s; link_space=χ) A = ITensorNetwork(ttn(heisenberg(g), s)) + inserter_kwargs = (; maxdim = χmax) + updater_kwargs = (; tol = 1e-14, krylovdim = 1, maxiter = 1, verbosity = 0, eager = false) + nsites, nsweeps = 2, 10 - @show alternating_update(Algorithm("bp_onesite"), A, ψ) + @time e_bp, ψ_bp = dmrg(copy(A), copy(ψ); nsweeps, nsites, updater_kwargs, inserter_kwargs) + @time e_ttn, ψ_ttn = dmrg(ttn(A), ttn(ψ); nsweeps, nsites, inserter_kwargs, updater_kwargs) + @show e_ttn, e_bp end end From cd2b139c23b417917582a13e3dd79bd78770cc9c Mon Sep 17 00:00:00 2001 From: Joey Date: Tue, 14 May 2024 19:00:11 -0400 Subject: [PATCH 03/27] New Changes --- src/abstractitensornetwork.jl | 23 +++++++++++-- src/formnetworks/bilinearformnetwork.jl | 4 +-- .../alternating_update/alternating_update.jl | 5 +-- test/test_belief_propagation_dmrg.jl | 33 ------------------- 4 files changed, 25 insertions(+), 40 deletions(-) delete mode 100644 test/test_belief_propagation_dmrg.jl diff --git a/src/abstractitensornetwork.jl b/src/abstractitensornetwork.jl index 80b127f6..e022ce09 100644 --- a/src/abstractitensornetwork.jl +++ b/src/abstractitensornetwork.jl @@ -797,6 +797,23 @@ end is_multi_edge(tn::AbstractITensorNetwork, e) = length(linkinds(tn, e)) > 1 is_multi_edge(tn::AbstractITensorNetwork) = Base.Fix1(is_multi_edge, tn) +function edges_equal(e1s, e2s) + if length(e1s) != length(e2s) + return false + end + for e in e1s + if e ∉ e2s && reverse(e) ∉ e2s + return false + end + end + return true +end + + +function edges_equal(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork) + return edges_equal(edges(tn1), edges(tn2)) +end + """Add two itensornetworks together by growing the bond dimension. The network structures need to be have the same vertex names, same site index on each vertex """ function ITensorMPS.add(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork) @assert issetequal(vertices(tn1), vertices(tn2)) @@ -806,14 +823,14 @@ function ITensorMPS.add(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork edges_tn1, edges_tn2 = edges(tn1), edges(tn2) - if !issetequal(edges_tn1, edges_tn2) + if !edges_equal(tn1, tn2) new_edges = union(edges_tn1, edges_tn2) tn1 = insert_linkinds(tn1, new_edges) tn2 = insert_linkinds(tn2, new_edges) end edges_tn1, edges_tn2 = edges(tn1), edges(tn2) - @assert issetequal(edges_tn1, edges_tn2) + @assert edges_equal(tn1, tn2) tn12 = copy(tn1) new_edge_indices = Dict( @@ -835,7 +852,7 @@ function ITensorMPS.add(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork e1_v = filter(x -> src(x) == v || dst(x) == v, edges_tn1) e2_v = filter(x -> src(x) == v || dst(x) == v, edges_tn2) - @assert issetequal(e1_v, e2_v) + @assert edges_equal(e1_v, e2_v) tn1v_linkinds = Index[only(linkinds(tn1, e)) for e in e1_v] tn2v_linkinds = Index[only(linkinds(tn2, e)) for e in e1_v] tn12v_linkinds = Index[new_edge_indices[e] for e in e1_v] diff --git a/src/formnetworks/bilinearformnetwork.jl b/src/formnetworks/bilinearformnetwork.jl index 306cb4a1..b4560938 100644 --- a/src/formnetworks/bilinearformnetwork.jl +++ b/src/formnetworks/bilinearformnetwork.jl @@ -65,7 +65,7 @@ function BilinearFormNetwork( @assert issetequal(flatten_siteinds(bra), flatten_siteinds(ket)) operator_inds = union_all_inds(siteinds(ket), dual_site_index_map(siteinds(ket))) # TODO: Define and use `identity_network` here. - O = ITensorNetwork(Op("I"), operator_inds) + O = ITensorNetwork(Op("I"), operator_inds; link_space = nothing) return BilinearFormNetwork(O, bra, ket; dual_site_index_map, kwargs...) end @@ -85,4 +85,4 @@ function update( tensornetwork(blf), ket_state, ket_vertex(blf, original_ket_state_vertex) ) return blf -end +end \ No newline at end of file diff --git a/src/solvers/alternating_update/alternating_update.jl b/src/solvers/alternating_update/alternating_update.jl index 156b983a..f176ca1f 100644 --- a/src/solvers/alternating_update/alternating_update.jl +++ b/src/solvers/alternating_update/alternating_update.jl @@ -103,12 +103,13 @@ function alternating_update(operator::AbstractTTN, init_state::AbstractTTN; kwar end function alternating_update(operator::AbstractITensorNetwork, init_state::AbstractITensorNetwork, sweep_plans; kwargs...) + cache_update_kwargs = is_tree(init_state) ? (;) : (; maxiter = 10, tol = 1e-5) ψOψ = QuadraticFormNetwork(operator, init_state) ψIψ = QuadraticFormNetwork(init_state) ψOψ_bpc = BeliefPropagationCache(ψOψ) ψIψ_bpc = BeliefPropagationCache(ψIψ) - ψOψ_bpc = update(ψOψ_bpc) - ψIψ_bpc = update(ψIψ_bpc) + ψOψ_bpc = update(ψOψ_bpc; cache_update_kwargs...) + ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) projected_operator = (ψOψ_bpc, ψIψ_bpc) return alternating_update(projected_operator, init_state, sweep_plans; kwargs...) end diff --git a/test/test_belief_propagation_dmrg.jl b/test/test_belief_propagation_dmrg.jl deleted file mode 100644 index 0350d950..00000000 --- a/test/test_belief_propagation_dmrg.jl +++ /dev/null @@ -1,33 +0,0 @@ -@eval module $(gensym()) - -using NamedGraphs: nv -using NamedGraphs.NamedGraphGenerators: named_grid, named_comb_tree, named_binary_tree -using ITensors: ITensors, Algorithm -using ITensors: dmrg, siteinds -using ITensorNetworks: alternating_update, bp_inserter, bp_extracter, bp_eigsolve_updater, random_tensornetwork, ttn, inner, maxlinkdim -using ITensorNetworks.ModelHamiltonians: heisenberg -using ITensorNetworks: ITensorNetwork - -using Random: Random - -using Test: @test, @testset - -@testset "belief_propagation dmrg" begin - ITensors.disable_warn_order() - - g = named_binary_tree(4) - s = siteinds("S=1/2", g) - χ, χmax = 1, 10 - Random.seed!(1234) - ψ = random_tensornetwork(s; link_space=χ) - A = ITensorNetwork(ttn(heisenberg(g), s)) - inserter_kwargs = (; maxdim = χmax) - updater_kwargs = (; tol = 1e-14, krylovdim = 1, maxiter = 1, verbosity = 0, eager = false) - nsites, nsweeps = 2, 10 - - @time e_bp, ψ_bp = dmrg(copy(A), copy(ψ); nsweeps, nsites, updater_kwargs, inserter_kwargs) - @time e_ttn, ψ_ttn = dmrg(ttn(A), ttn(ψ); nsweeps, nsites, inserter_kwargs, updater_kwargs) - - @show e_ttn, e_bp -end -end From 201882a841153bcefb7e5cd0f23aeef47a4c3fd2 Mon Sep 17 00:00:00 2001 From: Joey Date: Thu, 16 May 2024 18:16:46 -0400 Subject: [PATCH 04/27] Small changes --- Project.toml | 1 + examples/belief_propagation_dmrg.jl | 50 ++++++++++++++ examples/exampleutils.jl | 66 +++++++++++++++++++ src/expect.jl | 26 +++++++- .../alternating_update/alternating_update.jl | 5 +- 5 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 examples/belief_propagation_dmrg.jl create mode 100644 examples/exampleutils.jl diff --git a/Project.toml b/Project.toml index 57d2753c..bb2537d3 100644 --- a/Project.toml +++ b/Project.toml @@ -24,6 +24,7 @@ NamedGraphs = "678767b0-92e7-4007-89e4-4527a8725b19" PackageExtensionCompat = "65ce6f38-6b18-4e1d-a461-8949797d7930" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" SerializedElementArrays = "d3ce8812-9567-47e9-a7b5-65a6d70a3065" SimpleTraits = "699a6c99-e7fa-54fc-8d76-47d257e15c1d" SparseArrayKit = "a9a3c162-d163-4c15-8926-b8794fbefed2" diff --git a/examples/belief_propagation_dmrg.jl b/examples/belief_propagation_dmrg.jl new file mode 100644 index 00000000..77c44195 --- /dev/null +++ b/examples/belief_propagation_dmrg.jl @@ -0,0 +1,50 @@ +using NamedGraphs.GraphsExtensions: add_edge +using NamedGraphs: nv +using NamedGraphs.NamedGraphGenerators: named_grid, named_comb_tree, named_binary_tree +using ITensors: ITensors, Algorithm, expect +using ITensors: dmrg, siteinds +using ITensorNetworks: alternating_update, bp_inserter, bp_extracter, bp_eigsolve_updater, random_tensornetwork, ttn, inner, maxlinkdim +using ITensorNetworks.ModelHamiltonians: heisenberg, ising +using ITensorNetworks: ITensorNetwork + +using ITensors: Scaled, Prod, site, which_op + +using Random: Random + +include("exampleutils.jl") + +ITensors.disable_warn_order() + +L = 24 +h = 2.5 +g = named_grid((L,1)) +g = add_edge(g, (L,1) => (1,1)) +s = siteinds("S=1/2", g) +χ, χmax = 2, 5 +Random.seed!(1234) +#ψ_init = ITensorNetwork(v -> "↑", s) +ψ_init = random_tensornetwork(s; link_space = 2) +A = model_tno(s, ising; h) +H_opsum = ising(s; h) + +e_init = sum(expect(ψ_init, H_opsum; alg = "bp")) +@show e_init +@show expect(ψ_bp, "Sx") +#A = ITensorNetwork(ttn(heisenberg(g), s)) +cache_update_kwargs = (;maxiter = 25, tol = 1e-5) +inserter_bp_kwargs = (; maxdim = χmax, cache_update_kwargs) +inserter_ttn_kwargs = (; maxdim = χmax) +updater_kwargs = (; tol = 1e-14, krylovdim = 5, maxiter = 5, verbosity = 0, eager = false) +nsites, nsweeps = 2, 5 + +@time e_bp, ψ_bp = dmrg(A, ψ_init; nsweeps, nsites, updater_kwargs, inserter_kwargs = inserter_bp_kwargs) +#@time e_ttn, ψ_ttn = dmrg(ttn(A), ttn(ψ); nsweeps, nsites, updater_kwargs, inserter_kwargs = inserter_ttn_kwargs) + +e_final = sum(expect(ψ_bp, H_opsum; alg = "bp")) + +@show e_final, e_bp + +@show expect(ψ_bp, "Sx") + +#@show e_bp +#@show inner(ψ_bp, A, ψ_bp; alg = "exact") / inner(ψ_bp, ψ_bp; alg = "exact") \ No newline at end of file diff --git a/examples/exampleutils.jl b/examples/exampleutils.jl new file mode 100644 index 00000000..8e955938 --- /dev/null +++ b/examples/exampleutils.jl @@ -0,0 +1,66 @@ +using ITensors: siteinds, Op, prime +using Graphs: edges, vertices, is_tree, connected_components +using NamedGraphs: NamedGraph, NamedEdge, NamedGraphs, rename_vertices +using NamedGraphs.NamedGraphGenerators: named_grid +using NamedGraphs.GraphsExtensions: forest_cover, add_edges, rem_edges, add_vertices, rem_vertices, disjoint_union, subgraph +using ITensorNetworks: AbstractFormNetwork, IndsNetwork, ITensorNetwork, insert_linkinds, ttn, union_all_inds +using DataGraphs: underlying_graph +using ITensorNetworks.ModelHamiltonians: heisenberg + +function NamedGraphs.GraphsExtensions.forest_cover(s::IndsNetwork; kwargs...) + g = underlying_graph(s) + ss = IndsNetwork[] + no_edges= 0 + for f in forest_cover(g) + for g_tree_vertices in connected_components(f) + g_tree = f[g_tree_vertices] + if(length(edges(g_tree))) != 0 + s_f = subgraph(v -> v ∈ vertices(g_tree), s) + edges_to_remove = filter(e -> e ∉ edges(g_tree) && reverse(e) ∉ edges(g_tree), edges(s_f)) + s_f = rem_edges(s_f, edges_to_remove) + push!(ss, s_f) + @assert is_tree(s_f) + no_edges += length(edges(s_f)) + end + end + end + + @assert no_edges == length(edges(s)) + + return ss +end + +function model_tno(s::IndsNetwork, model::Function; params...) + forests = forest_cover(s) + tnos = ITensorNetwork[] + for s_tree in forests + g = underlying_graph(s_tree) + tno = ITensorNetwork(ttn(model(g; params...), s_tree)) + + missing_vertices = setdiff(vertices(s), vertices(g)) + s_remaining_verts = subgraph(v -> v ∈ missing_vertices, s) + + @assert issubset(edges(s_tree), edges(s)) + @assert issubset(edges(s_remaining_verts), edges(s)) + identity_tno = ITensorNetwork(Op("I"), union_all_inds(s_remaining_verts, prime(s_remaining_verts))) + tno = disjoint_union(tno, identity_tno) + tno = rename_vertices(v -> first(v), tno) + missing_edges = filter(e -> e ∉ edges(tno) && reverse(e) ∉ edges(tno), edges(s)) + missing_edges = NamedEdge[e ∈ edges(s) ? e : reverse(e) for e in missing_edges] + tno = insert_linkinds(tno, missing_edges; link_space = 1) + push!(tnos, tno) + end + + return reduce(+, tnos) +end + +function n_site_expect(ψIψ::AbstractFormNetwork, ops::Vector{String}, vs; kwargs...) + ψIψ_vs = [ψIψ[operator_vertex(ψIψ, v)] for v in vs] + s_vs = [commonind(ψIψ[ket_vertex(ψIψ, v)], ψIψ_vs[i]) for (i, v) in enumerate(vs)] + operators = [ITensors.op(ops[i].which_op, s_vs[i]) for i in 1:length(ops)] + ∂ψIψ_∂vs = environment(ψIψ, operator_vertices(ψIψ, [vs]); kwargs...) + numerator = contract([∂ψIψ_∂vs; operators]; contract_kwargs...)[] + denominator = contract([∂ψIψ_∂vs; ψIψ_vs]; contract_kwargs...)[] + + return numerator / denominator +end \ No newline at end of file diff --git a/src/expect.jl b/src/expect.jl index e1d46a9f..cd60ca28 100644 --- a/src/expect.jl +++ b/src/expect.jl @@ -4,6 +4,12 @@ using ITensorMPS: ITensorMPS, expect default_expect_alg() = "bp" +function ITensorMPS.expect( + ψ::AbstractITensorNetwork, ops; alg=default_expect_alg(), kwargs... +) + return expect(Algorithm(alg), ψ, ops; kwargs...) +end + function ITensorMPS.expect( ψIψ::AbstractFormNetwork, op::Op; contract_kwargs=(; sequence="automatic"), kwargs... ) @@ -18,6 +24,24 @@ function ITensorMPS.expect( return numerator / denominator end +function ITensorMPS.expect( + ψIψ::AbstractFormNetwork, ops::Scaled{ComplexF64, Prod{Op}}; contract_kwargs=(; sequence="automatic"), kwargs... +) + scalar = first(ops.args) + iszero(scalar) && return 0.0 + n_ops = length(ops) + vs = site.(ops[1:n_ops]) + op_strings = which_op.(ops[1:n_ops]) + ψIψ_vs = [ψIψ[operator_vertex(ψIψ, v)] for v in vs] + sinds = [commonind(ψIψ[ket_vertex(ψIψ, v)], ψIψ_vs[i]) for (i,v) in enumerate(vs)] + operators = [ITensors.op(op_strings[i], sinds[i]) for i in 1:n_ops] + ∂ψIψ_∂v = environment(ψIψ, operator_vertices(ψIψ, vs); kwargs...) + numerator = contract(vcat(∂ψIψ_∂v, operators); contract_kwargs...)[] + denominator = contract(vcat(∂ψIψ_∂v, ψIψ_vs); contract_kwargs...)[] + + return scalar * numerator / denominator +end + function ITensorMPS.expect( alg::Algorithm, ψ::AbstractITensorNetwork, @@ -62,4 +86,4 @@ function ITensorMPS.expect( ψ::AbstractITensorNetwork, op::String; alg=default_expect_alg(), kwargs... ) return expect(ψ, op, vertices(ψ); alg, kwargs...) -end +end \ No newline at end of file diff --git a/src/solvers/alternating_update/alternating_update.jl b/src/solvers/alternating_update/alternating_update.jl index b1a4e42d..494b87e5 100644 --- a/src/solvers/alternating_update/alternating_update.jl +++ b/src/solvers/alternating_update/alternating_update.jl @@ -102,7 +102,10 @@ function alternating_update(operator::AbstractTTN, init_state::AbstractTTN; kwar return alternating_update(projected_operator, init_state; kwargs...) end -function alternating_update(operator::AbstractITensorNetwork, init_state::AbstractITensorNetwork, sweep_plans; kwargs...) +#TODO: Brainwave. Generalise your BP alternating update to operator::Sum{AbstractITensorNetwork}. Shouldn't this +# account for the environment correctly and put the BP error precisely on the state only, which is better +# conditioned?! +function alternating_update(operators::AbstractITensorNetwork, init_state::AbstractITensorNetwork, sweep_plans; kwargs...) cache_update_kwargs = is_tree(init_state) ? (;) : (; maxiter = 10, tol = 1e-5) ψOψ = QuadraticFormNetwork(operator, init_state) ψIψ = QuadraticFormNetwork(init_state) From 7228fb5362c1781f5af7e9bfb233e80cbc783fa7 Mon Sep 17 00:00:00 2001 From: Joey Date: Fri, 31 May 2024 10:05:53 -0400 Subject: [PATCH 05/27] Changes --- examples/belief_propagation_dmrg.jl | 121 ++++++++++++------ src/caches/beliefpropagationcache.jl | 23 +++- src/lib/ITensorsExtensions/src/itensor.jl | 1 + .../src/ModelHamiltonians.jl | 5 +- .../alternating_update/alternating_update.jl | 16 ++- .../alternating_update/region_update.jl | 14 +- src/solvers/dmrg.jl | 6 +- src/solvers/extract/extract.jl | 8 +- src/solvers/insert/insert.jl | 32 ++--- src/solvers/local_solvers/eigsolve.jl | 11 +- src/solvers/sweep_plans/sweep_plans.jl | 24 +++- 11 files changed, 179 insertions(+), 82 deletions(-) diff --git a/examples/belief_propagation_dmrg.jl b/examples/belief_propagation_dmrg.jl index 77c44195..9ad607db 100644 --- a/examples/belief_propagation_dmrg.jl +++ b/examples/belief_propagation_dmrg.jl @@ -1,13 +1,15 @@ -using NamedGraphs.GraphsExtensions: add_edge -using NamedGraphs: nv +using NamedGraphs.GraphsExtensions: add_edge, rem_edge +using NamedGraphs: nv, src using NamedGraphs.NamedGraphGenerators: named_grid, named_comb_tree, named_binary_tree -using ITensors: ITensors, Algorithm, expect +using ITensors: ITensors, Algorithm, expect, mapprime using ITensors: dmrg, siteinds -using ITensorNetworks: alternating_update, bp_inserter, bp_extracter, bp_eigsolve_updater, random_tensornetwork, ttn, inner, maxlinkdim +using ITensorNetworks: alternating_update, bp_inserter, bp_extracter, bp_eigsolve_updater, random_tensornetwork, ttn, inner, maxlinkdim, map_inds, combine_linkinds using ITensorNetworks.ModelHamiltonians: heisenberg, ising using ITensorNetworks: ITensorNetwork - -using ITensors: Scaled, Prod, site, which_op +using Dictionaries +using ITensors: Scaled, Prod, site, which_op, inds, combiner, op, sim +using ITensors.NDTensors: array +using LinearAlgebra using Random: Random @@ -15,36 +17,77 @@ include("exampleutils.jl") ITensors.disable_warn_order() -L = 24 -h = 2.5 -g = named_grid((L,1)) -g = add_edge(g, (L,1) => (1,1)) -s = siteinds("S=1/2", g) -χ, χmax = 2, 5 -Random.seed!(1234) -#ψ_init = ITensorNetwork(v -> "↑", s) -ψ_init = random_tensornetwork(s; link_space = 2) -A = model_tno(s, ising; h) -H_opsum = ising(s; h) - -e_init = sum(expect(ψ_init, H_opsum; alg = "bp")) -@show e_init -@show expect(ψ_bp, "Sx") -#A = ITensorNetwork(ttn(heisenberg(g), s)) -cache_update_kwargs = (;maxiter = 25, tol = 1e-5) -inserter_bp_kwargs = (; maxdim = χmax, cache_update_kwargs) -inserter_ttn_kwargs = (; maxdim = χmax) -updater_kwargs = (; tol = 1e-14, krylovdim = 5, maxiter = 5, verbosity = 0, eager = false) -nsites, nsweeps = 2, 5 - -@time e_bp, ψ_bp = dmrg(A, ψ_init; nsweeps, nsites, updater_kwargs, inserter_kwargs = inserter_bp_kwargs) -#@time e_ttn, ψ_ttn = dmrg(ttn(A), ttn(ψ); nsweeps, nsites, updater_kwargs, inserter_kwargs = inserter_ttn_kwargs) - -e_final = sum(expect(ψ_bp, H_opsum; alg = "bp")) - -@show e_final, e_bp - -@show expect(ψ_bp, "Sx") - -#@show e_bp -#@show inner(ψ_bp, A, ψ_bp; alg = "exact") / inner(ψ_bp, ψ_bp; alg = "exact") \ No newline at end of file +function ising_operator_ring(s::IndsNetwork; h = 0, hl = 0) + L = length(vertices(s)) + s_tree = rem_edge(s, (1,1) => (L,1)) + g_tree = rem_edge(s, (1,1) => (L,1)) + A = ITensorNetwork(ttn(ising(g_tree; h, hl), s_tree)) + A = insert_linkinds(A, [NamedEdge((1,1) => (L,1))]) + Ap2 = ITensorNetwork(v -> v == (L,1) || v == (1,1) ? Op("Sz") : Op("I"), union_all_inds(s,s')) + return A + Ap2 +end + +function ising_operator_sq_ring(s::IndsNetwork; h = 0, hl = 0) + L = length(vertices(s)) + s_tree = rem_edge(s, (1,1) => (L,1)) + g_tree = rem_edge(s, (1,1) => (L,1)) + A = ITensorNetwork(ttn(ising(g_tree; h, hl), s_tree)) + A = insert_linkinds(A, [NamedEdge((1,1) => (L,1))]) + Ap2 = ITensorNetwork(v -> v == (L,1) || v == (1,1) ? Op("Sz") : Op("I"), union_all_inds(s,s')) + A = A + Ap2 + + Ap = map_inds(prime, A; links = []) + Ap = map_inds(sim, Ap; sites = []) + + Asq = copy(A) + for v in vertices(Asq) + Asq[v] = Ap[v] * A[v] + Asq[v] = mapprime(Asq[v], 2, 1) + end + + return combine_linkinds(Asq) +end + +function main() + L = 4 + h, hl = 0.5, 0.1 + g = named_grid((L,1); periodic = false) + s = siteinds("S=1/2", g) + A = ITensorNetwork(ttn(ising(g; h, hl), s)) + #A = ising_operator_ring(s; h, hl) + #Asq = ising_operator_sq_ring(s; h, hl) + + χ, χmax = 2, 4 + Random.seed!(1234) + ψ_init = ITensorNetwork(v -> "↓", s) + A_vec = ITensorNetwork[A1, A2] + H_opsum = ising(s; h) + + e_init = sum(expect(ψ_init, H_opsum; alg = "bp")) + @show e_init + #A = ITensorNetwork(ttn(heisenberg(g), s)) + cache_update_kwargs = (;maxiter = 30, tol = 1e-8) + inserter_bp_kwargs = (; maxdim = χmax, cutoff = 1e-14, cache_update_kwargs) + inserter_ttn_kwargs = (; maxdim = χmax) + updater_kwargs = (; tol = 1e-14, krylovdim = 5, maxiter = 2, verbosity = 0, eager = false) + nsites, nsweeps = 2, 3 + + A = ITensorNetwork[A] + #@time e_bp_vectorized, ψ_bp_vectorized = dmrg(A_vec, ψ_init; nsweeps, nsites, updater_kwargs, inserter_kwargs = inserter_bp_kwargs) + @time e_bp_nonvectorized, ψ_bp_nonvectorized = dmrg(A, ψ_init; nsweeps, nsites, updater_kwargs, inserter_kwargs = inserter_bp_kwargs) + #@time e_ttn, ψ_ttn = dmrg(ttn(A), ttn(ψ_init); nsweeps, nsites, updater_kwargs, inserter_kwargs = inserter_ttn_kwargs) + + #e_final_vectorized = sum(expect(ψ_bp_vectorized, H_opsum; alg = "bp")) + e_final_nonvectorized = sum(expect(ψ_bp_nonvectorized, H_opsum; alg = "bp")) + + #@show e_final_vectorized + @show e_final_nonvectorized + #@show e_ttn + + #@show expect(ψ_bp_nonvectorized, "Sx") + @show expect(ψ_bp_nonvectorized, "Sx") + #@show e_bp + #@show sum([inner(ψ_bp, A, ψ_bp; alg = "exact")] for A in A_vec) / inner(ψ_bp, ψ_bp; alg = "exact") +end + +main() \ No newline at end of file diff --git a/src/caches/beliefpropagationcache.jl b/src/caches/beliefpropagationcache.jl index b980a52f..fd577ce4 100644 --- a/src/caches/beliefpropagationcache.jl +++ b/src/caches/beliefpropagationcache.jl @@ -13,7 +13,8 @@ using NamedGraphs.PartitionedGraphs: unpartitioned_graph using SimpleTraits: SimpleTraits, Not, @traitfn -default_message(inds_e) = ITensor[denseblocks(delta(i)) for i in inds_e] +#default_message(inds_e) = ITensor[denseblocks(delta(i)) for i in inds_e] +default_message(inds_e) = ITensor[denseblocks(delta(inds_e))] default_messages(ptn::PartitionedGraph) = Dictionary() default_message_norm(m::ITensor) = norm(m) function default_message_update(contract_list::Vector{ITensor}; kwargs...) @@ -83,6 +84,24 @@ function tensornetwork(bp_cache::BeliefPropagationCache) return unpartitioned_graph(partitioned_tensornetwork(bp_cache)) end +function reset_messages(bp_cache::BeliefPropagationCache, pes::Vector{<:PartitionEdge}) + new_messages = copy(messages(bp_cache)) + for pe in pes + delete!(new_messages, pe) + end + return BeliefPropagationCache(partitioned_tensornetwork(bp_cache), new_messages, default_message(bp_cache)) +end + +function reset_messages(bp_cache::BeliefPropagationCache) + pedges = vcat(partitionedges(partitioned_tensornetwork(bp_cache)), reverse.(partitionedges(partitioned_tensornetwork(bp_cache)))) + return reset_messages(bp_cache, pedges) +end + +function reset_message(bp_cache::BeliefPropagationCache, pe::PartitionEdge) + return reset_messages(bp_cache, PartitionEdge[pe]) +end + + #Forward from partitioned graph for f in [ :(PartitionedGraphs.partitioned_graph), @@ -173,6 +192,7 @@ function update_message( ) vertex = src(edge) messages = environment(bp_cache, vertex; ignore_edges=PartitionEdge[reverse(edge)]) + state = factor(bp_cache, vertex) return message_update(ITensor[messages; state]; message_update_kwargs...) @@ -258,6 +278,7 @@ Update the tensornetwork inside the cache """ function update_factors(bp_cache::BeliefPropagationCache, factors) bp_cache = copy(bp_cache) + factors = copy(factors) tn = tensornetwork(bp_cache) for vertex in eachindex(factors) # TODO: Add a check that this preserves the graph structure. diff --git a/src/lib/ITensorsExtensions/src/itensor.jl b/src/lib/ITensorsExtensions/src/itensor.jl index 8c834830..4e01e0d8 100644 --- a/src/lib/ITensorsExtensions/src/itensor.jl +++ b/src/lib/ITensorsExtensions/src/itensor.jl @@ -20,6 +20,7 @@ using ITensors.NDTensors: NDTensors, Block, Tensor, + array, blockdim, blockoffsets, denseblocks, diff --git a/src/lib/ModelHamiltonians/src/ModelHamiltonians.jl b/src/lib/ModelHamiltonians/src/ModelHamiltonians.jl index f54faea3..0f6f3383 100644 --- a/src/lib/ModelHamiltonians/src/ModelHamiltonians.jl +++ b/src/lib/ModelHamiltonians/src/ModelHamiltonians.jl @@ -108,8 +108,8 @@ heisenberg(N::Integer; kwargs...) = heisenberg(path_graph(N); kwargs...) """ Next-to-nearest-neighbor Ising model (ZZX) on a general graph """ -function ising(g::AbstractGraph; J1=-1, J2=0, h=0) - (; J1, J2, h) = map(to_callable, (; J1, J2, h)) +function ising(g::AbstractGraph; J1=-1, J2=0, h=0, hl = 0) + (; J1, J2, h, hl) = map(to_callable, (; J1, J2, h, hl)) ℋ = OpSum() for e in edges(g) ℋ += J1(e), "Sz", src(e), "Sz", dst(e) @@ -129,6 +129,7 @@ function ising(g::AbstractGraph; J1=-1, J2=0, h=0) end for v in vertices(g) ℋ += h(v), "Sx", v + ℋ += hl(v), "Sz", v end return ℋ end diff --git a/src/solvers/alternating_update/alternating_update.jl b/src/solvers/alternating_update/alternating_update.jl index 494b87e5..ef4f9359 100644 --- a/src/solvers/alternating_update/alternating_update.jl +++ b/src/solvers/alternating_update/alternating_update.jl @@ -21,6 +21,7 @@ function alternating_update( inserter=default_inserter(), transform_operator_kwargs=(;), transform_operator=default_transform_operator(), + sweep_plan_func = default_sweep_plan, kwargs..., ) inserter_kwargs = (; inserter_kwargs..., kwargs...) @@ -28,6 +29,7 @@ function alternating_update( nsweeps, init_state; root_vertex, + sweep_plan_func, extracter, extracter_kwargs, updater, @@ -102,19 +104,19 @@ function alternating_update(operator::AbstractTTN, init_state::AbstractTTN; kwar return alternating_update(projected_operator, init_state; kwargs...) end -#TODO: Brainwave. Generalise your BP alternating update to operator::Sum{AbstractITensorNetwork}. Shouldn't this +#TODO: Generalise your BP alternating update to operator::Sum{AbstractITensorNetwork}. Shouldn't this # account for the environment correctly and put the BP error precisely on the state only, which is better # conditioned?! -function alternating_update(operators::AbstractITensorNetwork, init_state::AbstractITensorNetwork, sweep_plans; kwargs...) +function alternating_update(operators::Vector{ITensorNetwork}, init_state::AbstractITensorNetwork, sweep_plans; kwargs...) cache_update_kwargs = is_tree(init_state) ? (;) : (; maxiter = 10, tol = 1e-5) - ψOψ = QuadraticFormNetwork(operator, init_state) + ψOψs = QuadraticFormNetwork[QuadraticFormNetwork(operator, init_state) for operator in operators] ψIψ = QuadraticFormNetwork(init_state) - ψOψ_bpc = BeliefPropagationCache(ψOψ) + ψOψ_bpcs = BeliefPropagationCache[BeliefPropagationCache(ψOψ) for ψOψ in ψOψs] ψIψ_bpc = BeliefPropagationCache(ψIψ) - ψOψ_bpc = update(ψOψ_bpc; cache_update_kwargs...) + ψOψ_bpcs = BeliefPropagationCache[update(ψOψ_bpc; cache_update_kwargs...) for ψOψ_bpc in ψOψ_bpcs] ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) - projected_operator = (ψOψ_bpc, ψIψ_bpc) - return alternating_update(projected_operator, init_state, sweep_plans; kwargs...) + projected_operators = (ψOψ_bpcs, ψIψ_bpc) + return alternating_update(projected_operators, init_state, sweep_plans; kwargs...) end function alternating_update( diff --git a/src/solvers/alternating_update/region_update.jl b/src/solvers/alternating_update/region_update.jl index 14364ec9..a53b6f7f 100644 --- a/src/solvers/alternating_update/region_update.jl +++ b/src/solvers/alternating_update/region_update.jl @@ -119,7 +119,7 @@ function region_update( return state, projected_operator end -function region_update(projected_operator, state; outputlevel, +function region_update(projected_operators, state; outputlevel, which_sweep, sweep_plan, which_region_update, @@ -138,13 +138,15 @@ function region_update(projected_operator, state; outputlevel, transform_operator_kwargs, internal_kwargs, ) = region_kwargs - ψOψ_bpc, ψIψ_bpc = projected_operator + ψOψ_bpcs, ψIψ_bpc = first(projected_operators), last(projected_operators) + #ψOψ_bpc = only(ψOψ_bpcs) - local_state, ∂ψOψ_bpc_∂r, sqrt_mts, inv_sqrt_mts = extracter(state, ψOψ_bpc, ψIψ_bpc, region; extracter_kwargs...) + #Fix extracter, update and inserter to work with sum of ψOψ_bpcs + local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts = extracter(state, ψOψ_bpcs, ψIψ_bpc, region; extracter_kwargs...) - local_state, _ = updater(local_state, ∂ψOψ_bpc_∂r, sqrt_mts, inv_sqrt_mts; updater_kwargs...) + local_state, _ = updater(local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts; updater_kwargs...) - state, ψOψ_bpc, ψIψ_bpc, spec, info = inserter(state, ψOψ_bpc, ψIψ_bpc, local_state, region; inserter_kwargs...) + state, ψOψ_bpcs, ψIψ_bpc, spec, info = inserter(state, ψOψ_bpcs, ψIψ_bpc, local_state, region; inserter_kwargs...) all_kwargs = (; which_region_update, @@ -163,5 +165,5 @@ function region_update(projected_operator, state; outputlevel, update_observer!(region_observer!; all_kwargs...) !(isnothing(region_printer)) && region_printer(; all_kwargs...) - return state, (ψOψ_bpc, ψIψ_bpc) + return state, (ψOψ_bpcs, ψIψ_bpc) end diff --git a/src/solvers/dmrg.jl b/src/solvers/dmrg.jl index 5b0dcd73..7ccef86e 100644 --- a/src/solvers/dmrg.jl +++ b/src/solvers/dmrg.jl @@ -25,13 +25,15 @@ function ITensorMPS.dmrg( end function ITensorMPS.dmrg( - operator, + operators::Vector{ITensorNetwork}, init_state; nsweeps, nsites=2, updater=bp_eigsolve_updater, inserter = bp_inserter, extracter = bp_extracter, + sweep_plan_func = bp_sweep_plan, + bp_sweep_kwargs = (;), (region_observer!)=nothing, kwargs..., ) @@ -40,7 +42,7 @@ function ITensorMPS.dmrg( region_observer!, ValuesObserver((; eigvals=eigvals_ref)) ) state = alternating_update( - operator, init_state; nsweeps, nsites, updater, region_observer!, inserter, extracter, kwargs... + operators, init_state; nsweeps, nsites, updater, region_observer!, inserter, extracter, sweep_plan_func, kwargs... ) eigval = only(eigvals_ref[]) return eigval, state diff --git a/src/solvers/extract/extract.jl b/src/solvers/extract/extract.jl index 64a3fae5..2172c480 100644 --- a/src/solvers/extract/extract.jl +++ b/src/solvers/extract/extract.jl @@ -25,11 +25,11 @@ function default_extracter(state, projected_operator, region, ortho; internal_kw return state, projected_operator, local_tensor end -function bp_extracter(ψ::AbstractITensorNetwork, ψAψ_bpc::BeliefPropagationCache, ψIψ_bpc::BeliefPropagationCache, region; +function bp_extracter(ψ::AbstractITensorNetwork, ψAψ_bpcs::Vector{<:BeliefPropagationCache}, ψIψ_bpc::BeliefPropagationCache, region; regularization = 10*eps(scalartype(ψ))) - form_network = unpartitioned_graph(partitioned_tensornetwork(ψAψ_bpc)) + form_network = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) form_ket_vertices, form_bra_vertices = ket_vertices(form_network, region), bra_vertices(form_network, region) - ∂ψAψ_bpc_∂r = environment(ψAψ_bpc, [form_ket_vertices; form_bra_vertices]) + ∂ψAψ_bpc_∂rs = [environment(ψAψ_bpc, [form_ket_vertices; form_bra_vertices]) for ψAψ_bpc in ψAψ_bpcs] state = prod(ψ[v] for v in region) messages = environment(ψIψ_bpc, partitionvertices(ψIψ_bpc, form_ket_vertices)) f_sqrt = sqrt ∘ (x -> x + regularization) @@ -37,5 +37,5 @@ function bp_extracter(ψ::AbstractITensorNetwork, ψAψ_bpc::BeliefPropagationCa sqrt_mts = [ITensorsExtensions.map_eigvals(f_sqrt, mt, inds(mt)[1], inds(mt)[2]; ishermitian=true) for mt in messages] inv_sqrt_mts = [ITensorsExtensions.map_eigvals(f_inv_sqrt, mt, inds(mt)[1], inds(mt)[2]; ishermitian=true) for mt in messages] - return state, ∂ψAψ_bpc_∂r, sqrt_mts, inv_sqrt_mts + return state, ∂ψAψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts end \ No newline at end of file diff --git a/src/solvers/insert/insert.jl b/src/solvers/insert/insert.jl index f78ec8ec..e1173448 100644 --- a/src/solvers/insert/insert.jl +++ b/src/solvers/insert/insert.jl @@ -49,42 +49,44 @@ function default_inserter( return state, nothing end -function bp_inserter(ψ::AbstractITensorNetwork, ψAψ_bpc::BeliefPropagationCache, +function bp_inserter(ψ::AbstractITensorNetwork, ψAψ_bpcs::Vector{<:BeliefPropagationCache}, ψIψ_bpc::BeliefPropagationCache, state::ITensor, region; cache_update_kwargs = (;), kwargs...) spec = nothing - form_network = unpartitioned_graph(partitioned_tensornetwork(ψAψ_bpc)) + form_network = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) + ψAψ_bpcs = BeliefPropagationCache[reset_messages(ψAψ_bpc) for ψAψ_bpc in ψAψ_bpcs] + ψIψ_bpc = reset_messages(ψIψ_bpc) if length(region) == 1 states = [state] elseif length(region) == 2 v1, v2 = region[1], region[2] e = edgetype(ψ)(v1, v2) - pe = partitionedge(ψAψ_bpc, ket_vertex(form_network, v1) => bra_vertex(form_network, v2)) + pe = partitionedge(ψIψ_bpc, ket_vertex(form_network, v1) => bra_vertex(form_network, v2)) stateᵥ₁, stateᵥ₂, spec = factorize_svd(state,uniqueinds(ψ[v1], ψ[v2]); ortho="none", tags=edge_tag(e),kwargs...) states = noprime.([stateᵥ₁, stateᵥ₂]) - delete!(messages(ψAψ_bpc), pe) - delete!(messages(ψIψ_bpc), pe) - delete!(messages(ψAψ_bpc), reverse(pe)) - delete!(messages(ψIψ_bpc), reverse(pe)) + #TODO: Insert spec into the message tensor guess here?! end for (i, v) in enumerate(region) state = states[i] + state_dag = copy(state) form_bra_v, form_ket_v = bra_vertex(form_network, v), ket_vertex(form_network, v) ψ[v] =state - state_dag = replaceinds(dag(state), inds(state), dual_index_map(form_network).(inds(state))) - ψAψ_bpc = update_factor(ψAψ_bpc, form_ket_v, state) - ψAψ_bpc = update_factor(ψAψ_bpc, form_bra_v, state_dag) + state_dag = replaceinds(dag(state_dag), inds(state_dag), dual_index_map(form_network).(inds(state_dag))) + ψAψ_bpcs = BeliefPropagationCache[update_factor(ψAψ_bpc, form_ket_v, state) for ψAψ_bpc in ψAψ_bpcs] + ψAψ_bpcs = BeliefPropagationCache[update_factor(ψAψ_bpc, form_bra_v, state_dag) for ψAψ_bpc in ψAψ_bpcs] ψIψ_bpc = update_factor(ψIψ_bpc, form_ket_v, state) ψIψ_bpc = update_factor(ψIψ_bpc, form_bra_v, state_dag) end - ψAψ_bpc = update(ψAψ_bpc; cache_update_kwargs...) + + ψAψ_bpcs = BeliefPropagationCache[update(ψAψ_bpc; cache_update_kwargs...) for ψAψ_bpc in ψAψ_bpcs] + ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) - updated_ψAψ = unpartitioned_graph(partitioned_tensornetwork(ψAψ_bpc)) - updated_ψIψ = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) - eigval = scalar(updated_ψAψ; cache! = Ref(ψAψ_bpc), alg = "bp") / scalar(updated_ψIψ; cache! = Ref(ψIψ_bpc), alg = "bp") - return ψ, ψAψ_bpc, ψIψ_bpc, spec, (; eigvals=[eigval]) + updated_ψIψ = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) + numerator_terms = [scalar(unpartitioned_graph(partitioned_tensornetwork(ψAψ_bpc)); cache! = Ref(ψAψ_bpc), alg = "bp") for ψAψ_bpc in ψAψ_bpcs] + eigval = sum(numerator_terms) / scalar(updated_ψIψ; cache! = Ref(ψIψ_bpc), alg = "bp") + return ψ, ψAψ_bpcs, ψIψ_bpc, spec, (; eigvals=[eigval]) end \ No newline at end of file diff --git a/src/solvers/local_solvers/eigsolve.jl b/src/solvers/local_solvers/eigsolve.jl index 824fa038..aa5ccc6c 100644 --- a/src/solvers/local_solvers/eigsolve.jl +++ b/src/solvers/local_solvers/eigsolve.jl @@ -33,19 +33,20 @@ function eigsolve_updater( return vecs[1], (; info, eigvals=vals) end -function bp_eigsolve_updater(init::ITensor, ∂ψAψ_bpc_∂r, sqrt_mts, inv_sqrt_mts; kwargs...) +function bp_eigsolve_updater(init::ITensor, ∂ψAψ_bpc_∂rs::Vector, sqrt_mts, inv_sqrt_mts; kwargs...) #TODO: Put inv_sqrt_mts onto ∂ψAψ_bpc_∂r beforehand. Need to do this in an efficient way without #precontracting ∂ψAψ_bpc_∂r - function get_new_state(∂ψAψ_bpc_∂r, inv_sqrt_mts, state::ITensor; sequence = "automatic") + function get_new_state(∂ψAψ_bpc_∂rs::Vector, inv_sqrt_mts, state::ITensor; sequences = ["automatic" for i in length(∂ψAψ_bpc_∂rs)]) state = noprime(contract([state; inv_sqrt_mts])) - state = dag(noprime(contract([state; ∂ψAψ_bpc_∂r]; sequence))) + states = ITensor[dag(noprime(contract([copy(state); ∂ψAψ_bpc_∂r]; sequence = sequences[i]))) for (i, ∂ψAψ_bpc_∂r) in enumerate(∂ψAψ_bpc_∂rs)] + state = reduce(+, states) return noprime(contract([state; (inv_sqrt_mts)])) end init = noprime(contract([init; sqrt_mts])) - sequence = optimal_contraction_sequence([init; ∂ψAψ_bpc_∂r]) - get_new_state_partial = partial(get_new_state, ∂ψAψ_bpc_∂r, inv_sqrt_mts; sequence) + sequences = [optimal_contraction_sequence([init; ∂ψAψ_bpc_∂r]) for ∂ψAψ_bpc_∂r in ∂ψAψ_bpc_∂rs] + get_new_state_partial = partial(get_new_state, ∂ψAψ_bpc_∂rs, inv_sqrt_mts; sequences) howmany = 1 vals, vecs, info = eigsolve(get_new_state_partial,init,howmany,:SR; ishermitian = true, kwargs...) diff --git a/src/solvers/sweep_plans/sweep_plans.jl b/src/solvers/sweep_plans/sweep_plans.jl index 69221995..cbace9e1 100644 --- a/src/solvers/sweep_plans/sweep_plans.jl +++ b/src/solvers/sweep_plans/sweep_plans.jl @@ -1,4 +1,4 @@ -using Graphs: AbstractEdge, dst, src +using Graphs: AbstractEdge, dst, src, edges using NamedGraphs.GraphsExtensions: GraphsExtensions direction(step_number) = isodd(step_number) ? Base.Forward : Base.Reverse @@ -143,6 +143,28 @@ function default_sweep_plans( return sweep_plans end +function bp_sweep_plan(g::AbstractGraph; + root_vertex=GraphsExtensions.default_root_vertex(graph), + region_kwargs, + nsites::Int, + es = edges(g), + vs = vertices(g)) + region_kwargs = (; internal_kwargs = (;), region_kwargs...) + + L = length(vertices(g)) + es = vcat([NamedEdge((i, 1) => (i + 1, 1)) for i in 1:(L-1)], [NamedEdge((L,1) => (1,1))]) + + if nsites == 2 + return collect( + flatten(map(e -> [([src(e), dst(e)], region_kwargs)], es)) + ) + elseif nsites == 1 + return collect( + flatten(map(v -> [([v], region_kwargs)], vs)) + ) + end +end + function default_sweep_plan( graph::AbstractGraph; root_vertex=GraphsExtensions.default_root_vertex(graph), From 75d0c3ba4e07949ae6a5d3c02f21ddd94f522b4a Mon Sep 17 00:00:00 2001 From: Joey Date: Fri, 31 May 2024 10:06:07 -0400 Subject: [PATCH 06/27] Utils additions --- examples/exampleutils.jl | 51 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/examples/exampleutils.jl b/examples/exampleutils.jl index 8e955938..c0244f56 100644 --- a/examples/exampleutils.jl +++ b/examples/exampleutils.jl @@ -1,8 +1,8 @@ -using ITensors: siteinds, Op, prime -using Graphs: edges, vertices, is_tree, connected_components +using ITensors: siteinds, Op, prime, OpSum +using Graphs: AbstractGraph, edges, vertices, is_tree, connected_components using NamedGraphs: NamedGraph, NamedEdge, NamedGraphs, rename_vertices using NamedGraphs.NamedGraphGenerators: named_grid -using NamedGraphs.GraphsExtensions: forest_cover, add_edges, rem_edges, add_vertices, rem_vertices, disjoint_union, subgraph +using NamedGraphs.GraphsExtensions: forest_cover, add_edges, rem_edges, add_vertices, rem_vertices, disjoint_union, subgraph, src, dst using ITensorNetworks: AbstractFormNetwork, IndsNetwork, ITensorNetwork, insert_linkinds, ttn, union_all_inds using DataGraphs: underlying_graph using ITensorNetworks.ModelHamiltonians: heisenberg @@ -30,7 +30,7 @@ function NamedGraphs.GraphsExtensions.forest_cover(s::IndsNetwork; kwargs...) return ss end -function model_tno(s::IndsNetwork, model::Function; params...) +function model_ising_tno(s::IndsNetwork, model::Function; params...) forests = forest_cover(s) tnos = ITensorNetwork[] for s_tree in forests @@ -54,6 +54,49 @@ function model_tno(s::IndsNetwork, model::Function; params...) return reduce(+, tnos) end +function model_tno_simplified(s::IndsNetwork, model::Function; params...) + forests = forest_cover(s) + tnos = ITensorNetwork[] + for s_tree in forests + g = underlying_graph(s_tree) + @show params + tno = ITensorNetwork(ttn(model(g; params...), s_tree)) + + missing_vertices = setdiff(vertices(s), vertices(g)) + s_remaining_verts = subgraph(v -> v ∈ missing_vertices, s) + + @assert issubset(edges(s_tree), edges(s)) + @assert issubset(edges(s_remaining_verts), edges(s)) + identity_tno = ITensorNetwork(Op("I"), union_all_inds(s_remaining_verts, prime(s_remaining_verts))) + tno = disjoint_union(tno, identity_tno) + tno = rename_vertices(v -> first(v), tno) + push!(tnos, tno) + end + + return tnos +end + +function ising_dictified(g::AbstractGraph, Js, hs) + ℋ = OpSum() + for e in edges(g) + ℋ += Js[e], "Sz", src(e), "Sz", dst(e) + end + for v in vertices(g) + ℋ += hs[v], "Sx", v + end + return ℋ +end + +function xyz_dictified(g::AbstractGraph, Jxs, Jys, Jzs) + ℋ = OpSum() + for e in edges(g) + ℋ += Jxs[e], "X", src(e), "X", dst(e) + ℋ += Jys[e], "Y", src(e), "Y", dst(e) + ℋ += Jzs[e], "Z", src(e), "Z", dst(e) + end + return ℋ +end + function n_site_expect(ψIψ::AbstractFormNetwork, ops::Vector{String}, vs; kwargs...) ψIψ_vs = [ψIψ[operator_vertex(ψIψ, v)] for v in vs] s_vs = [commonind(ψIψ[ket_vertex(ψIψ, v)], ψIψ_vs[i]) for (i, v) in enumerate(vs)] From c90139b18dfc4986a8c1a2ac0eb50fc17f98b282 Mon Sep 17 00:00:00 2001 From: Joey Date: Sun, 2 Jun 2024 09:15:47 -0400 Subject: [PATCH 07/27] More stuff --- examples/belief_propagation_dmrg.jl | 82 +++++++--------- examples/exampleutils.jl | 96 ++++++++++++++++--- examples/imaginary_time_evo.jl | 34 +++++++ .../alternating_update/region_update.jl | 3 +- src/solvers/dmrg.jl | 2 +- src/solvers/insert/insert.jl | 6 +- src/solvers/local_solvers/eigsolve.jl | 1 - src/solvers/sweep_plans/sweep_plans.jl | 7 +- 8 files changed, 161 insertions(+), 70 deletions(-) create mode 100644 examples/imaginary_time_evo.jl diff --git a/examples/belief_propagation_dmrg.jl b/examples/belief_propagation_dmrg.jl index 9ad607db..b1a679e0 100644 --- a/examples/belief_propagation_dmrg.jl +++ b/examples/belief_propagation_dmrg.jl @@ -14,67 +14,59 @@ using LinearAlgebra using Random: Random include("exampleutils.jl") +include("imaginary_time_evo.jl") ITensors.disable_warn_order() -function ising_operator_ring(s::IndsNetwork; h = 0, hl = 0) - L = length(vertices(s)) - s_tree = rem_edge(s, (1,1) => (L,1)) - g_tree = rem_edge(s, (1,1) => (L,1)) - A = ITensorNetwork(ttn(ising(g_tree; h, hl), s_tree)) - A = insert_linkinds(A, [NamedEdge((1,1) => (L,1))]) - Ap2 = ITensorNetwork(v -> v == (L,1) || v == (1,1) ? Op("Sz") : Op("I"), union_all_inds(s,s')) - return A + Ap2 -end - -function ising_operator_sq_ring(s::IndsNetwork; h = 0, hl = 0) - L = length(vertices(s)) - s_tree = rem_edge(s, (1,1) => (L,1)) - g_tree = rem_edge(s, (1,1) => (L,1)) - A = ITensorNetwork(ttn(ising(g_tree; h, hl), s_tree)) - A = insert_linkinds(A, [NamedEdge((1,1) => (L,1))]) - Ap2 = ITensorNetwork(v -> v == (L,1) || v == (1,1) ? Op("Sz") : Op("I"), union_all_inds(s,s')) - A = A + Ap2 - - Ap = map_inds(prime, A; links = []) - Ap = map_inds(sim, Ap; sites = []) - - Asq = copy(A) - for v in vertices(Asq) - Asq[v] = Ap[v] * A[v] - Asq[v] = mapprime(Asq[v], 2, 1) - end - - return combine_linkinds(Asq) +function smallest_eigvalue(A::AbstractITensorNetwork) + out = reduce(*, [A[v] for v in vertices(A)]) + out = out * combiner(inds(out; plev = 0)) *combiner(inds(out; plev = 1)) + out = array(out) + return minimum(LinearAlgebra.eigvals(out)) end function main() L = 4 - h, hl = 0.5, 0.1 - g = named_grid((L,1); periodic = false) + h, hl, J = 0.5, 0.1, -1.0 + g = named_grid((L,1); periodic = true) + #g = heavy_hex_lattice_graph(2,2) + hs = Dictionary(vertices(g), [h for v in vertices(g)]) + hls = Dictionary(vertices(g), [hl for v in vertices(g)]) + Js = Dictionary(edges(g), [J for e in edges(g)]) + one_site_params = (; hs, hls) + two_site_params = (; Js) s = siteinds("S=1/2", g) - A = ITensorNetwork(ttn(ising(g; h, hl), s)) - #A = ising_operator_ring(s; h, hl) - #Asq = ising_operator_sq_ring(s; h, hl) + A = model_tno(s, ising_dictified; two_site_params, one_site_params) + A2 = first(model_tno_simplified(s, ising_dictified; two_site_params, one_site_params)) - χ, χmax = 2, 4 + χ, χmax, χTEBDmax = 1, 3, 3 + nperiods = 10 + dβs = [(25, 0.2/((2^(i-1)))) for i in 1:nperiods] + nbetas = 200 Random.seed!(1234) - ψ_init = ITensorNetwork(v -> "↓", s) - A_vec = ITensorNetwork[A1, A2] - H_opsum = ising(s; h) - + cache_update_kwargs = (;maxiter = 25, tol = 1e-10) + #ψ_init = ITensorNetwork(v -> "↑", s) + ψ_init = random_tensornetwork(s; link_space = χ) + H_opsum = ising(s; h, hl, J1 = J) e_init = sum(expect(ψ_init, H_opsum; alg = "bp")) - @show e_init - #A = ITensorNetwork(ttn(heisenberg(g), s)) - cache_update_kwargs = (;maxiter = 30, tol = 1e-8) + println("Initial Energy is $e_init") + #ψ_imag_time = imaginary_time_evo(s, ψ_init, ising_dictified, dβs, nbetas; model_params = (; two_site_params..., one_site_params...), bp_update_kwargs = cache_update_kwargs, + #apply_kwargs = (; cutoff = 1e-10, maxdim = χTEBDmax)) + #ψ_init = copy(ψ_imag_time) + inserter_bp_kwargs = (; maxdim = χmax, cutoff = 1e-14, cache_update_kwargs) inserter_ttn_kwargs = (; maxdim = χmax) - updater_kwargs = (; tol = 1e-14, krylovdim = 5, maxiter = 2, verbosity = 0, eager = false) - nsites, nsweeps = 2, 3 + updater_kwargs = (; tol = 1e-14, krylovdim = 3, maxiter = 2, verbosity = 0, eager = false) + nsites, nsweeps = 1, 2 A = ITensorNetwork[A] + A2 = ITensorNetwork[A2] + H_opsum_A2 = ising(underlying_graph(only(A2)); h, hl, J1 = J) + @show smallest_eigvalue(only(A2)) + @show sum(expect(ψ_init, H_opsum_A2; alg = "bp")) #@time e_bp_vectorized, ψ_bp_vectorized = dmrg(A_vec, ψ_init; nsweeps, nsites, updater_kwargs, inserter_kwargs = inserter_bp_kwargs) - @time e_bp_nonvectorized, ψ_bp_nonvectorized = dmrg(A, ψ_init; nsweeps, nsites, updater_kwargs, inserter_kwargs = inserter_bp_kwargs) + @time e_bp_nonvectorized, ψ_bp_nonvectorized = dmrg(A2, ψ_init; nsweeps, nsites, updater_kwargs, inserter_kwargs = inserter_bp_kwargs) + @show sum(expect(ψ_bp_nonvectorized, H_opsum_A2; alg = "bp")) #@time e_ttn, ψ_ttn = dmrg(ttn(A), ttn(ψ_init); nsweeps, nsites, updater_kwargs, inserter_kwargs = inserter_ttn_kwargs) #e_final_vectorized = sum(expect(ψ_bp_vectorized, H_opsum; alg = "bp")) diff --git a/examples/exampleutils.jl b/examples/exampleutils.jl index c0244f56..13e1418d 100644 --- a/examples/exampleutils.jl +++ b/examples/exampleutils.jl @@ -1,11 +1,15 @@ -using ITensors: siteinds, Op, prime, OpSum -using Graphs: AbstractGraph, edges, vertices, is_tree, connected_components +using ITensors: siteinds, Op, prime, OpSum, apply +using Graphs: AbstractGraph, SimpleGraph, edges, vertices, is_tree, connected_components using NamedGraphs: NamedGraph, NamedEdge, NamedGraphs, rename_vertices -using NamedGraphs.NamedGraphGenerators: named_grid -using NamedGraphs.GraphsExtensions: forest_cover, add_edges, rem_edges, add_vertices, rem_vertices, disjoint_union, subgraph, src, dst -using ITensorNetworks: AbstractFormNetwork, IndsNetwork, ITensorNetwork, insert_linkinds, ttn, union_all_inds +using NamedGraphs.NamedGraphGenerators: named_grid, named_hexagonal_lattice_graph +using NamedGraphs.GraphsExtensions: decorate_graph_edges, forest_cover, add_edges, rem_edges, add_vertices, rem_vertices, disjoint_union, subgraph, src, dst +using NamedGraphs.PartitionedGraphs: PartitionVertex, partitionedge +using ITensorNetworks: BeliefPropagationCache, AbstractITensorNetwork, AbstractFormNetwork, IndsNetwork, ITensorNetwork, insert_linkinds, ttn, union_all_inds, + neighbor_vertices, environment, messages, update_factor, message using DataGraphs: underlying_graph using ITensorNetworks.ModelHamiltonians: heisenberg +using ITensors: ITensor, noprime, dag, noncommonind, commonind, replaceind +using ITensors.NDTensors: denseblocks function NamedGraphs.GraphsExtensions.forest_cover(s::IndsNetwork; kwargs...) g = underlying_graph(s) @@ -30,12 +34,14 @@ function NamedGraphs.GraphsExtensions.forest_cover(s::IndsNetwork; kwargs...) return ss end -function model_ising_tno(s::IndsNetwork, model::Function; params...) +function model_tno(s::IndsNetwork, model::Function; two_site_params, one_site_params) forests = forest_cover(s) tnos = ITensorNetwork[] + n_forests = length(forests) + modified_one_site_params = deepcopy(one_site_params) for s_tree in forests g = underlying_graph(s_tree) - tno = ITensorNetwork(ttn(model(g; params...), s_tree)) + tno = ITensorNetwork(ttn(model(g; two_site_params..., modified_one_site_params...), s_tree)) missing_vertices = setdiff(vertices(s), vertices(g)) s_remaining_verts = subgraph(v -> v ∈ missing_vertices, s) @@ -49,18 +55,27 @@ function model_ising_tno(s::IndsNetwork, model::Function; params...) missing_edges = NamedEdge[e ∈ edges(s) ? e : reverse(e) for e in missing_edges] tno = insert_linkinds(tno, missing_edges; link_space = 1) push!(tnos, tno) + + for param in modified_one_site_params + for v in vertices(g) + if haskey(param, v) + delete!(param ,v) + end + end + end end return reduce(+, tnos) end -function model_tno_simplified(s::IndsNetwork, model::Function; params...) +function model_tno_simplified(s::IndsNetwork, model::Function; two_site_params, one_site_params) forests = forest_cover(s) tnos = ITensorNetwork[] + n_forests = length(forests) + modified_one_site_params = deepcopy(one_site_params) for s_tree in forests g = underlying_graph(s_tree) - @show params - tno = ITensorNetwork(ttn(model(g; params...), s_tree)) + tno = ITensorNetwork(ttn(model(g; two_site_params..., modified_one_site_params...), s_tree)) missing_vertices = setdiff(vertices(s), vertices(g)) s_remaining_verts = subgraph(v -> v ∈ missing_vertices, s) @@ -71,23 +86,38 @@ function model_tno_simplified(s::IndsNetwork, model::Function; params...) tno = disjoint_union(tno, identity_tno) tno = rename_vertices(v -> first(v), tno) push!(tnos, tno) + + for param in modified_one_site_params + for v in vertices(g) + if haskey(param, v) + delete!(param ,v) + end + end + end end return tnos end -function ising_dictified(g::AbstractGraph, Js, hs) +function ising_dictified(g::AbstractGraph; Js, hs, hls) ℋ = OpSum() for e in edges(g) - ℋ += Js[e], "Sz", src(e), "Sz", dst(e) + if haskey(Js, e) && !iszero(Js[e]) + ℋ += Js[e], "Sz", src(e), "Sz", dst(e) + end end for v in vertices(g) - ℋ += hs[v], "Sx", v + if haskey(hs, v) && !iszero(hs[v]) + ℋ += hs[v], "Sx", v + end + if haskey(hls, v) && !iszero(hls[v]) + ℋ += hls[v], "Sz", v + end end return ℋ end -function xyz_dictified(g::AbstractGraph, Jxs, Jys, Jzs) +function xyz_dictified(g::AbstractGraph; Jxs, Jys, Jzs) ℋ = OpSum() for e in edges(g) ℋ += Jxs[e], "X", src(e), "X", dst(e) @@ -106,4 +136,42 @@ function n_site_expect(ψIψ::AbstractFormNetwork, ops::Vector{String}, vs; kwar denominator = contract([∂ψIψ_∂vs; ψIψ_vs]; contract_kwargs...)[] return numerator / denominator +end + +function heavy_hex_lattice_graph(n::Int64, m::Int64) + """Create heavy-hex lattice geometry""" + g = named_hexagonal_lattice_graph(n, m) + g = decorate_graph_edges(g) + + vertex_rename = Dictionary() + for (i,v) in enumerate(vertices(g)) + set!(vertex_rename, v, (i,)) + end + g = rename_vertices(v -> vertex_rename[v], g) + + return g +end + +function BP_apply(o::ITensor, ψ::AbstractITensorNetwork, bpc::BeliefPropagationCache; apply_kwargs...) + bpc = copy(bpc) + ψ = copy(ψ) + vs = neighbor_vertices(ψ, o) + envs = environment(bpc, PartitionVertex.(vs)) + singular_values! = Ref(ITensor()) + ψ = noprime(apply(o, ψ; envs, singular_values!, normalize=true, apply_kwargs...)) + ψdag = prime(dag(ψ); sites=[]) + if length(vs) == 2 + v1, v2 = vs + pe = partitionedge(bpc, (v1, "bra") => (v2, "bra")) + mts = messages(bpc) + ind1, ind2 = noncommonind(singular_values![], ψ[v1]), commonind(singular_values![], ψ[v1]) + singular_values![] = denseblocks(replaceind(singular_values![], ind1, ind2')) + set!(mts, pe, ITensor[singular_values![]]) + set!(mts, reverse(pe), ITensor[singular_values![]]) + end + for v in vs + bpc = update_factor(bpc, (v, "ket"), ψ[v]) + bpc = update_factor(bpc, (v, "bra"), ψdag[v]) + end + return ψ, bpc end \ No newline at end of file diff --git a/examples/imaginary_time_evo.jl b/examples/imaginary_time_evo.jl new file mode 100644 index 00000000..59d48c8a --- /dev/null +++ b/examples/imaginary_time_evo.jl @@ -0,0 +1,34 @@ + +using ITensors: Trotter +using ITensorNetworks: norm_sqr_network, update +using SplitApplyCombine: group + +function imaginary_time_evo(s::IndsNetwork, ψ::ITensorNetwork, model::Function, dbetas::Vector{<:Tuple}, nbetas::Int64; model_params, + bp_update_kwargs = (; maxiter = 10, tol = 1e-10), apply_kwargs = (; cutoff = 1e-12, maxdim = 10)) + ψ = copy(ψ) + g = underlying_graph(ψ) + + ℋ =model(g; model_params...) + ψψ = norm_sqr_network(ψ) + bpc = BeliefPropagationCache(ψψ, group(v->v[1], vertices(ψψ))) + bpc = update(bpc; bp_update_kwargs...) + println("Starting Imaginary Time Evolution") + β = 0 + for (i, period) in enumerate(dbetas) + nbetas, dβ = first(period), last(period) + println("Entering evolution period $i , β = $β, dβ = $dβ") + U = exp(- dβ * ℋ, alg = Trotter{1}()) + gates = Vector{ITensor}(U, s) + for i in 1:nbetas + for gate in gates + ψ, bpc = BP_apply(gate, ψ, bpc; apply_kwargs...) + end + β += dβ + bpc = update(bpc; bp_update_kwargs...) + end + e = sum(expect(ψ, ℋ; alg = "bp")) + println("Energy is $e") + end + + return ψ +end \ No newline at end of file diff --git a/src/solvers/alternating_update/region_update.jl b/src/solvers/alternating_update/region_update.jl index a53b6f7f..135597d2 100644 --- a/src/solvers/alternating_update/region_update.jl +++ b/src/solvers/alternating_update/region_update.jl @@ -139,8 +139,7 @@ function region_update(projected_operators, state; outputlevel, internal_kwargs, ) = region_kwargs ψOψ_bpcs, ψIψ_bpc = first(projected_operators), last(projected_operators) - #ψOψ_bpc = only(ψOψ_bpcs) - + #Fix extracter, update and inserter to work with sum of ψOψ_bpcs local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts = extracter(state, ψOψ_bpcs, ψIψ_bpc, region; extracter_kwargs...) diff --git a/src/solvers/dmrg.jl b/src/solvers/dmrg.jl index 7ccef86e..607e476b 100644 --- a/src/solvers/dmrg.jl +++ b/src/solvers/dmrg.jl @@ -20,7 +20,7 @@ function ITensorMPS.dmrg( state = alternating_update( operator, init_state; nsweeps, nsites, updater, region_observer!, kwargs... ) - eigval = only(eigvals_ref[]) + eigval = first(eigvals_ref[]) return eigval, state end diff --git a/src/solvers/insert/insert.jl b/src/solvers/insert/insert.jl index e1173448..b61d6c34 100644 --- a/src/solvers/insert/insert.jl +++ b/src/solvers/insert/insert.jl @@ -22,7 +22,6 @@ function default_inserter( indsTe = inds(state[ortho_vert]) L, phi, spec = factorize(phi, indsTe; tags=tags(state, e), maxdim, mindim, cutoff) state[ortho_vert] = L - else v = ortho_vert end @@ -57,6 +56,7 @@ function bp_inserter(ψ::AbstractITensorNetwork, ψAψ_bpcs::Vector{<:BeliefProp form_network = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) ψAψ_bpcs = BeliefPropagationCache[reset_messages(ψAψ_bpc) for ψAψ_bpc in ψAψ_bpcs] ψIψ_bpc = reset_messages(ψIψ_bpc) + @show messages(ψIψ_bpc) if length(region) == 1 states = [state] elseif length(region) == 2 @@ -88,5 +88,7 @@ function bp_inserter(ψ::AbstractITensorNetwork, ψAψ_bpcs::Vector{<:BeliefProp updated_ψIψ = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) numerator_terms = [scalar(unpartitioned_graph(partitioned_tensornetwork(ψAψ_bpc)); cache! = Ref(ψAψ_bpc), alg = "bp") for ψAψ_bpc in ψAψ_bpcs] eigval = sum(numerator_terms) / scalar(updated_ψIψ; cache! = Ref(ψIψ_bpc), alg = "bp") - return ψ, ψAψ_bpcs, ψIψ_bpc, spec, (; eigvals=[eigval]) + @show eigval + @show scalar(only(ψAψ_bpcs); alg = "exact") / scalar(ψIψ_bpc; alg = "exact") + return ψ, ψAψ_bpcs, ψIψ_bpc, spec, (; eigvals=[eigval]) end \ No newline at end of file diff --git a/src/solvers/local_solvers/eigsolve.jl b/src/solvers/local_solvers/eigsolve.jl index aa5ccc6c..a5d5e96d 100644 --- a/src/solvers/local_solvers/eigsolve.jl +++ b/src/solvers/local_solvers/eigsolve.jl @@ -50,7 +50,6 @@ function bp_eigsolve_updater(init::ITensor, ∂ψAψ_bpc_∂rs::Vector, sqrt_mts howmany = 1 vals, vecs, info = eigsolve(get_new_state_partial,init,howmany,:SR; ishermitian = true, kwargs...) - state = first(vecs) state = noprime(contract([state; inv_sqrt_mts])) diff --git a/src/solvers/sweep_plans/sweep_plans.jl b/src/solvers/sweep_plans/sweep_plans.jl index cbace9e1..12ea8b88 100644 --- a/src/solvers/sweep_plans/sweep_plans.jl +++ b/src/solvers/sweep_plans/sweep_plans.jl @@ -147,13 +147,10 @@ function bp_sweep_plan(g::AbstractGraph; root_vertex=GraphsExtensions.default_root_vertex(graph), region_kwargs, nsites::Int, - es = edges(g), - vs = vertices(g)) + es = vcat(collect(edges(g)), collect(reverse(edges(g)))), + vs = vcat(reverse(collect(vertices(g))), collect(vertices(g)))) region_kwargs = (; internal_kwargs = (;), region_kwargs...) - L = length(vertices(g)) - es = vcat([NamedEdge((i, 1) => (i + 1, 1)) for i in 1:(L-1)], [NamedEdge((L,1) => (1,1))]) - if nsites == 2 return collect( flatten(map(e -> [([src(e), dst(e)], region_kwargs)], es)) From e87e1b362013cc4ee14f235b28d330ccde32a836 Mon Sep 17 00:00:00 2001 From: Joey Date: Fri, 7 Jun 2024 13:51:33 -0400 Subject: [PATCH 08/27] Big Improvements --- examples/belief_propagation_dmrg.jl | 85 --------- examples/exampleutils.jl | 177 ------------------ src/beliefpropagationdmrg/bp_dmrg.jl | 75 ++++++++ src/beliefpropagationdmrg/bp_extracter.jl | 19 ++ src/beliefpropagationdmrg/bp_inserter.jl | 63 +++++++ src/beliefpropagationdmrg/bp_updater.jl | 28 +++ src/beliefpropagationdmrg/main.jl | 30 +++ .../tensornetworkoperators.jl | 56 ++++++ src/beliefpropagationdmrg/utils.jl | 105 +++++++++++ src/caches/beliefpropagationcache.jl | 40 +++- src/solvers/local_solvers/eigsolve.jl | 23 --- 11 files changed, 412 insertions(+), 289 deletions(-) delete mode 100644 examples/belief_propagation_dmrg.jl delete mode 100644 examples/exampleutils.jl create mode 100644 src/beliefpropagationdmrg/bp_dmrg.jl create mode 100644 src/beliefpropagationdmrg/bp_extracter.jl create mode 100644 src/beliefpropagationdmrg/bp_inserter.jl create mode 100644 src/beliefpropagationdmrg/bp_updater.jl create mode 100644 src/beliefpropagationdmrg/main.jl create mode 100644 src/beliefpropagationdmrg/tensornetworkoperators.jl create mode 100644 src/beliefpropagationdmrg/utils.jl diff --git a/examples/belief_propagation_dmrg.jl b/examples/belief_propagation_dmrg.jl deleted file mode 100644 index b1a679e0..00000000 --- a/examples/belief_propagation_dmrg.jl +++ /dev/null @@ -1,85 +0,0 @@ -using NamedGraphs.GraphsExtensions: add_edge, rem_edge -using NamedGraphs: nv, src -using NamedGraphs.NamedGraphGenerators: named_grid, named_comb_tree, named_binary_tree -using ITensors: ITensors, Algorithm, expect, mapprime -using ITensors: dmrg, siteinds -using ITensorNetworks: alternating_update, bp_inserter, bp_extracter, bp_eigsolve_updater, random_tensornetwork, ttn, inner, maxlinkdim, map_inds, combine_linkinds -using ITensorNetworks.ModelHamiltonians: heisenberg, ising -using ITensorNetworks: ITensorNetwork -using Dictionaries -using ITensors: Scaled, Prod, site, which_op, inds, combiner, op, sim -using ITensors.NDTensors: array -using LinearAlgebra - -using Random: Random - -include("exampleutils.jl") -include("imaginary_time_evo.jl") - -ITensors.disable_warn_order() - -function smallest_eigvalue(A::AbstractITensorNetwork) - out = reduce(*, [A[v] for v in vertices(A)]) - out = out * combiner(inds(out; plev = 0)) *combiner(inds(out; plev = 1)) - out = array(out) - return minimum(LinearAlgebra.eigvals(out)) -end - -function main() - L = 4 - h, hl, J = 0.5, 0.1, -1.0 - g = named_grid((L,1); periodic = true) - #g = heavy_hex_lattice_graph(2,2) - hs = Dictionary(vertices(g), [h for v in vertices(g)]) - hls = Dictionary(vertices(g), [hl for v in vertices(g)]) - Js = Dictionary(edges(g), [J for e in edges(g)]) - one_site_params = (; hs, hls) - two_site_params = (; Js) - s = siteinds("S=1/2", g) - A = model_tno(s, ising_dictified; two_site_params, one_site_params) - A2 = first(model_tno_simplified(s, ising_dictified; two_site_params, one_site_params)) - - χ, χmax, χTEBDmax = 1, 3, 3 - nperiods = 10 - dβs = [(25, 0.2/((2^(i-1)))) for i in 1:nperiods] - nbetas = 200 - Random.seed!(1234) - cache_update_kwargs = (;maxiter = 25, tol = 1e-10) - #ψ_init = ITensorNetwork(v -> "↑", s) - ψ_init = random_tensornetwork(s; link_space = χ) - H_opsum = ising(s; h, hl, J1 = J) - e_init = sum(expect(ψ_init, H_opsum; alg = "bp")) - println("Initial Energy is $e_init") - #ψ_imag_time = imaginary_time_evo(s, ψ_init, ising_dictified, dβs, nbetas; model_params = (; two_site_params..., one_site_params...), bp_update_kwargs = cache_update_kwargs, - #apply_kwargs = (; cutoff = 1e-10, maxdim = χTEBDmax)) - #ψ_init = copy(ψ_imag_time) - - inserter_bp_kwargs = (; maxdim = χmax, cutoff = 1e-14, cache_update_kwargs) - inserter_ttn_kwargs = (; maxdim = χmax) - updater_kwargs = (; tol = 1e-14, krylovdim = 3, maxiter = 2, verbosity = 0, eager = false) - nsites, nsweeps = 1, 2 - - A = ITensorNetwork[A] - A2 = ITensorNetwork[A2] - H_opsum_A2 = ising(underlying_graph(only(A2)); h, hl, J1 = J) - @show smallest_eigvalue(only(A2)) - @show sum(expect(ψ_init, H_opsum_A2; alg = "bp")) - #@time e_bp_vectorized, ψ_bp_vectorized = dmrg(A_vec, ψ_init; nsweeps, nsites, updater_kwargs, inserter_kwargs = inserter_bp_kwargs) - @time e_bp_nonvectorized, ψ_bp_nonvectorized = dmrg(A2, ψ_init; nsweeps, nsites, updater_kwargs, inserter_kwargs = inserter_bp_kwargs) - @show sum(expect(ψ_bp_nonvectorized, H_opsum_A2; alg = "bp")) - #@time e_ttn, ψ_ttn = dmrg(ttn(A), ttn(ψ_init); nsweeps, nsites, updater_kwargs, inserter_kwargs = inserter_ttn_kwargs) - - #e_final_vectorized = sum(expect(ψ_bp_vectorized, H_opsum; alg = "bp")) - e_final_nonvectorized = sum(expect(ψ_bp_nonvectorized, H_opsum; alg = "bp")) - - #@show e_final_vectorized - @show e_final_nonvectorized - #@show e_ttn - - #@show expect(ψ_bp_nonvectorized, "Sx") - @show expect(ψ_bp_nonvectorized, "Sx") - #@show e_bp - #@show sum([inner(ψ_bp, A, ψ_bp; alg = "exact")] for A in A_vec) / inner(ψ_bp, ψ_bp; alg = "exact") -end - -main() \ No newline at end of file diff --git a/examples/exampleutils.jl b/examples/exampleutils.jl deleted file mode 100644 index 13e1418d..00000000 --- a/examples/exampleutils.jl +++ /dev/null @@ -1,177 +0,0 @@ -using ITensors: siteinds, Op, prime, OpSum, apply -using Graphs: AbstractGraph, SimpleGraph, edges, vertices, is_tree, connected_components -using NamedGraphs: NamedGraph, NamedEdge, NamedGraphs, rename_vertices -using NamedGraphs.NamedGraphGenerators: named_grid, named_hexagonal_lattice_graph -using NamedGraphs.GraphsExtensions: decorate_graph_edges, forest_cover, add_edges, rem_edges, add_vertices, rem_vertices, disjoint_union, subgraph, src, dst -using NamedGraphs.PartitionedGraphs: PartitionVertex, partitionedge -using ITensorNetworks: BeliefPropagationCache, AbstractITensorNetwork, AbstractFormNetwork, IndsNetwork, ITensorNetwork, insert_linkinds, ttn, union_all_inds, - neighbor_vertices, environment, messages, update_factor, message -using DataGraphs: underlying_graph -using ITensorNetworks.ModelHamiltonians: heisenberg -using ITensors: ITensor, noprime, dag, noncommonind, commonind, replaceind -using ITensors.NDTensors: denseblocks - -function NamedGraphs.GraphsExtensions.forest_cover(s::IndsNetwork; kwargs...) - g = underlying_graph(s) - ss = IndsNetwork[] - no_edges= 0 - for f in forest_cover(g) - for g_tree_vertices in connected_components(f) - g_tree = f[g_tree_vertices] - if(length(edges(g_tree))) != 0 - s_f = subgraph(v -> v ∈ vertices(g_tree), s) - edges_to_remove = filter(e -> e ∉ edges(g_tree) && reverse(e) ∉ edges(g_tree), edges(s_f)) - s_f = rem_edges(s_f, edges_to_remove) - push!(ss, s_f) - @assert is_tree(s_f) - no_edges += length(edges(s_f)) - end - end - end - - @assert no_edges == length(edges(s)) - - return ss -end - -function model_tno(s::IndsNetwork, model::Function; two_site_params, one_site_params) - forests = forest_cover(s) - tnos = ITensorNetwork[] - n_forests = length(forests) - modified_one_site_params = deepcopy(one_site_params) - for s_tree in forests - g = underlying_graph(s_tree) - tno = ITensorNetwork(ttn(model(g; two_site_params..., modified_one_site_params...), s_tree)) - - missing_vertices = setdiff(vertices(s), vertices(g)) - s_remaining_verts = subgraph(v -> v ∈ missing_vertices, s) - - @assert issubset(edges(s_tree), edges(s)) - @assert issubset(edges(s_remaining_verts), edges(s)) - identity_tno = ITensorNetwork(Op("I"), union_all_inds(s_remaining_verts, prime(s_remaining_verts))) - tno = disjoint_union(tno, identity_tno) - tno = rename_vertices(v -> first(v), tno) - missing_edges = filter(e -> e ∉ edges(tno) && reverse(e) ∉ edges(tno), edges(s)) - missing_edges = NamedEdge[e ∈ edges(s) ? e : reverse(e) for e in missing_edges] - tno = insert_linkinds(tno, missing_edges; link_space = 1) - push!(tnos, tno) - - for param in modified_one_site_params - for v in vertices(g) - if haskey(param, v) - delete!(param ,v) - end - end - end - end - - return reduce(+, tnos) -end - -function model_tno_simplified(s::IndsNetwork, model::Function; two_site_params, one_site_params) - forests = forest_cover(s) - tnos = ITensorNetwork[] - n_forests = length(forests) - modified_one_site_params = deepcopy(one_site_params) - for s_tree in forests - g = underlying_graph(s_tree) - tno = ITensorNetwork(ttn(model(g; two_site_params..., modified_one_site_params...), s_tree)) - - missing_vertices = setdiff(vertices(s), vertices(g)) - s_remaining_verts = subgraph(v -> v ∈ missing_vertices, s) - - @assert issubset(edges(s_tree), edges(s)) - @assert issubset(edges(s_remaining_verts), edges(s)) - identity_tno = ITensorNetwork(Op("I"), union_all_inds(s_remaining_verts, prime(s_remaining_verts))) - tno = disjoint_union(tno, identity_tno) - tno = rename_vertices(v -> first(v), tno) - push!(tnos, tno) - - for param in modified_one_site_params - for v in vertices(g) - if haskey(param, v) - delete!(param ,v) - end - end - end - end - - return tnos -end - -function ising_dictified(g::AbstractGraph; Js, hs, hls) - ℋ = OpSum() - for e in edges(g) - if haskey(Js, e) && !iszero(Js[e]) - ℋ += Js[e], "Sz", src(e), "Sz", dst(e) - end - end - for v in vertices(g) - if haskey(hs, v) && !iszero(hs[v]) - ℋ += hs[v], "Sx", v - end - if haskey(hls, v) && !iszero(hls[v]) - ℋ += hls[v], "Sz", v - end - end - return ℋ -end - -function xyz_dictified(g::AbstractGraph; Jxs, Jys, Jzs) - ℋ = OpSum() - for e in edges(g) - ℋ += Jxs[e], "X", src(e), "X", dst(e) - ℋ += Jys[e], "Y", src(e), "Y", dst(e) - ℋ += Jzs[e], "Z", src(e), "Z", dst(e) - end - return ℋ -end - -function n_site_expect(ψIψ::AbstractFormNetwork, ops::Vector{String}, vs; kwargs...) - ψIψ_vs = [ψIψ[operator_vertex(ψIψ, v)] for v in vs] - s_vs = [commonind(ψIψ[ket_vertex(ψIψ, v)], ψIψ_vs[i]) for (i, v) in enumerate(vs)] - operators = [ITensors.op(ops[i].which_op, s_vs[i]) for i in 1:length(ops)] - ∂ψIψ_∂vs = environment(ψIψ, operator_vertices(ψIψ, [vs]); kwargs...) - numerator = contract([∂ψIψ_∂vs; operators]; contract_kwargs...)[] - denominator = contract([∂ψIψ_∂vs; ψIψ_vs]; contract_kwargs...)[] - - return numerator / denominator -end - -function heavy_hex_lattice_graph(n::Int64, m::Int64) - """Create heavy-hex lattice geometry""" - g = named_hexagonal_lattice_graph(n, m) - g = decorate_graph_edges(g) - - vertex_rename = Dictionary() - for (i,v) in enumerate(vertices(g)) - set!(vertex_rename, v, (i,)) - end - g = rename_vertices(v -> vertex_rename[v], g) - - return g -end - -function BP_apply(o::ITensor, ψ::AbstractITensorNetwork, bpc::BeliefPropagationCache; apply_kwargs...) - bpc = copy(bpc) - ψ = copy(ψ) - vs = neighbor_vertices(ψ, o) - envs = environment(bpc, PartitionVertex.(vs)) - singular_values! = Ref(ITensor()) - ψ = noprime(apply(o, ψ; envs, singular_values!, normalize=true, apply_kwargs...)) - ψdag = prime(dag(ψ); sites=[]) - if length(vs) == 2 - v1, v2 = vs - pe = partitionedge(bpc, (v1, "bra") => (v2, "bra")) - mts = messages(bpc) - ind1, ind2 = noncommonind(singular_values![], ψ[v1]), commonind(singular_values![], ψ[v1]) - singular_values![] = denseblocks(replaceind(singular_values![], ind1, ind2')) - set!(mts, pe, ITensor[singular_values![]]) - set!(mts, reverse(pe), ITensor[singular_values![]]) - end - for v in vs - bpc = update_factor(bpc, (v, "ket"), ψ[v]) - bpc = update_factor(bpc, (v, "bra"), ψdag[v]) - end - return ψ, bpc -end \ No newline at end of file diff --git a/src/beliefpropagationdmrg/bp_dmrg.jl b/src/beliefpropagationdmrg/bp_dmrg.jl new file mode 100644 index 00000000..f3b5168b --- /dev/null +++ b/src/beliefpropagationdmrg/bp_dmrg.jl @@ -0,0 +1,75 @@ +using NamedGraphs.GraphsExtensions: is_tree +using NamedGraphs.PartitionedGraphs: partitionvertices +using ITensorNetworks: ITensorNetwork, QuadraticFormNetwork, BeliefPropagationCache, update, rescale_messages +using ITensors: scalar + +include("utils.jl") +include("bp_extracter.jl") +include("bp_inserter.jl") +include("bp_updater.jl") + +default_bp_update_kwargs(ψ::ITensorNetwork) = is_tree(ψ) ? (;) : (; maxiter = 25, tol = 1e-7) + + +function build_update_caches(operators::Vector{ITensorNetwork}, ψ_init::ITensorNetwork; cache_update_kwargs = default_bp_update_kwargs(ψ_init)) + ψ = copy(ψ_init) + ψIψ = QuadraticFormNetwork(ψ) + ψIψ_bpc = BeliefPropagationCache(ψIψ) + ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) + + ψOψs = QuadraticFormNetwork[QuadraticFormNetwork(operator, ψ) for operator in operators] + ψOψ_bpcs = BeliefPropagationCache[BeliefPropagationCache(ψOψ) for ψOψ in ψOψs] + ψOψ_bpcs = BeliefPropagationCache[update(ψOψ_bpc; cache_update_kwargs...) for ψOψ_bpc in ψOψ_bpcs] + + return (ψ, ψIψ_bpc, ψOψ_bpcs) +end + +function default_vertex_order(ψ_init) + verts = collect(vertices(ψ_init)) + return [[v] for v in vcat(verts[1:length(verts) - 1], reverse(verts))] +end + +alt_vertex_order(ψ_init) = [[v] for v in collect(vertices(ψ_init))] + +function bp_dmrg(operators::Vector{ITensorNetwork}, ψ_init::ITensorNetwork; no_sweeps = 1, bp_update_kwargs = default_bp_update_kwargs( ψ_init), + vertex_order_func = default_vertex_order) + state, ψIψ_bpc, ψOψ_bpcs = build_update_caches(operators, ψ_init) + regions = vertex_order_func(state) + + energy = sum(scalar.(ψOψ_bpcs)) / scalar(ψIψ_bpc) + println("Initial energy is $energy") + energies = [energy] + + for i in 1:no_sweeps + println("Beginning sweep $i") + for region in regions + println("Updating vertex $region") + + state, ψIψ_bpc, ψOψ_bpcs = bp_renormalize(state, ψIψ_bpc, ψOψ_bpcs) + + v = only(region) + form_op_v = (v, "operator") + ψIψ_bpc = update(ψIψ_bpc; bp_update_kwargs...) + local_ops = local_op.(ψOψ_bpcs, (v,)) + ψOψ_bpcs = replace_v.(ψOψ_bpcs, (v,)) + ψOψ_bpcs = update.(ψOψ_bpcs; bp_update_kwargs...) + ψOψ_bpcs_scalars = scalar.(ψOψ_bpcs) + pv = PartitionVertex(v) + ψOψ_bpcs = BeliefPropagationCache[rescale_messages(ψOψ_bpc, ψOψ_bpc_scalar, pv) for (ψOψ_bpc, ψOψ_bpc_scalar) in zip(ψOψ_bpcs, ψOψ_bpcs_scalars)] + ψOψ_bpcs = BeliefPropagationCache[update_factor(ψOψ_bpc, form_op_v, local_op) for (ψOψ_bpc, local_op) in zip(ψOψ_bpcs, local_ops)] + local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts = bp_extracter(state, ψOψ_bpcs, ψIψ_bpc, region) + + #Do an eigsolve + local_state, _ = bp_eigsolve_updater(local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts) + + state, ψOψ_bpcs, ψIψ_bpc, _, _ = bp_inserter_one_site(state, ψOψ_bpcs, ψIψ_bpc, local_state, region; cache_update_kwargs =bp_update_kwargs) + + ψOψ_bpcs = update.(ψOψ_bpcs; bp_update_kwargs...) + energy = sum(scalar.(ψOψ_bpcs)) / scalar(ψIψ_bpc) + println("Current energy is $energy") + append!(energies, energy) + end + end + + return state, energies +end diff --git a/src/beliefpropagationdmrg/bp_extracter.jl b/src/beliefpropagationdmrg/bp_extracter.jl new file mode 100644 index 00000000..a56b7638 --- /dev/null +++ b/src/beliefpropagationdmrg/bp_extracter.jl @@ -0,0 +1,19 @@ +using ITensors: scalartype +using ITensorNetworks: ket_vertices, bra_vertices +using ITensorNetworks.ITensorsExtensions: map_eigvals + + +function bp_extracter(ψ::AbstractITensorNetwork, ψAψ_bpcs::Vector{<:BeliefPropagationCache}, ψIψ_bpc::BeliefPropagationCache, region; + regularization = 10*eps(scalartype(ψ))) + form_network = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) + form_ket_vertices, form_bra_vertices = ket_vertices(form_network, region), bra_vertices(form_network, region) + ∂ψAψ_bpc_∂rs = [environment(ψAψ_bpc, [form_ket_vertices; form_bra_vertices]) for ψAψ_bpc in ψAψ_bpcs] + state = prod(ψ[v] for v in region) + messages = environment(ψIψ_bpc, partitionvertices(ψIψ_bpc, form_ket_vertices)) + f_sqrt = sqrt ∘ (x -> x + regularization) + f_inv_sqrt = inv ∘ sqrt ∘ (x -> x + regularization) + sqrt_mts = [map_eigvals(f_sqrt, mt, inds(mt)[1], inds(mt)[2]; ishermitian=true) for mt in messages] + inv_sqrt_mts = [map_eigvals(f_inv_sqrt, mt, inds(mt)[1], inds(mt)[2]; ishermitian=true) for mt in messages] + + return state, ∂ψAψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts + end \ No newline at end of file diff --git a/src/beliefpropagationdmrg/bp_inserter.jl b/src/beliefpropagationdmrg/bp_inserter.jl new file mode 100644 index 00000000..0b7cb1c4 --- /dev/null +++ b/src/beliefpropagationdmrg/bp_inserter.jl @@ -0,0 +1,63 @@ +# function bp_inserter(ψ::AbstractITensorNetwork, ψAψ_bpcs::Vector{<:BeliefPropagationCache}, +# ψIψ_bpc::BeliefPropagationCache, state::ITensor, region; cache_update_kwargs = (;), kwargs...) + +# spec = nothing + +# form_network = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) +# if length(region) == 1 +# states = [state] +# elseif length(region) == 2 +# v1, v2 = region[1], region[2] +# e = edgetype(ψ)(v1, v2) +# pe = partitionedge(ψIψ_bpc, ket_vertex(form_network, v1) => bra_vertex(form_network, v2)) +# stateᵥ₁, stateᵥ₂, spec = factorize_svd(state,uniqueinds(ψ[v1], ψ[v2]); ortho="none", tags=edge_tag(e),kwargs...) +# states = noprime.([stateᵥ₁, stateᵥ₂]) +# ψIψ_bpc = reset_messages(ψIψ_bpc, [pe, reverse(pe)]) +# ψAψ_bpcs = BeliefPropagationCache[reset_messages(ψAψ_bpc, [pe, reverse(pe)]) for ψAψ_bpc in ψAψ_bpcs] +# #TODO: Insert spec into the message tensor guess here?! +# end + +# for (i, v) in enumerate(region) +# state = states[i] +# state_dag = copy(state) +# form_bra_v, form_ket_v = bra_vertex(form_network, v), ket_vertex(form_network, v) +# ψ[v] =state +# state_dag = replaceinds(dag(state_dag), inds(state_dag), dual_index_map(form_network).(inds(state_dag))) +# ψAψ_bpcs = BeliefPropagationCache[update_factor(ψAψ_bpc, form_ket_v, state) for ψAψ_bpc in ψAψ_bpcs] +# ψAψ_bpcs = BeliefPropagationCache[update_factor(ψAψ_bpc, form_bra_v, state_dag) for ψAψ_bpc in ψAψ_bpcs] +# ψIψ_bpc = update_factor(ψIψ_bpc, form_ket_v, state) +# ψIψ_bpc = update_factor(ψIψ_bpc, form_bra_v, state_dag) +# end + + +# ψAψ_bpcs = BeliefPropagationCache[update(ψAψ_bpc; cache_update_kwargs...) for ψAψ_bpc in ψAψ_bpcs] + +# ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) + +# return ψ, ψAψ_bpcs, ψIψ_bpc, spec, (; eigvals=[0.0]) +# end + +function bp_inserter_one_site(ψ::AbstractITensorNetwork, ψAψ_bpcs::Vector{<:BeliefPropagationCache}, + ψIψ_bpc::BeliefPropagationCache, state::ITensor, region; cache_update_kwargs = (;), kwargs...) + + spec = nothing + + ψ = copy(ψ) + form_network = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) + @assert length(region) == 1 + states = [state] + + for (i, v) in enumerate(region) + state = states[i] + state_dag = copy(state) + form_bra_v, form_op_v, form_ket_v = bra_vertex(form_network, v), operator_vertex(form_network, v), ket_vertex(form_network, v) + ψ[v] =state + state_dag = replaceinds(dag(state_dag), inds(state_dag), dual_index_map(form_network).(inds(state_dag))) + ψAψ_bpcs = BeliefPropagationCache[update_factor(ψAψ_bpc, form_ket_v, state) for ψAψ_bpc in ψAψ_bpcs] + ψAψ_bpcs = BeliefPropagationCache[update_factor(ψAψ_bpc, form_bra_v, state_dag) for ψAψ_bpc in ψAψ_bpcs] + ψIψ_bpc = update_factor(ψIψ_bpc, form_ket_v, state) + ψIψ_bpc = update_factor(ψIψ_bpc, form_bra_v, state_dag) + end + + return ψ, ψAψ_bpcs, ψIψ_bpc, spec, (; eigvals=[0.0]) +end \ No newline at end of file diff --git a/src/beliefpropagationdmrg/bp_updater.jl b/src/beliefpropagationdmrg/bp_updater.jl new file mode 100644 index 00000000..0263f8c5 --- /dev/null +++ b/src/beliefpropagationdmrg/bp_updater.jl @@ -0,0 +1,28 @@ +using ITensors: contract +using ITensors.ContractionSequenceOptimization: optimal_contraction_sequence +using KrylovKit: eigsolve + +default_krylov_kwargs() = (; tol = 1e-14, krylovdim = 3, maxiter = 2, verbosity = 0, eager = false) + +function bp_eigsolve_updater(init::ITensor, ∂ψAψ_bpc_∂rs::Vector, sqrt_mts, inv_sqrt_mts; krylov_kwargs = default_krylov_kwargs()) + + #TODO: Put inv_sqrt_mts onto ∂ψAψ_bpc_∂r beforehand. Need to do this in an efficient way without + #precontracting ∂ψAψ_bpc_∂r + function get_new_state(∂ψAψ_bpc_∂rs::Vector, inv_sqrt_mts, state::ITensor; sequences = ["automatic" for i in length(∂ψAψ_bpc_∂rs)]) + state = noprime(contract([state; inv_sqrt_mts])) + states = ITensor[dag(noprime(contract([copy(state); ∂ψAψ_bpc_∂r]; sequence = sequences[i]))) for (i, ∂ψAψ_bpc_∂r) in enumerate(∂ψAψ_bpc_∂rs)] + state = reduce(+, states) + return noprime(contract([state; (inv_sqrt_mts)])) + end + + init = noprime(contract([init; sqrt_mts])) + sequences = [optimal_contraction_sequence([init; ∂ψAψ_bpc_∂r]) for ∂ψAψ_bpc_∂r in ∂ψAψ_bpc_∂rs] + get_new_state_ = state -> get_new_state(∂ψAψ_bpc_∂rs, inv_sqrt_mts, state; sequences) + howmany = 1 + + vals, vecs, info = eigsolve(get_new_state_,init,howmany,:SR; ishermitian = true, krylov_kwargs...) + state = first(vecs) + state = noprime(contract([state; inv_sqrt_mts])) + + return state, (; info, eigvals=vals) + end \ No newline at end of file diff --git a/src/beliefpropagationdmrg/main.jl b/src/beliefpropagationdmrg/main.jl new file mode 100644 index 00000000..9dc691c7 --- /dev/null +++ b/src/beliefpropagationdmrg/main.jl @@ -0,0 +1,30 @@ +using ITensorNetworks: random_tensornetwork +using NamedGraphs.NamedGraphGenerators: named_comb_tree +using NPZ +using ITensors: expect + +include("tensornetworkoperators.jl") +include("bp_dmrg.jl") + + +function main() + L = 24 + g = named_grid((L,1); periodic = true) + h,hl = 0.8, 0.2 + s = siteinds("S=1/2", g) + χ = 2 + #ψ0 = ITensorNetwork(v -> "↑", s) + ψ0 = random_tensornetwork(s; link_space = χ) + + H = ising(s; h, hl) + tnos = opsum_to_tno(s, H) + tno = reduce(+, tnos) + + ψfinal, energies = bp_dmrg(tnos, ψ0; no_sweeps = 10, vertex_order_func = alt_vertex_order) + final_mags = expect(ψfinal, "Z", ; alg = "bp") + npzwrite("/Users/jtindall/Documents/Data/BPDMRG/ISINGL$(L)h$(h)hl$(hl)chi$(χ).npz", energies = energies, final_mags = final_mags) + +end + + +main() \ No newline at end of file diff --git a/src/beliefpropagationdmrg/tensornetworkoperators.jl b/src/beliefpropagationdmrg/tensornetworkoperators.jl new file mode 100644 index 00000000..bb4f2d90 --- /dev/null +++ b/src/beliefpropagationdmrg/tensornetworkoperators.jl @@ -0,0 +1,56 @@ +using NamedGraphs: NamedGraph, AbstractGraph, vertices, edges, NamedEdge +using NamedGraphs.NamedGraphGenerators: named_grid, named_hexagonal_lattice_graph +using NamedGraphs.GraphsExtensions: forest_cover, connected_components, add_edges, add_edge, add_vertices, rem_edges, decorate_graph_edges, rename_vertices + +using ITensors: OpSum, siteinds, sites, inds, combiner +using ITensors.NDTensors: array +using ITensorNetworks: AbstractITensorNetwork, ITensorNetwork, IndsNetwork, underlying_graph, ttn, maxlinkdim +using ITensorNetworks.ModelHamiltonians: ising +using Dictionaries + +using LinearAlgebra: eigvals + +function connect_forests(s::IndsNetwork) + g = underlying_graph(s) + fs = forest_cover(g) + fs_connected = Tuple{IndsNetwork, Vector{NamedEdge}}[] + for f in fs + s_f = copy(s) + verts = vertices(f) + es = edges(f) + c_f = NamedGraph[f[vs] for vs in connected_components(f)] + dummy_es = NamedEdge[NamedEdge(first(vertices(c_f[i])) => first(vertices(c_f[i+1]))) for i in 1:(length(c_f) - 1)] + s_f = rem_edges(s_f, edges(s_f)) + s_f = add_edges(s_f, vcat(es, dummy_es)) + push!(fs_connected, (s_f, dummy_es)) + end + return fs_connected +end + +function opsum_to_tno(s::IndsNetwork, H::OpSum; cutoff::Float64 = 1e-14, insert_dummy_inds = false) + s_fs_connected = connect_forests(s) + no_forests = length(s_fs_connected) + tnos = ITensorNetwork[] + for (s_f, dummy_edges) in s_fs_connected + real_es = setdiff(edges(s_f), dummy_edges) + new_opsum = OpSum() + for term in H + if length(sites(term)) == 1 && !iszero(first(term.args)) + new_opsum += (1.0 / no_forests) * term + elseif length(sites(term)) == 2 && !iszero(first(term.args)) + e = NamedEdge(first(sites(term)) => last(sites(term))) + if (e ∈ real_es || reverse(e) ∈ real_es) + new_opsum += term + end + end + end + tno = truncate(ttn(new_opsum, s_f); cutoff) + tno = ITensorNetwork(tno) + if insert_dummy_inds + tno = insert_linkinds(tno, setdiff(edges(s), edges(tno))) + end + push!(tnos, tno) + end + + return tnos +end \ No newline at end of file diff --git a/src/beliefpropagationdmrg/utils.jl b/src/beliefpropagationdmrg/utils.jl new file mode 100644 index 00000000..65fbd310 --- /dev/null +++ b/src/beliefpropagationdmrg/utils.jl @@ -0,0 +1,105 @@ +using ITensors: siteinds, Op, prime, OpSum, apply +using Graphs: AbstractGraph, SimpleGraph, edges, vertices, is_tree, connected_components +using NamedGraphs: NamedGraph, NamedEdge, NamedGraphs, rename_vertices +using NamedGraphs.NamedGraphGenerators: named_grid, named_hexagonal_lattice_graph +using NamedGraphs.GraphsExtensions: decorate_graph_edges, forest_cover, add_edges, rem_edges, add_vertices, rem_vertices, disjoint_union, subgraph, src, dst +using NamedGraphs.PartitionedGraphs: PartitionVertex, partitionedge, unpartitioned_graph +using ITensorNetworks: BeliefPropagationCache, AbstractITensorNetwork, AbstractFormNetwork, IndsNetwork, ITensorNetwork, insert_linkinds, ttn, union_all_inds, + neighbor_vertices, environment, messages, update_factor, message, partitioned_tensornetwork, bra_vertex, ket_vertex, operator_vertex, default_cache_update_kwargs, + dual_index_map +using DataGraphs: underlying_graph +using ITensorNetworks.ModelHamiltonians: heisenberg +using ITensors: ITensor, noprime, dag, noncommonind, commonind, replaceind, dim, noncommoninds, delta, replaceinds +using ITensors.NDTensors: denseblocks + +function heavy_hex_lattice_graph(n::Int64, m::Int64) + """Create heavy-hex lattice geometry""" + g = named_hexagonal_lattice_graph(n, m) + g = decorate_graph_edges(g) + + vertex_rename = Dictionary() + for (i,v) in enumerate(vertices(g)) + set!(vertex_rename, v, (i,)) + end + g = rename_vertices(v -> vertex_rename[v], g) + + return g +end + +function BP_apply(o::ITensor, ψ::AbstractITensorNetwork, bpc::BeliefPropagationCache; apply_kwargs...) + bpc = copy(bpc) + ψ = copy(ψ) + vs = neighbor_vertices(ψ, o) + envs = environment(bpc, PartitionVertex.(vs)) + singular_values! = Ref(ITensor()) + ψ = noprime(apply(o, ψ; envs, singular_values!, normalize=true, apply_kwargs...)) + ψdag = prime(dag(ψ); sites=[]) + if length(vs) == 2 + v1, v2 = vs + pe = partitionedge(bpc, (v1, "bra") => (v2, "bra")) + mts = messages(bpc) + ind1, ind2 = noncommonind(singular_values![], ψ[v1]), commonind(singular_values![], ψ[v1]) + singular_values![] = denseblocks(replaceind(singular_values![], ind1, ind2')) + set!(mts, pe, ITensor[singular_values![]]) + set!(mts, reverse(pe), ITensor[singular_values![]]) + end + for v in vs + bpc = update_factor(bpc, (v, "ket"), ψ[v]) + bpc = update_factor(bpc, (v, "bra"), ψdag[v]) + end + return ψ, bpc +end + +function smallest_eigvalue(A::AbstractITensorNetwork) + out = reduce(*, [A[v] for v in vertices(A)]) + out = out * combiner(inds(out; plev = 0)) *combiner(inds(out; plev = 1)) + out = array(out) + return minimum(real.(eigvals(out))) +end + +function bp_renormalize(ψ::ITensorNetwork, ψIψ::BeliefPropagationCache, ψOψs::Vector) + + qf = unpartitioned_graph(partitioned_tensornetwork( ψIψ)) + L = length(vertices(ψ)) + Z = scalar(ψIψ) + Zval = Z^(-1/(2*L)) + ψ = copy(ψ) + for v in vertices(ψ) + form_bra_v, form_ket_v = bra_vertex(qf, v), ket_vertex(qf, v) + state = ψ[v] * Zval + state_dag = copy(state) + state_dag = replaceinds(dag(state_dag), inds(state_dag), dual_index_map(qf).(inds(state_dag))) + ψ[v] = state + ψIψ = update_factor(ψIψ, form_ket_v, state) + ψIψ = update_factor(ψIψ, form_bra_v, state_dag) + ψOψs = update_factor.(ψOψs, (form_bra_v, ), (state, )) + ψOψs = update_factor.(ψOψs, (form_ket_v, ), (state_dag, )) + end + + return ψ, ψIψ, ψOψs +end + +function replace_v(bpc::BeliefPropagationCache, v) + bpc = copy(bpc) + qf = unpartitioned_graph(partitioned_tensornetwork(bpc)) + v_ket, v_bra, v_op = bra_vertex(qf, v), ket_vertex(qf, v), operator_vertex(qf, v) + s, sp = commonind(qf[v_op], qf[v_bra]), commonind(qf[v_op], qf[v_ket]) + d = dim(s) + remaining_inds = intersect(noncommoninds(qf[v_op], qf[v_bra]), noncommoninds(qf[v_op], qf[v_ket])) + bpc = update_factor(bpc, v_ket, ITensor(sqrt(1.0 / d), inds(qf[v_ket]))) + bpc = update_factor(bpc, v_bra, ITensor(sqrt(1.0 / d), inds(qf[v_bra]))) + bpc = update_factor(bpc, v_op, delta(s,sp)*ITensor(1.0, remaining_inds)) + return bpc +end + +function local_op(bpc::BeliefPropagationCache, v) + qf = unpartitioned_graph(partitioned_tensornetwork(bpc)) + v_op = operator_vertex(qf, v) + return copy(qf[v_op]) +end + + +function get_local_term(bpc::BeliefPropagationCache, v) + qf = copy(unpartitioned_graph(partitioned_tensornetwork(bpc))) + return qf[(v, "bra")]*qf[(v, "ket")]*qf[(v, "operator")] +end \ No newline at end of file diff --git a/src/caches/beliefpropagationcache.jl b/src/caches/beliefpropagationcache.jl index fd577ce4..f280f576 100644 --- a/src/caches/beliefpropagationcache.jl +++ b/src/caches/beliefpropagationcache.jl @@ -13,15 +13,15 @@ using NamedGraphs.PartitionedGraphs: unpartitioned_graph using SimpleTraits: SimpleTraits, Not, @traitfn -#default_message(inds_e) = ITensor[denseblocks(delta(i)) for i in inds_e] -default_message(inds_e) = ITensor[denseblocks(delta(inds_e))] +default_message(inds_e) = ITensor[denseblocks(delta(i)) for i in inds_e] +#default_message(inds_e) = ITensor[denseblocks(delta(inds_e))] default_messages(ptn::PartitionedGraph) = Dictionary() default_message_norm(m::ITensor) = norm(m) -function default_message_update(contract_list::Vector{ITensor}; kwargs...) +function default_message_update(contract_list::Vector{ITensor}; normalize = true, kwargs...) sequence = optimal_contraction_sequence(contract_list) updated_messages = contract(contract_list; sequence, kwargs...) message_norm = norm(updated_messages) - if !iszero(message_norm) + if !iszero(message_norm) && normalize updated_messages /= message_norm end return ITensor[updated_messages] @@ -330,3 +330,35 @@ end function scalar_factors_quotient(bp_cache::BeliefPropagationCache) return vertex_scalars(bp_cache), edge_scalars(bp_cache) end + +function ITensors.scalar(bp_cache::BeliefPropagationCache) + v_scalars, e_scalars = vertex_scalars(bp_cache), edge_scalars(bp_cache) + return prod(v_scalars) / prod(e_scalars) +end + +function rescale_messages(bp_cache::BeliefPropagationCache, scalar::Float64, pv::PartitionVertex; scale_all = true) + bp_cache = copy(bp_cache) + pedges = boundary_partitionedges(bp_cache, PartitionVertex[pv]; dir=:in) + no_ms = length(pedges) + mts = messages(bp_cache) + if scale_all + scale_neg = scalar < 0 ? true : false + c = abs(scalar) ^ (1/no_ms) + + for pe in pedges + mt = only(mts[pe]) + mt *= (c / sum(mt)) + set!(mts, pe, ITensor[mt]) + end + + if scale_neg + mt = only(mts[first(pedges)]) + mt *= -1 + set!(mts, first(pedges), ITensor[mt]) + end + end + return bp_cache +end + + + diff --git a/src/solvers/local_solvers/eigsolve.jl b/src/solvers/local_solvers/eigsolve.jl index a5d5e96d..5b083ee9 100644 --- a/src/solvers/local_solvers/eigsolve.jl +++ b/src/solvers/local_solvers/eigsolve.jl @@ -31,27 +31,4 @@ function eigsolve_updater( eager, ) return vecs[1], (; info, eigvals=vals) -end - -function bp_eigsolve_updater(init::ITensor, ∂ψAψ_bpc_∂rs::Vector, sqrt_mts, inv_sqrt_mts; kwargs...) - - #TODO: Put inv_sqrt_mts onto ∂ψAψ_bpc_∂r beforehand. Need to do this in an efficient way without - #precontracting ∂ψAψ_bpc_∂r - function get_new_state(∂ψAψ_bpc_∂rs::Vector, inv_sqrt_mts, state::ITensor; sequences = ["automatic" for i in length(∂ψAψ_bpc_∂rs)]) - state = noprime(contract([state; inv_sqrt_mts])) - states = ITensor[dag(noprime(contract([copy(state); ∂ψAψ_bpc_∂r]; sequence = sequences[i]))) for (i, ∂ψAψ_bpc_∂r) in enumerate(∂ψAψ_bpc_∂rs)] - state = reduce(+, states) - return noprime(contract([state; (inv_sqrt_mts)])) - end - - init = noprime(contract([init; sqrt_mts])) - sequences = [optimal_contraction_sequence([init; ∂ψAψ_bpc_∂r]) for ∂ψAψ_bpc_∂r in ∂ψAψ_bpc_∂rs] - get_new_state_partial = partial(get_new_state, ∂ψAψ_bpc_∂rs, inv_sqrt_mts; sequences) - howmany = 1 - - vals, vecs, info = eigsolve(get_new_state_partial,init,howmany,:SR; ishermitian = true, kwargs...) - state = first(vecs) - state = noprime(contract([state; inv_sqrt_mts])) - - return state, (; info, eigvals=vals) end \ No newline at end of file From 8d780a83e1370b013748d47b348d34c85046ecec Mon Sep 17 00:00:00 2001 From: Joey Date: Fri, 7 Jun 2024 17:47:04 -0400 Subject: [PATCH 09/27] Refactor code --- examples/dmrg.jl | 72 +++++++++++++++++ examples/utils.jl | 44 +++++++++++ src/beliefpropagationdmrg/bp_dmrg.jl | 14 ++-- src/beliefpropagationdmrg/bp_extracter.jl | 20 ++--- src/beliefpropagationdmrg/bp_inserter.jl | 94 ++++++++++------------- src/beliefpropagationdmrg/bp_updater.jl | 31 ++++---- src/beliefpropagationdmrg/main.jl | 12 ++- src/beliefpropagationdmrg/utils.jl | 22 ------ src/caches/beliefpropagationcache.jl | 18 ----- 9 files changed, 196 insertions(+), 131 deletions(-) create mode 100644 examples/dmrg.jl create mode 100644 examples/utils.jl diff --git a/examples/dmrg.jl b/examples/dmrg.jl new file mode 100644 index 00000000..d949368a --- /dev/null +++ b/examples/dmrg.jl @@ -0,0 +1,72 @@ +using DataGraphs: edge_data, vertex_data +using Dictionaries: Dictionary +using Graphs: nv, vertices +using ITensorMPS: ITensorMPS +using ITensorNetworks: + ITensorNetworks, + OpSum, + ttn, + apply, + dmrg, + inner, + mpo, + random_mps, + random_ttn, + linkdims, + siteinds, + random_tensornetwork +using ITensorNetworks.ITensorsExtensions: replace_vertices +using ITensorNetworks.ModelHamiltonians: ModelHamiltonians +using ITensors: ITensors, expect +using KrylovKit: eigsolve +using NamedGraphs.NamedGraphGenerators: named_comb_tree +using Observers: observer +using NamedGraphs.NamedGraphGenerators: named_grid + +using NPZ + +function main() + + N = 24 + g = heavy_hex_lattice_graph(3,3) + N = length(vertices(g)) + g_mps = named_grid((N,1)) + g_mps = rename_vertices(v -> (first(v), ), g_mps) + h, hl = 0.8, 0.2 + J = -1 + s = siteinds("S=1/2",g_mps) + chi = 10 + pbc = false + + os = OpSum() + for e in edges(g) + os += J, "Sz", src(e),"Sz",dst(e) + end + for v in vertices(g) + os += h, "Sx", v + os += hl, "Sz", v + end + + H = ttn(os, s) + + psi0 = ttn(random_tensornetwork(s; link_space = chi)) + sweep(; which_sweep, kw...) = which_sweep + energy(; eigvals, kw...) = eigvals[1] + region(; which_region_update, sweep_plan, kw...) = first(sweep_plan[which_region_update]) + region_observer! = observer(sweep, region, energy) + + e, psifinal = dmrg( + H, psi0; nsweeps = 5, maxdim = chi, cutoff= 1e-14, nsites = 1, region_observer! + ) + energies = region_observer!.energy + + final_mags = expect(psifinal, "Z") + file_name = "/Users/jtindall/Documents/Data/DMRG/HEAVYHEXISINGL$(N)h$(h)hl$(hl)chi$(chi)" + if pbc + file_name *= "PBC" + end + npzwrite(file_name*".npz", energies = energies, final_mags = final_mags) + +end + +main() \ No newline at end of file diff --git a/examples/utils.jl b/examples/utils.jl new file mode 100644 index 00000000..e2156e30 --- /dev/null +++ b/examples/utils.jl @@ -0,0 +1,44 @@ +function BP_apply(o::ITensor, ψ::AbstractITensorNetwork, bpc::BeliefPropagationCache; apply_kwargs...) + bpc = copy(bpc) + ψ = copy(ψ) + vs = neighbor_vertices(ψ, o) + envs = environment(bpc, PartitionVertex.(vs)) + singular_values! = Ref(ITensor()) + ψ = noprime(apply(o, ψ; envs, singular_values!, normalize=true, apply_kwargs...)) + ψdag = prime(dag(ψ); sites=[]) + if length(vs) == 2 + v1, v2 = vs + pe = partitionedge(bpc, (v1, "bra") => (v2, "bra")) + mts = messages(bpc) + ind1, ind2 = noncommonind(singular_values![], ψ[v1]), commonind(singular_values![], ψ[v1]) + singular_values![] = denseblocks(replaceind(singular_values![], ind1, ind2')) + set!(mts, pe, ITensor[singular_values![]]) + set!(mts, reverse(pe), ITensor[singular_values![]]) + end + for v in vs + bpc = update_factor(bpc, (v, "ket"), ψ[v]) + bpc = update_factor(bpc, (v, "bra"), ψdag[v]) + end + return ψ, bpc +end + +function smallest_eigvalue(A::AbstractITensorNetwork) + out = reduce(*, [A[v] for v in vertices(A)]) + out = out * combiner(inds(out; plev = 0)) *combiner(inds(out; plev = 1)) + out = array(out) + return minimum(real.(eigvals(out))) +end + +function heavy_hex_lattice_graph(n::Int64, m::Int64) + """Create heavy-hex lattice geometry""" + g = named_hexagonal_lattice_graph(n, m) + g = decorate_graph_edges(g) + + vertex_rename = Dictionary() + for (i,v) in enumerate(vertices(g)) + set!(vertex_rename, v, (i,)) + end + g = rename_vertices(v -> vertex_rename[v], g) + + return g +end \ No newline at end of file diff --git a/src/beliefpropagationdmrg/bp_dmrg.jl b/src/beliefpropagationdmrg/bp_dmrg.jl index f3b5168b..5a337a1c 100644 --- a/src/beliefpropagationdmrg/bp_dmrg.jl +++ b/src/beliefpropagationdmrg/bp_dmrg.jl @@ -10,8 +10,7 @@ include("bp_updater.jl") default_bp_update_kwargs(ψ::ITensorNetwork) = is_tree(ψ) ? (;) : (; maxiter = 25, tol = 1e-7) - -function build_update_caches(operators::Vector{ITensorNetwork}, ψ_init::ITensorNetwork; cache_update_kwargs = default_bp_update_kwargs(ψ_init)) +function initialize_caches(ψ_init::ITensorNetwork, operators::Vector{ITensorNetwork}; cache_update_kwargs = default_bp_update_kwargs(ψ_init)) ψ = copy(ψ_init) ψIψ = QuadraticFormNetwork(ψ) ψIψ_bpc = BeliefPropagationCache(ψIψ) @@ -31,9 +30,10 @@ end alt_vertex_order(ψ_init) = [[v] for v in collect(vertices(ψ_init))] -function bp_dmrg(operators::Vector{ITensorNetwork}, ψ_init::ITensorNetwork; no_sweeps = 1, bp_update_kwargs = default_bp_update_kwargs( ψ_init), +function bp_dmrg(ψ_init::ITensorNetwork, operators::Vector{ITensorNetwork}; no_sweeps = 1, bp_update_kwargs = default_bp_update_kwargs(ψ_init), vertex_order_func = default_vertex_order) - state, ψIψ_bpc, ψOψ_bpcs = build_update_caches(operators, ψ_init) + + state, ψIψ_bpc, ψOψ_bpcs = initialize_caches(ψ_init, operators) regions = vertex_order_func(state) energy = sum(scalar.(ψOψ_bpcs)) / scalar(ψIψ_bpc) @@ -44,8 +44,6 @@ function bp_dmrg(operators::Vector{ITensorNetwork}, ψ_init::ITensorNetwork; no_ println("Beginning sweep $i") for region in regions println("Updating vertex $region") - - state, ψIψ_bpc, ψOψ_bpcs = bp_renormalize(state, ψIψ_bpc, ψOψ_bpcs) v = only(region) form_op_v = (v, "operator") @@ -57,14 +55,14 @@ function bp_dmrg(operators::Vector{ITensorNetwork}, ψ_init::ITensorNetwork; no_ pv = PartitionVertex(v) ψOψ_bpcs = BeliefPropagationCache[rescale_messages(ψOψ_bpc, ψOψ_bpc_scalar, pv) for (ψOψ_bpc, ψOψ_bpc_scalar) in zip(ψOψ_bpcs, ψOψ_bpcs_scalars)] ψOψ_bpcs = BeliefPropagationCache[update_factor(ψOψ_bpc, form_op_v, local_op) for (ψOψ_bpc, local_op) in zip(ψOψ_bpcs, local_ops)] + local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts = bp_extracter(state, ψOψ_bpcs, ψIψ_bpc, region) #Do an eigsolve local_state, _ = bp_eigsolve_updater(local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts) - state, ψOψ_bpcs, ψIψ_bpc, _, _ = bp_inserter_one_site(state, ψOψ_bpcs, ψIψ_bpc, local_state, region; cache_update_kwargs =bp_update_kwargs) + state, ψOψ_bpcs, ψIψ_bpc = bp_inserter(state, ψOψ_bpcs, ψIψ_bpc, local_state, region; cache_update_kwargs =bp_update_kwargs) - ψOψ_bpcs = update.(ψOψ_bpcs; bp_update_kwargs...) energy = sum(scalar.(ψOψ_bpcs)) / scalar(ψIψ_bpc) println("Current energy is $energy") append!(energies, energy) diff --git a/src/beliefpropagationdmrg/bp_extracter.jl b/src/beliefpropagationdmrg/bp_extracter.jl index a56b7638..5a3f0c08 100644 --- a/src/beliefpropagationdmrg/bp_extracter.jl +++ b/src/beliefpropagationdmrg/bp_extracter.jl @@ -1,19 +1,21 @@ using ITensors: scalartype -using ITensorNetworks: ket_vertices, bra_vertices +using ITensorNetworks: ket_vertices, bra_vertices, tensornetwork using ITensorNetworks.ITensorsExtensions: map_eigvals -function bp_extracter(ψ::AbstractITensorNetwork, ψAψ_bpcs::Vector{<:BeliefPropagationCache}, ψIψ_bpc::BeliefPropagationCache, region; - regularization = 10*eps(scalartype(ψ))) - form_network = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) +function bp_extracter(ψ::AbstractITensorNetwork, ψOψ_bpcs::Vector{<:BeliefPropagationCache}, ψIψ_bpc::BeliefPropagationCache, region; + regularization = 10*eps(scalartype(ψ)), ishermitian = true) + + form_network = tensornetwork(ψIψ_bpc) form_ket_vertices, form_bra_vertices = ket_vertices(form_network, region), bra_vertices(form_network, region) - ∂ψAψ_bpc_∂rs = [environment(ψAψ_bpc, [form_ket_vertices; form_bra_vertices]) for ψAψ_bpc in ψAψ_bpcs] + + ∂ψOψ_bpc_∂rs = environment.(ψOψ_bpcs, ([form_ket_vertices; form_bra_vertices], )) state = prod(ψ[v] for v in region) messages = environment(ψIψ_bpc, partitionvertices(ψIψ_bpc, form_ket_vertices)) f_sqrt = sqrt ∘ (x -> x + regularization) f_inv_sqrt = inv ∘ sqrt ∘ (x -> x + regularization) - sqrt_mts = [map_eigvals(f_sqrt, mt, inds(mt)[1], inds(mt)[2]; ishermitian=true) for mt in messages] - inv_sqrt_mts = [map_eigvals(f_inv_sqrt, mt, inds(mt)[1], inds(mt)[2]; ishermitian=true) for mt in messages] - - return state, ∂ψAψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts + sqrt_mts = map_eigvals.((f_sqrt, ), messages, first.(inds.(messages)), last.(inds.(messages)); ishermitian) + inv_sqrt_mts = map_eigvals.((f_inv_sqrt, ), messages, first.(inds.(messages)), last.(inds.(messages)); ishermitian) + + return state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts end \ No newline at end of file diff --git a/src/beliefpropagationdmrg/bp_inserter.jl b/src/beliefpropagationdmrg/bp_inserter.jl index 0b7cb1c4..0a7986c3 100644 --- a/src/beliefpropagationdmrg/bp_inserter.jl +++ b/src/beliefpropagationdmrg/bp_inserter.jl @@ -1,63 +1,49 @@ -# function bp_inserter(ψ::AbstractITensorNetwork, ψAψ_bpcs::Vector{<:BeliefPropagationCache}, -# ψIψ_bpc::BeliefPropagationCache, state::ITensor, region; cache_update_kwargs = (;), kwargs...) - -# spec = nothing - -# form_network = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) -# if length(region) == 1 -# states = [state] -# elseif length(region) == 2 -# v1, v2 = region[1], region[2] -# e = edgetype(ψ)(v1, v2) -# pe = partitionedge(ψIψ_bpc, ket_vertex(form_network, v1) => bra_vertex(form_network, v2)) -# stateᵥ₁, stateᵥ₂, spec = factorize_svd(state,uniqueinds(ψ[v1], ψ[v2]); ortho="none", tags=edge_tag(e),kwargs...) -# states = noprime.([stateᵥ₁, stateᵥ₂]) -# ψIψ_bpc = reset_messages(ψIψ_bpc, [pe, reverse(pe)]) -# ψAψ_bpcs = BeliefPropagationCache[reset_messages(ψAψ_bpc, [pe, reverse(pe)]) for ψAψ_bpc in ψAψ_bpcs] -# #TODO: Insert spec into the message tensor guess here?! -# end - -# for (i, v) in enumerate(region) -# state = states[i] -# state_dag = copy(state) -# form_bra_v, form_ket_v = bra_vertex(form_network, v), ket_vertex(form_network, v) -# ψ[v] =state -# state_dag = replaceinds(dag(state_dag), inds(state_dag), dual_index_map(form_network).(inds(state_dag))) -# ψAψ_bpcs = BeliefPropagationCache[update_factor(ψAψ_bpc, form_ket_v, state) for ψAψ_bpc in ψAψ_bpcs] -# ψAψ_bpcs = BeliefPropagationCache[update_factor(ψAψ_bpc, form_bra_v, state_dag) for ψAψ_bpc in ψAψ_bpcs] -# ψIψ_bpc = update_factor(ψIψ_bpc, form_ket_v, state) -# ψIψ_bpc = update_factor(ψIψ_bpc, form_bra_v, state_dag) -# end - - -# ψAψ_bpcs = BeliefPropagationCache[update(ψAψ_bpc; cache_update_kwargs...) for ψAψ_bpc in ψAψ_bpcs] - -# ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) - -# return ψ, ψAψ_bpcs, ψIψ_bpc, spec, (; eigvals=[0.0]) -# end +using ITensorNetworks: update_factors -function bp_inserter_one_site(ψ::AbstractITensorNetwork, ψAψ_bpcs::Vector{<:BeliefPropagationCache}, - ψIψ_bpc::BeliefPropagationCache, state::ITensor, region; cache_update_kwargs = (;), kwargs...) +function normalize_state_update_caches(ψ::ITensorNetwork, ψIψ::BeliefPropagationCache, ψOψs::Vector{<:BeliefPropagationCache}) + qf = tensornetwork(ψIψ) + L = length(vertices(ψ)) + cur_norm = scalar(ψIψ) + rescale_coeff = cur_norm^(-1/(2*L)) + ψ = copy(ψ) + for v in vertices(ψ) + form_bra_v, form_ket_v = bra_vertex(qf, v), ket_vertex(qf, v) + state = ψ[v] * rescale_coeff + ψ[v] = state + state_dag = copy(ψ[v]) + state_dag = replaceinds(dag(state_dag), inds(state_dag), dual_index_map(qf).(inds(state_dag))) + vertices_states = Dictionary([form_ket_v, form_bra_v], [state, state_dag]) + ψIψ = update_factors(ψIψ, vertices_states) + ψOψs = update_factors.(ψOψs, (vertices_states, )) + end - spec = nothing + return ψ, ψIψ, ψOψs +end +#TODO: Add support for nsites = 2 +function bp_inserter(ψ::AbstractITensorNetwork, ψOψ_bpcs::Vector{<:BeliefPropagationCache}, + ψIψ_bpc::BeliefPropagationCache, state::ITensor, region; normalize_state = true, cache_update_kwargs, nsites::Int64 = 1, kwargs...) + + @assert nsites == 1 ψ = copy(ψ) - form_network = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) - @assert length(region) == 1 - states = [state] + form_network = tensornetwork(ψIψ_bpc) + states = ITensor[state] - for (i, v) in enumerate(region) - state = states[i] - state_dag = copy(state) - form_bra_v, form_op_v, form_ket_v = bra_vertex(form_network, v), operator_vertex(form_network, v), ket_vertex(form_network, v) - ψ[v] =state + for (state, v) in zip(states, region) + ψ[v] = state + state_dag = copy(ψ[v]) state_dag = replaceinds(dag(state_dag), inds(state_dag), dual_index_map(form_network).(inds(state_dag))) - ψAψ_bpcs = BeliefPropagationCache[update_factor(ψAψ_bpc, form_ket_v, state) for ψAψ_bpc in ψAψ_bpcs] - ψAψ_bpcs = BeliefPropagationCache[update_factor(ψAψ_bpc, form_bra_v, state_dag) for ψAψ_bpc in ψAψ_bpcs] - ψIψ_bpc = update_factor(ψIψ_bpc, form_ket_v, state) - ψIψ_bpc = update_factor(ψIψ_bpc, form_bra_v, state_dag) + form_bra_v, form_op_v, form_ket_v = bra_vertex(form_network, v), operator_vertex(form_network, v), ket_vertex(form_network, v) + vertices_states = Dictionary([form_ket_v, form_bra_v], [state, state_dag]) + ψOψ_bpcs = update_factors.(ψOψ_bpcs, (vertices_states,)) + ψIψ_bpc = update_factors(ψIψ_bpc, vertices_states) + end + + ψOψ_bpcs = update.(ψOψ_bpcs; cache_update_kwargs...) + ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) + if normalize_state + ψ, ψIψ_bpc, ψOψ_bpcs = normalize_state_update_caches(ψ, ψIψ_bpc, ψOψ_bpcs) end - return ψ, ψAψ_bpcs, ψIψ_bpc, spec, (; eigvals=[0.0]) + return ψ, ψOψ_bpcs, ψIψ_bpc end \ No newline at end of file diff --git a/src/beliefpropagationdmrg/bp_updater.jl b/src/beliefpropagationdmrg/bp_updater.jl index 0263f8c5..9145bdbf 100644 --- a/src/beliefpropagationdmrg/bp_updater.jl +++ b/src/beliefpropagationdmrg/bp_updater.jl @@ -2,27 +2,26 @@ using ITensors: contract using ITensors.ContractionSequenceOptimization: optimal_contraction_sequence using KrylovKit: eigsolve -default_krylov_kwargs() = (; tol = 1e-14, krylovdim = 3, maxiter = 2, verbosity = 0, eager = false) +default_krylov_kwargs() = (; tol = 1e-14, krylovdim = 3, maxiter = 1, verbosity = 0, eager = false, ishermitian = true) -function bp_eigsolve_updater(init::ITensor, ∂ψAψ_bpc_∂rs::Vector, sqrt_mts, inv_sqrt_mts; krylov_kwargs = default_krylov_kwargs()) +#TODO: Put inv_sqrt_mts onto ∂ψOψ_bpc_∂r beforehand. Need to do this in an efficient way without +#precontracting ∂ψOψ_bpc_∂r and getting the index logic too messy +function get_new_state(∂ψOψ_bpc_∂rs::Vector, inv_sqrt_mts, state::ITensor; sequences = ["automatic" for i in length(∂ψOψ_bpc_∂rs)]) + state = noprime(contract([state; inv_sqrt_mts])) + states = ITensor[dag(noprime(contract([copy(state); ∂ψOψ_bpc_∂r]; sequence))) for (∂ψOψ_bpc_∂r, sequence) in zip(∂ψOψ_bpc_∂rs, sequences)] + state = reduce(+, states) + return noprime(contract([state; (inv_sqrt_mts)])) +end - #TODO: Put inv_sqrt_mts onto ∂ψAψ_bpc_∂r beforehand. Need to do this in an efficient way without - #precontracting ∂ψAψ_bpc_∂r - function get_new_state(∂ψAψ_bpc_∂rs::Vector, inv_sqrt_mts, state::ITensor; sequences = ["automatic" for i in length(∂ψAψ_bpc_∂rs)]) - state = noprime(contract([state; inv_sqrt_mts])) - states = ITensor[dag(noprime(contract([copy(state); ∂ψAψ_bpc_∂r]; sequence = sequences[i]))) for (i, ∂ψAψ_bpc_∂r) in enumerate(∂ψAψ_bpc_∂rs)] - state = reduce(+, states) - return noprime(contract([state; (inv_sqrt_mts)])) - end +function bp_eigsolve_updater(init::ITensor, ∂ψOψ_bpc_∂rs::Vector, sqrt_mts, inv_sqrt_mts; krylov_kwargs = default_krylov_kwargs()) init = noprime(contract([init; sqrt_mts])) - sequences = [optimal_contraction_sequence([init; ∂ψAψ_bpc_∂r]) for ∂ψAψ_bpc_∂r in ∂ψAψ_bpc_∂rs] - get_new_state_ = state -> get_new_state(∂ψAψ_bpc_∂rs, inv_sqrt_mts, state; sequences) + sequences = [optimal_contraction_sequence([init; ∂ψOψ_bpc_∂r]) for ∂ψOψ_bpc_∂r in ∂ψOψ_bpc_∂rs] + get_new_state_ = state -> get_new_state(∂ψOψ_bpc_∂rs, inv_sqrt_mts, state; sequences) howmany = 1 - vals, vecs, info = eigsolve(get_new_state_,init,howmany,:SR; ishermitian = true, krylov_kwargs...) - state = first(vecs) - state = noprime(contract([state; inv_sqrt_mts])) + vals, vecs, info = eigsolve(get_new_state_,init,howmany,:SR; krylov_kwargs...) + state = noprime(contract([first(vecs); inv_sqrt_mts])) return state, (; info, eigvals=vals) - end \ No newline at end of file +end \ No newline at end of file diff --git a/src/beliefpropagationdmrg/main.jl b/src/beliefpropagationdmrg/main.jl index 9dc691c7..d3b8ed0e 100644 --- a/src/beliefpropagationdmrg/main.jl +++ b/src/beliefpropagationdmrg/main.jl @@ -2,14 +2,18 @@ using ITensorNetworks: random_tensornetwork using NamedGraphs.NamedGraphGenerators: named_comb_tree using NPZ using ITensors: expect +using Random include("tensornetworkoperators.jl") include("bp_dmrg.jl") +Random.seed!(1234) function main() - L = 24 - g = named_grid((L,1); periodic = true) + #L = 24 + #g = named_grid((L,1); periodic = true) + g = heavy_hex_lattice_graph(3,3) + L = length(vertices(g)) h,hl = 0.8, 0.2 s = siteinds("S=1/2", g) χ = 2 @@ -20,9 +24,9 @@ function main() tnos = opsum_to_tno(s, H) tno = reduce(+, tnos) - ψfinal, energies = bp_dmrg(tnos, ψ0; no_sweeps = 10, vertex_order_func = alt_vertex_order) + ψfinal, energies = bp_dmrg(ψ0, tnos; no_sweeps = 2, vertex_order_func = alt_vertex_order) final_mags = expect(ψfinal, "Z", ; alg = "bp") - npzwrite("/Users/jtindall/Documents/Data/BPDMRG/ISINGL$(L)h$(h)hl$(hl)chi$(χ).npz", energies = energies, final_mags = final_mags) + npzwrite("/Users/jtindall/Documents/Data/BPDMRG/HEAVYHEXISINGL$(L)h$(h)hl$(hl)chi$(χ).npz", energies = energies, final_mags = final_mags) end diff --git a/src/beliefpropagationdmrg/utils.jl b/src/beliefpropagationdmrg/utils.jl index 65fbd310..8761d921 100644 --- a/src/beliefpropagationdmrg/utils.jl +++ b/src/beliefpropagationdmrg/utils.jl @@ -57,28 +57,6 @@ function smallest_eigvalue(A::AbstractITensorNetwork) return minimum(real.(eigvals(out))) end -function bp_renormalize(ψ::ITensorNetwork, ψIψ::BeliefPropagationCache, ψOψs::Vector) - - qf = unpartitioned_graph(partitioned_tensornetwork( ψIψ)) - L = length(vertices(ψ)) - Z = scalar(ψIψ) - Zval = Z^(-1/(2*L)) - ψ = copy(ψ) - for v in vertices(ψ) - form_bra_v, form_ket_v = bra_vertex(qf, v), ket_vertex(qf, v) - state = ψ[v] * Zval - state_dag = copy(state) - state_dag = replaceinds(dag(state_dag), inds(state_dag), dual_index_map(qf).(inds(state_dag))) - ψ[v] = state - ψIψ = update_factor(ψIψ, form_ket_v, state) - ψIψ = update_factor(ψIψ, form_bra_v, state_dag) - ψOψs = update_factor.(ψOψs, (form_bra_v, ), (state, )) - ψOψs = update_factor.(ψOψs, (form_ket_v, ), (state_dag, )) - end - - return ψ, ψIψ, ψOψs -end - function replace_v(bpc::BeliefPropagationCache, v) bpc = copy(bpc) qf = unpartitioned_graph(partitioned_tensornetwork(bpc)) diff --git a/src/caches/beliefpropagationcache.jl b/src/caches/beliefpropagationcache.jl index f280f576..cb074a98 100644 --- a/src/caches/beliefpropagationcache.jl +++ b/src/caches/beliefpropagationcache.jl @@ -84,24 +84,6 @@ function tensornetwork(bp_cache::BeliefPropagationCache) return unpartitioned_graph(partitioned_tensornetwork(bp_cache)) end -function reset_messages(bp_cache::BeliefPropagationCache, pes::Vector{<:PartitionEdge}) - new_messages = copy(messages(bp_cache)) - for pe in pes - delete!(new_messages, pe) - end - return BeliefPropagationCache(partitioned_tensornetwork(bp_cache), new_messages, default_message(bp_cache)) -end - -function reset_messages(bp_cache::BeliefPropagationCache) - pedges = vcat(partitionedges(partitioned_tensornetwork(bp_cache)), reverse.(partitionedges(partitioned_tensornetwork(bp_cache)))) - return reset_messages(bp_cache, pedges) -end - -function reset_message(bp_cache::BeliefPropagationCache, pe::PartitionEdge) - return reset_messages(bp_cache, PartitionEdge[pe]) -end - - #Forward from partitioned graph for f in [ :(PartitionedGraphs.partitioned_graph), From e62ae0f82e94a797d5af9b2d087516b66764b898 Mon Sep 17 00:00:00 2001 From: Joey Date: Tue, 11 Jun 2024 14:02:10 -0400 Subject: [PATCH 10/27] Save stuff --- examples/dmrg.jl | 41 ++++--- examples/utils.jl | 26 ++++- src/beliefpropagationdmrg/bp_dmrg.jl | 28 ++--- src/beliefpropagationdmrg/bp_inserter.jl | 1 - src/beliefpropagationdmrg/bp_updater.jl | 6 +- src/beliefpropagationdmrg/graphsextensions.jl | 109 ++++++++++++++++++ src/beliefpropagationdmrg/main.jl | 24 ++-- src/beliefpropagationdmrg/utils.jl | 62 +++------- src/solvers/extract/extract.jl | 15 --- 9 files changed, 203 insertions(+), 109 deletions(-) create mode 100644 src/beliefpropagationdmrg/graphsextensions.jl diff --git a/examples/dmrg.jl b/examples/dmrg.jl index d949368a..3a4d016f 100644 --- a/examples/dmrg.jl +++ b/examples/dmrg.jl @@ -3,6 +3,8 @@ using Dictionaries: Dictionary using Graphs: nv, vertices using ITensorMPS: ITensorMPS using ITensorNetworks: + AbstractITensorNetwork, + BeliefPropagationCache, ITensorNetworks, OpSum, ttn, @@ -14,10 +16,11 @@ using ITensorNetworks: random_ttn, linkdims, siteinds, - random_tensornetwork + random_tensornetwork, + maxlinkdim using ITensorNetworks.ITensorsExtensions: replace_vertices using ITensorNetworks.ModelHamiltonians: ModelHamiltonians -using ITensors: ITensors, expect +using ITensors: ITensors, ITensor, expect using KrylovKit: eigsolve using NamedGraphs.NamedGraphGenerators: named_comb_tree using Observers: observer @@ -25,18 +28,24 @@ using NamedGraphs.NamedGraphGenerators: named_grid using NPZ +include("utils.jl") + +Random.seed!(5634) + function main() - N = 24 - g = heavy_hex_lattice_graph(3,3) + g_str = "HeavyHex" + pbc = true + g = g_str == "Chain" ? named_grid((24,1); periodic = pbc) : heavy_hex_lattice_graph(2,2; periodic = pbc) + g = renamer(g) + save = false + chi =1 + N = length(vertices(g)) - g_mps = named_grid((N,1)) - g_mps = rename_vertices(v -> (first(v), ), g_mps) - h, hl = 0.8, 0.2 - J = -1 + g_mps = renamer(named_grid((N,1))) + h, hl = 1.05, 0.4 + J = 1 s = siteinds("S=1/2",g_mps) - chi = 10 - pbc = false os = OpSum() for e in edges(g) @@ -56,16 +65,20 @@ function main() region_observer! = observer(sweep, region, energy) e, psifinal = dmrg( - H, psi0; nsweeps = 5, maxdim = chi, cutoff= 1e-14, nsites = 1, region_observer! + H, psi0; nsweeps = 20, maxdim = chi, cutoff= 1e-14, nsites = 1, region_observer! ) - energies = region_observer!.energy + energies = (region_observer!.energy) / N + @show last(energies) + @show maxlinkdim(psifinal) final_mags = expect(psifinal, "Z") - file_name = "/Users/jtindall/Documents/Data/DMRG/HEAVYHEXISINGL$(N)h$(h)hl$(hl)chi$(chi)" + file_name = "/Users/jtindall/Files/Data/DMRG/"*g_str*"ISINGL$(N)h$(h)hl$(hl)chi$(chi)" if pbc file_name *= "PBC" end - npzwrite(file_name*".npz", energies = energies, final_mags = final_mags) + if save + npzwrite(file_name*".npz", energies = energies, final_mags = final_mags) + end end diff --git a/examples/utils.jl b/examples/utils.jl index e2156e30..c00a04db 100644 --- a/examples/utils.jl +++ b/examples/utils.jl @@ -1,3 +1,18 @@ +using ITensors: siteinds, Op, prime, OpSum, apply +using Graphs: AbstractGraph, SimpleGraph, edges, vertices, is_tree, connected_components +using NamedGraphs: NamedGraph, NamedEdge, NamedGraphs, rename_vertices +using NamedGraphs.NamedGraphGenerators: named_grid, named_hexagonal_lattice_graph +using NamedGraphs.GraphsExtensions: decorate_graph_edges, forest_cover, add_edges, rem_edges, add_vertices, rem_vertices, disjoint_union, subgraph, src, dst +using NamedGraphs.PartitionedGraphs: PartitionVertex, partitionedge, unpartitioned_graph +using ITensorNetworks: BeliefPropagationCache, AbstractITensorNetwork, AbstractFormNetwork, IndsNetwork, ITensorNetwork, insert_linkinds, ttn, union_all_inds, + neighbor_vertices, environment, messages, update_factor, message, partitioned_tensornetwork, bra_vertex, ket_vertex, operator_vertex, default_cache_update_kwargs, + dual_index_map +using DataGraphs: underlying_graph +using ITensorNetworks.ModelHamiltonians: heisenberg +using ITensors: ITensor, noprime, dag, noncommonind, commonind, replaceind, dim, noncommoninds, delta, replaceinds +using ITensors.NDTensors: denseblocks +using Dictionaries: set! + function BP_apply(o::ITensor, ψ::AbstractITensorNetwork, bpc::BeliefPropagationCache; apply_kwargs...) bpc = copy(bpc) ψ = copy(ψ) @@ -29,16 +44,17 @@ function smallest_eigvalue(A::AbstractITensorNetwork) return minimum(real.(eigvals(out))) end -function heavy_hex_lattice_graph(n::Int64, m::Int64) +function heavy_hex_lattice_graph(n::Int64, m::Int64; periodic) """Create heavy-hex lattice geometry""" - g = named_hexagonal_lattice_graph(n, m) + g = named_hexagonal_lattice_graph(n, m; periodic) g = decorate_graph_edges(g) + return g +end +function renamer(g) vertex_rename = Dictionary() for (i,v) in enumerate(vertices(g)) set!(vertex_rename, v, (i,)) end - g = rename_vertices(v -> vertex_rename[v], g) - - return g + return rename_vertices(v -> vertex_rename[v], g) end \ No newline at end of file diff --git a/src/beliefpropagationdmrg/bp_dmrg.jl b/src/beliefpropagationdmrg/bp_dmrg.jl index 5a337a1c..27339c3b 100644 --- a/src/beliefpropagationdmrg/bp_dmrg.jl +++ b/src/beliefpropagationdmrg/bp_dmrg.jl @@ -7,8 +7,9 @@ include("utils.jl") include("bp_extracter.jl") include("bp_inserter.jl") include("bp_updater.jl") +include("graphsextensions.jl") -default_bp_update_kwargs(ψ::ITensorNetwork) = is_tree(ψ) ? (;) : (; maxiter = 25, tol = 1e-7) +default_bp_update_kwargs(ψ::ITensorNetwork) = is_tree(ψ) ? (;) : (; maxiter = 30, tol = 1e-10) function initialize_caches(ψ_init::ITensorNetwork, operators::Vector{ITensorNetwork}; cache_update_kwargs = default_bp_update_kwargs(ψ_init)) ψ = copy(ψ_init) @@ -23,38 +24,32 @@ function initialize_caches(ψ_init::ITensorNetwork, operators::Vector{ITensorNet return (ψ, ψIψ_bpc, ψOψ_bpcs) end -function default_vertex_order(ψ_init) - verts = collect(vertices(ψ_init)) - return [[v] for v in vcat(verts[1:length(verts) - 1], reverse(verts))] -end - -alt_vertex_order(ψ_init) = [[v] for v in collect(vertices(ψ_init))] - function bp_dmrg(ψ_init::ITensorNetwork, operators::Vector{ITensorNetwork}; no_sweeps = 1, bp_update_kwargs = default_bp_update_kwargs(ψ_init), - vertex_order_func = default_vertex_order) + vertex_order_func = ψ -> _bp_region_plan(ψ; nsites = 1, add_additional_traversal = true), energy_calc_fun) + L = length(vertices(ψ_init)) state, ψIψ_bpc, ψOψ_bpcs = initialize_caches(ψ_init, operators) regions = vertex_order_func(state) - energy = sum(scalar.(ψOψ_bpcs)) / scalar(ψIψ_bpc) - println("Initial energy is $energy") + energy = energy_calc_fun(state, ψIψ_bpc) + println("Initial energy density is $energy") energies = [energy] for i in 1:no_sweeps println("Beginning sweep $i") for region in regions + region = [rand(vertices(state))] println("Updating vertex $region") v = only(region) form_op_v = (v, "operator") - ψIψ_bpc = update(ψIψ_bpc; bp_update_kwargs...) local_ops = local_op.(ψOψ_bpcs, (v,)) ψOψ_bpcs = replace_v.(ψOψ_bpcs, (v,)) ψOψ_bpcs = update.(ψOψ_bpcs; bp_update_kwargs...) ψOψ_bpcs_scalars = scalar.(ψOψ_bpcs) pv = PartitionVertex(v) - ψOψ_bpcs = BeliefPropagationCache[rescale_messages(ψOψ_bpc, ψOψ_bpc_scalar, pv) for (ψOψ_bpc, ψOψ_bpc_scalar) in zip(ψOψ_bpcs, ψOψ_bpcs_scalars)] - ψOψ_bpcs = BeliefPropagationCache[update_factor(ψOψ_bpc, form_op_v, local_op) for (ψOψ_bpc, local_op) in zip(ψOψ_bpcs, local_ops)] + ψOψ_bpcs = rescale_messages.(ψOψ_bpcs, ψOψ_bpcs_scalars, (pv,)) + ψOψ_bpcs = update_factor.(ψOψ_bpcs, (form_op_v,), local_ops) local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts = bp_extracter(state, ψOψ_bpcs, ψIψ_bpc, region) @@ -63,8 +58,9 @@ function bp_dmrg(ψ_init::ITensorNetwork, operators::Vector{ITensorNetwork}; no_ state, ψOψ_bpcs, ψIψ_bpc = bp_inserter(state, ψOψ_bpcs, ψIψ_bpc, local_state, region; cache_update_kwargs =bp_update_kwargs) - energy = sum(scalar.(ψOψ_bpcs)) / scalar(ψIψ_bpc) - println("Current energy is $energy") + energy = energy_calc_fun(state, ψIψ_bpc) + + println("Current energy density is $energy") append!(energies, energy) end end diff --git a/src/beliefpropagationdmrg/bp_inserter.jl b/src/beliefpropagationdmrg/bp_inserter.jl index 0a7986c3..40bd3222 100644 --- a/src/beliefpropagationdmrg/bp_inserter.jl +++ b/src/beliefpropagationdmrg/bp_inserter.jl @@ -39,7 +39,6 @@ function bp_inserter(ψ::AbstractITensorNetwork, ψOψ_bpcs::Vector{<:BeliefProp ψIψ_bpc = update_factors(ψIψ_bpc, vertices_states) end - ψOψ_bpcs = update.(ψOψ_bpcs; cache_update_kwargs...) ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) if normalize_state ψ, ψIψ_bpc, ψOψ_bpcs = normalize_state_update_caches(ψ, ψIψ_bpc, ψOψ_bpcs) diff --git a/src/beliefpropagationdmrg/bp_updater.jl b/src/beliefpropagationdmrg/bp_updater.jl index 9145bdbf..51ab51ed 100644 --- a/src/beliefpropagationdmrg/bp_updater.jl +++ b/src/beliefpropagationdmrg/bp_updater.jl @@ -2,11 +2,11 @@ using ITensors: contract using ITensors.ContractionSequenceOptimization: optimal_contraction_sequence using KrylovKit: eigsolve -default_krylov_kwargs() = (; tol = 1e-14, krylovdim = 3, maxiter = 1, verbosity = 0, eager = false, ishermitian = true) +default_krylov_kwargs() = (; tol = 1e-14, krylovdim = 20, maxiter = 3, verbosity = 0, eager = false, ishermitian = true) #TODO: Put inv_sqrt_mts onto ∂ψOψ_bpc_∂r beforehand. Need to do this in an efficient way without #precontracting ∂ψOψ_bpc_∂r and getting the index logic too messy -function get_new_state(∂ψOψ_bpc_∂rs::Vector, inv_sqrt_mts, state::ITensor; sequences = ["automatic" for i in length(∂ψOψ_bpc_∂rs)]) +function get_new_state(∂ψOψ_bpc_∂rs::Vector, inv_sqrt_mts, sqrt_mts, state::ITensor; sequences = ["automatic" for i in length(∂ψOψ_bpc_∂rs)]) state = noprime(contract([state; inv_sqrt_mts])) states = ITensor[dag(noprime(contract([copy(state); ∂ψOψ_bpc_∂r]; sequence))) for (∂ψOψ_bpc_∂r, sequence) in zip(∂ψOψ_bpc_∂rs, sequences)] state = reduce(+, states) @@ -17,7 +17,7 @@ function bp_eigsolve_updater(init::ITensor, ∂ψOψ_bpc_∂rs::Vector, sqrt_mts init = noprime(contract([init; sqrt_mts])) sequences = [optimal_contraction_sequence([init; ∂ψOψ_bpc_∂r]) for ∂ψOψ_bpc_∂r in ∂ψOψ_bpc_∂rs] - get_new_state_ = state -> get_new_state(∂ψOψ_bpc_∂rs, inv_sqrt_mts, state; sequences) + get_new_state_ = state -> get_new_state(∂ψOψ_bpc_∂rs, inv_sqrt_mts, sqrt_mts, state; sequences) howmany = 1 vals, vecs, info = eigsolve(get_new_state_,init,howmany,:SR; krylov_kwargs...) diff --git a/src/beliefpropagationdmrg/graphsextensions.jl b/src/beliefpropagationdmrg/graphsextensions.jl new file mode 100644 index 00000000..97c467fa --- /dev/null +++ b/src/beliefpropagationdmrg/graphsextensions.jl @@ -0,0 +1,109 @@ +using Graphs: AbstractGraph +using NamedGraphs.GraphsExtensions: a_star, add_edge!, dfs_tree, post_order_dfs_edges +using NamedGraphs.GraphsExtensions: default_root_vertex, degree, degrees, neighbors, edgetype, rem_edge!, vertextype + +#Given a graph, traverse it from start vertex to end vertex, covering each edge exactly once. +#Complexity is O(length(edges(g))) +function eulerian_path(g::AbstractGraph, start_vertex, end_vertex) + #Conditions on g for the required path to exist + if start_vertex != end_vertex + @assert isodd(degree(g, start_vertex) % 2) + @assert isodd(degree(g, end_vertex) % 2) + @assert all(x -> iseven(x), degrees(g, setdiff(vertices(g), [start_vertex, end_vertex]))) + else + @assert all(x -> iseven(x), degrees(g)) + end + + path = vertextype(g)[] + stack = vertextype(g)[] + current_vertex = end_vertex + g_modified = copy(g) + while !isempty(stack) || !iszero(degree(g_modified, current_vertex)) + if iszero(degree(g_modified, current_vertex)) + push!(path, current_vertex) + last_vertex = pop!(stack) + current_vertex = last_vertex + else + push!(stack, current_vertex) + vn = first(neighbors(g_modified, current_vertex)) + rem_edge!(g_modified, edgetype(g_modified)(current_vertex, vn)) + current_vertex = vn + end + end + + push!(path, current_vertex) + + return edgetype(g_modified)[edgetype(g_modified)(path[i], path[i+1]) for i in 1:(length(path) - 1)] +end + +eulerian_cycle(g::AbstractGraph, start_vertex) = eulerian_path(g, start_vertex, start_vertex) + +function make_all_degrees_even(g::AbstractGraph) + g_modified = copy(g) + vertices_odd_degree = collect(filter(v -> isodd(degree(g, v)), vertices(g_modified))) + while !isempty(vertices_odd_degree) + vertex_pairs = [(vertices_odd_degree[i], vertices_odd_degree[j]) for i in 1:length(vertices_odd_degree) for j in (i+1):length(vertices_odd_degree)] + vertex_pair = first(sort(vertex_pairs; by = vp -> length(a_star(g, vp...)))) + add_edge!(g_modified, edgetype(g_modified)(vertex_pair...)) + vertices_odd_degree = filter(v -> v != first(vertex_pair) && v != last(vertex_pair), vertices_odd_degree) + end + return g_modified +end + +#Given a graph, traverse it in a cycle from start_vertex and try to minimise the number of edges traversed more than once +function _eulerian_cycle(g::AbstractGraph, start_vertex; add_additional_traversal = false) + g_modified = make_all_degrees_even(g::AbstractGraph) + path = eulerian_cycle(g_modified, start_vertex) + + !add_additional_traversal && return path + + modified_path = edgetype(g_modified)[] + + for e in path + if src(e) ∉ neighbors(g, dst(e)) + inner_path = a_star(g, src(e), dst(e)) + append!(modified_path, inner_path) + else + push!(modified_path, e) + end + end + + return modified_path +end + +function _bp_region_plan(g::AbstractGraph, start_vertex = default_root_vertex(g); nsites::Int = 1, add_additional_traversal = false) + path = _eulerian_cycle(g, start_vertex; add_additional_traversal) + if nsites == 1 + regions = [[v] for v in vcat(src.(path))] + @assert all( v -> only(v) ∈ vertices(g), regions) + return vcat(regions, reverse(regions)) + else + regions = filter(e -> e ∈ edges(g) || reverse(e) ∈ edges(g), path) + @assert all(e -> e ∈ regions || reverse(e) ∈ regions, edges(g)) + return regions + end +end + +function path_to_path(path) + verts = [] + for e in path + if isempty(verts) || src(e) ≠ last(verts) + push!(verts, src(e)) + push!(verts, dst(e)) + end + end + return [[v] for v in verts] +end + +function bp_region_plan(g::AbstractGraph, start_vertex = default_root_vertex(g); nsites::Int = 1, add_additional_traversal = false) + path = post_order_dfs_edges(g, start_vertex) + if nsites == 1 + regions = path_to_path(path) + @assert all( v -> only(v) ∈ vertices(g), regions) + return vcat(regions, reverse(regions)) + else + regions = filter(e -> e ∈ edges(g) || reverse(e) ∈ edges(g), path) + @assert all(e -> e ∈ regions || reverse(e) ∈ regions, edges(g)) + return regions + end +end \ No newline at end of file diff --git a/src/beliefpropagationdmrg/main.jl b/src/beliefpropagationdmrg/main.jl index d3b8ed0e..57e14eb0 100644 --- a/src/beliefpropagationdmrg/main.jl +++ b/src/beliefpropagationdmrg/main.jl @@ -4,29 +4,35 @@ using NPZ using ITensors: expect using Random +include("graphsextensions.jl") include("tensornetworkoperators.jl") include("bp_dmrg.jl") -Random.seed!(1234) +Random.seed!(5634) function main() - #L = 24 - #g = named_grid((L,1); periodic = true) - g = heavy_hex_lattice_graph(3,3) + g_str = "HeavyHex" + g = g_str == "Chain" ? named_grid((12,1); periodic = true) : heavy_hex_lattice_graph(2,2; periodic = true) + g = renamer(g) + save = true L = length(vertices(g)) - h,hl = 0.8, 0.2 + h, hl, J = 1.05, 0.4, 1.0 s = siteinds("S=1/2", g) χ = 2 #ψ0 = ITensorNetwork(v -> "↑", s) - ψ0 = random_tensornetwork(s; link_space = χ) + ψ0 = random_tensornetwork(s; link_space = 2) - H = ising(s; h, hl) + H = ising(s; h, hl, J1 = J) tnos = opsum_to_tno(s, H) tno = reduce(+, tnos) - ψfinal, energies = bp_dmrg(ψ0, tnos; no_sweeps = 2, vertex_order_func = alt_vertex_order) + energy_calc_fun = (tn, bp_cache) -> sum(expect(tn, H; alg = "bp", (cache!) = Ref(bp_cache)))/L + + ψfinal, energies = bp_dmrg(ψ0, tnos; no_sweeps = 5, energy_calc_fun) final_mags = expect(ψfinal, "Z", ; alg = "bp") - npzwrite("/Users/jtindall/Documents/Data/BPDMRG/HEAVYHEXISINGL$(L)h$(h)hl$(hl)chi$(χ).npz", energies = energies, final_mags = final_mags) + if save + npzwrite("/Users/jtindall/Files/Data/BPDMRG/"*g_str*"ISINGL$(L)h$(h)hl$(hl)chi$(χ).npz", energies = energies, final_mags = final_mags) + end end diff --git a/src/beliefpropagationdmrg/utils.jl b/src/beliefpropagationdmrg/utils.jl index 8761d921..de586d73 100644 --- a/src/beliefpropagationdmrg/utils.jl +++ b/src/beliefpropagationdmrg/utils.jl @@ -12,51 +12,6 @@ using ITensorNetworks.ModelHamiltonians: heisenberg using ITensors: ITensor, noprime, dag, noncommonind, commonind, replaceind, dim, noncommoninds, delta, replaceinds using ITensors.NDTensors: denseblocks -function heavy_hex_lattice_graph(n::Int64, m::Int64) - """Create heavy-hex lattice geometry""" - g = named_hexagonal_lattice_graph(n, m) - g = decorate_graph_edges(g) - - vertex_rename = Dictionary() - for (i,v) in enumerate(vertices(g)) - set!(vertex_rename, v, (i,)) - end - g = rename_vertices(v -> vertex_rename[v], g) - - return g -end - -function BP_apply(o::ITensor, ψ::AbstractITensorNetwork, bpc::BeliefPropagationCache; apply_kwargs...) - bpc = copy(bpc) - ψ = copy(ψ) - vs = neighbor_vertices(ψ, o) - envs = environment(bpc, PartitionVertex.(vs)) - singular_values! = Ref(ITensor()) - ψ = noprime(apply(o, ψ; envs, singular_values!, normalize=true, apply_kwargs...)) - ψdag = prime(dag(ψ); sites=[]) - if length(vs) == 2 - v1, v2 = vs - pe = partitionedge(bpc, (v1, "bra") => (v2, "bra")) - mts = messages(bpc) - ind1, ind2 = noncommonind(singular_values![], ψ[v1]), commonind(singular_values![], ψ[v1]) - singular_values![] = denseblocks(replaceind(singular_values![], ind1, ind2')) - set!(mts, pe, ITensor[singular_values![]]) - set!(mts, reverse(pe), ITensor[singular_values![]]) - end - for v in vs - bpc = update_factor(bpc, (v, "ket"), ψ[v]) - bpc = update_factor(bpc, (v, "bra"), ψdag[v]) - end - return ψ, bpc -end - -function smallest_eigvalue(A::AbstractITensorNetwork) - out = reduce(*, [A[v] for v in vertices(A)]) - out = out * combiner(inds(out; plev = 0)) *combiner(inds(out; plev = 1)) - out = array(out) - return minimum(real.(eigvals(out))) -end - function replace_v(bpc::BeliefPropagationCache, v) bpc = copy(bpc) qf = unpartitioned_graph(partitioned_tensornetwork(bpc)) @@ -80,4 +35,19 @@ end function get_local_term(bpc::BeliefPropagationCache, v) qf = copy(unpartitioned_graph(partitioned_tensornetwork(bpc))) return qf[(v, "bra")]*qf[(v, "ket")]*qf[(v, "operator")] -end \ No newline at end of file +end + +function exact_energy(g::AbstractGraph, bpc::BeliefPropagationCache) + tn = ITensorNetwork(g) + for v in vertices(g) + tn[v] = get_local_term(bpc, v) + end + degree_two_sites = filter(v -> degree(tn, v) == 2, vertices(tn)) + while !isempty(degree_two_sites) + v = first(degree_two_sites) + vn = first(neighbors(g, v)) + tn = contract(tn, NamedEdge(v => vn); merged_vertex=vn) + degree_two_sites = filter(v -> degree(tn, v) == 2, vertices(tn)) + end + return ITensors.contract(ITensor[tn[v] for v in vertices(tn)]; sequence = "automatic")[] +end diff --git a/src/solvers/extract/extract.jl b/src/solvers/extract/extract.jl index 2172c480..19a49dfa 100644 --- a/src/solvers/extract/extract.jl +++ b/src/solvers/extract/extract.jl @@ -23,19 +23,4 @@ function default_extracter(state, projected_operator, region, ortho; internal_kw end projected_operator = position(projected_operator, state, region) return state, projected_operator, local_tensor -end - -function bp_extracter(ψ::AbstractITensorNetwork, ψAψ_bpcs::Vector{<:BeliefPropagationCache}, ψIψ_bpc::BeliefPropagationCache, region; - regularization = 10*eps(scalartype(ψ))) - form_network = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) - form_ket_vertices, form_bra_vertices = ket_vertices(form_network, region), bra_vertices(form_network, region) - ∂ψAψ_bpc_∂rs = [environment(ψAψ_bpc, [form_ket_vertices; form_bra_vertices]) for ψAψ_bpc in ψAψ_bpcs] - state = prod(ψ[v] for v in region) - messages = environment(ψIψ_bpc, partitionvertices(ψIψ_bpc, form_ket_vertices)) - f_sqrt = sqrt ∘ (x -> x + regularization) - f_inv_sqrt = inv ∘ sqrt ∘ (x -> x + regularization) - sqrt_mts = [ITensorsExtensions.map_eigvals(f_sqrt, mt, inds(mt)[1], inds(mt)[2]; ishermitian=true) for mt in messages] - inv_sqrt_mts = [ITensorsExtensions.map_eigvals(f_inv_sqrt, mt, inds(mt)[1], inds(mt)[2]; ishermitian=true) for mt in messages] - - return state, ∂ψAψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts end \ No newline at end of file From 371492d3063ed2bbf465566d7710fe0f82613c58 Mon Sep 17 00:00:00 2001 From: Joey Date: Tue, 11 Jun 2024 22:25:40 -0400 Subject: [PATCH 11/27] Commit 1 --- src/beliefpropagationdmrg/bp_dmrg.jl | 53 ++++++++++++++------ src/beliefpropagationdmrg/bp_inserter.jl | 7 +-- src/beliefpropagationdmrg/main.jl | 7 ++- src/beliefpropagationdmrg/utils.jl | 62 ++++++++++++++---------- src/caches/beliefpropagationcache.jl | 48 ++++++++++++------ 5 files changed, 109 insertions(+), 68 deletions(-) diff --git a/src/beliefpropagationdmrg/bp_dmrg.jl b/src/beliefpropagationdmrg/bp_dmrg.jl index 27339c3b..9feed611 100644 --- a/src/beliefpropagationdmrg/bp_dmrg.jl +++ b/src/beliefpropagationdmrg/bp_dmrg.jl @@ -1,6 +1,6 @@ using NamedGraphs.GraphsExtensions: is_tree -using NamedGraphs.PartitionedGraphs: partitionvertices -using ITensorNetworks: ITensorNetwork, QuadraticFormNetwork, BeliefPropagationCache, update, rescale_messages +using NamedGraphs.PartitionedGraphs: partitionvertices, partitionedges, PartitionEdge +using ITensorNetworks: ITensorNetwork, QuadraticFormNetwork, BeliefPropagationCache, update, default_message_update using ITensors: scalar include("utils.jl") @@ -11,52 +11,73 @@ include("graphsextensions.jl") default_bp_update_kwargs(ψ::ITensorNetwork) = is_tree(ψ) ? (;) : (; maxiter = 30, tol = 1e-10) +message_update_f = tns -> default_message_update(tns; normalize = false) + function initialize_caches(ψ_init::ITensorNetwork, operators::Vector{ITensorNetwork}; cache_update_kwargs = default_bp_update_kwargs(ψ_init)) ψ = copy(ψ_init) ψIψ = QuadraticFormNetwork(ψ) ψIψ_bpc = BeliefPropagationCache(ψIψ) - ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) ψOψs = QuadraticFormNetwork[QuadraticFormNetwork(operator, ψ) for operator in operators] ψOψ_bpcs = BeliefPropagationCache[BeliefPropagationCache(ψOψ) for ψOψ in ψOψs] - ψOψ_bpcs = BeliefPropagationCache[update(ψOψ_bpc; cache_update_kwargs...) for ψOψ_bpc in ψOψ_bpcs] - return (ψ, ψIψ_bpc, ψOψ_bpcs) end -function bp_dmrg(ψ_init::ITensorNetwork, operators::Vector{ITensorNetwork}; no_sweeps = 1, bp_update_kwargs = default_bp_update_kwargs(ψ_init), +function reduced_bp(state::ITensorNetwork, operators::Vector{ITensorNetwork}, ψIψ_bpc::BeliefPropagationCache, + ψOψ_bpcs::Vector{<:BeliefPropagationCache}, v) + + ψIψ_bpc_mts = messages(ψIψ_bpc) + ψOψ_bpcs = copy.(ψOψ_bpcs) + + for (ψOψ_bpc, operator) in zip(ψOψ_bpcs, operators) + ptn = partitioned_tensornetwork(ψOψ_bpc) + edge_seq = post_order_dfs_edges(underlying_graph(operator), v) + broken_edges = setdiff(edges(state), edges(operator)) + partition_broken_edges = PartitionEdge.(broken_edges) + partition_broken_edges = vcat(partition_broken_edges, reverse.(partition_broken_edges)) + mts = messages(ψOψ_bpc) + for pe in partition_broken_edges + set!(mts, pe, copy(ψIψ_bpc_mts[pe])) + end + partition_edge_seq = PartitionEdge.(edge_seq) + ψOψ_bpc = update(ψOψ_bpc, partition_edge_seq; message_update = message_update_f) + end + + return state, ψOψ_bpcs, ψIψ_bpc +end + + +function bp_dmrg(ψ_init::ITensorNetwork, operators::Vector; no_sweeps = 1, bp_update_kwargs = default_bp_update_kwargs(ψ_init), vertex_order_func = ψ -> _bp_region_plan(ψ; nsites = 1, add_additional_traversal = true), energy_calc_fun) L = length(vertices(ψ_init)) state, ψIψ_bpc, ψOψ_bpcs = initialize_caches(ψ_init, operators) regions = vertex_order_func(state) + state, ψIψ_bpc, ψOψ_bpcs = updater(state, ψIψ_bpc, ψOψ_bpcs; cache_update_kwargs = bp_update_kwargs) + energy = energy_calc_fun(state, ψIψ_bpc) println("Initial energy density is $energy") energies = [energy] + no_sweeps = 1 for i in 1:no_sweeps println("Beginning sweep $i") for region in regions - region = [rand(vertices(state))] println("Updating vertex $region") v = only(region) - form_op_v = (v, "operator") - local_ops = local_op.(ψOψ_bpcs, (v,)) - ψOψ_bpcs = replace_v.(ψOψ_bpcs, (v,)) - ψOψ_bpcs = update.(ψOψ_bpcs; bp_update_kwargs...) - ψOψ_bpcs_scalars = scalar.(ψOψ_bpcs) - pv = PartitionVertex(v) - ψOψ_bpcs = rescale_messages.(ψOψ_bpcs, ψOψ_bpcs_scalars, (pv,)) - ψOψ_bpcs = update_factor.(ψOψ_bpcs, (form_op_v,), local_ops) + #TODO: Do BP on ψOψs but default the messages to be incoming to that region to be those from ψIψ_bpc + state, ψOψ_bpcs, ψIψ_bpc = reduced_bp(state, operators, ψIψ_bpc, ψOψ_bpcs, v) local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts = bp_extracter(state, ψOψ_bpcs, ψIψ_bpc, region) #Do an eigsolve local_state, _ = bp_eigsolve_updater(local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts) - state, ψOψ_bpcs, ψIψ_bpc = bp_inserter(state, ψOψ_bpcs, ψIψ_bpc, local_state, region; cache_update_kwargs =bp_update_kwargs) + state, ψOψ_bpcs, ψIψ_bpc = bp_inserter(state, ψOψ_bpcs, ψIψ_bpc, local_state, region) + + state, ψIψ_bpc, ψOψ_bpcs = updater(state, ψIψ_bpc, ψOψ_bpcs; cache_update_kwargs = bp_update_kwargs) energy = energy_calc_fun(state, ψIψ_bpc) diff --git a/src/beliefpropagationdmrg/bp_inserter.jl b/src/beliefpropagationdmrg/bp_inserter.jl index 40bd3222..96b50ad3 100644 --- a/src/beliefpropagationdmrg/bp_inserter.jl +++ b/src/beliefpropagationdmrg/bp_inserter.jl @@ -22,7 +22,7 @@ end #TODO: Add support for nsites = 2 function bp_inserter(ψ::AbstractITensorNetwork, ψOψ_bpcs::Vector{<:BeliefPropagationCache}, - ψIψ_bpc::BeliefPropagationCache, state::ITensor, region; normalize_state = true, cache_update_kwargs, nsites::Int64 = 1, kwargs...) + ψIψ_bpc::BeliefPropagationCache, state::ITensor, region; nsites::Int64 = 1, kwargs...) @assert nsites == 1 ψ = copy(ψ) @@ -39,10 +39,5 @@ function bp_inserter(ψ::AbstractITensorNetwork, ψOψ_bpcs::Vector{<:BeliefProp ψIψ_bpc = update_factors(ψIψ_bpc, vertices_states) end - ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) - if normalize_state - ψ, ψIψ_bpc, ψOψ_bpcs = normalize_state_update_caches(ψ, ψIψ_bpc, ψOψ_bpcs) - end - return ψ, ψOψ_bpcs, ψIψ_bpc end \ No newline at end of file diff --git a/src/beliefpropagationdmrg/main.jl b/src/beliefpropagationdmrg/main.jl index 57e14eb0..05484d24 100644 --- a/src/beliefpropagationdmrg/main.jl +++ b/src/beliefpropagationdmrg/main.jl @@ -11,20 +11,19 @@ include("bp_dmrg.jl") Random.seed!(5634) function main() - g_str = "HeavyHex" + g_str = "Chain" g = g_str == "Chain" ? named_grid((12,1); periodic = true) : heavy_hex_lattice_graph(2,2; periodic = true) g = renamer(g) save = true L = length(vertices(g)) h, hl, J = 1.05, 0.4, 1.0 s = siteinds("S=1/2", g) - χ = 2 + χ = 1 #ψ0 = ITensorNetwork(v -> "↑", s) - ψ0 = random_tensornetwork(s; link_space = 2) + ψ0 = random_tensornetwork(s; link_space = χ) H = ising(s; h, hl, J1 = J) tnos = opsum_to_tno(s, H) - tno = reduce(+, tnos) energy_calc_fun = (tn, bp_cache) -> sum(expect(tn, H; alg = "bp", (cache!) = Ref(bp_cache)))/L diff --git a/src/beliefpropagationdmrg/utils.jl b/src/beliefpropagationdmrg/utils.jl index de586d73..f9c765ad 100644 --- a/src/beliefpropagationdmrg/utils.jl +++ b/src/beliefpropagationdmrg/utils.jl @@ -6,37 +6,12 @@ using NamedGraphs.GraphsExtensions: decorate_graph_edges, forest_cover, add_edge using NamedGraphs.PartitionedGraphs: PartitionVertex, partitionedge, unpartitioned_graph using ITensorNetworks: BeliefPropagationCache, AbstractITensorNetwork, AbstractFormNetwork, IndsNetwork, ITensorNetwork, insert_linkinds, ttn, union_all_inds, neighbor_vertices, environment, messages, update_factor, message, partitioned_tensornetwork, bra_vertex, ket_vertex, operator_vertex, default_cache_update_kwargs, - dual_index_map + dual_index_map, region_scalar, renormalize_messages, scalar_factors_quotient using DataGraphs: underlying_graph using ITensorNetworks.ModelHamiltonians: heisenberg using ITensors: ITensor, noprime, dag, noncommonind, commonind, replaceind, dim, noncommoninds, delta, replaceinds using ITensors.NDTensors: denseblocks -function replace_v(bpc::BeliefPropagationCache, v) - bpc = copy(bpc) - qf = unpartitioned_graph(partitioned_tensornetwork(bpc)) - v_ket, v_bra, v_op = bra_vertex(qf, v), ket_vertex(qf, v), operator_vertex(qf, v) - s, sp = commonind(qf[v_op], qf[v_bra]), commonind(qf[v_op], qf[v_ket]) - d = dim(s) - remaining_inds = intersect(noncommoninds(qf[v_op], qf[v_bra]), noncommoninds(qf[v_op], qf[v_ket])) - bpc = update_factor(bpc, v_ket, ITensor(sqrt(1.0 / d), inds(qf[v_ket]))) - bpc = update_factor(bpc, v_bra, ITensor(sqrt(1.0 / d), inds(qf[v_bra]))) - bpc = update_factor(bpc, v_op, delta(s,sp)*ITensor(1.0, remaining_inds)) - return bpc -end - -function local_op(bpc::BeliefPropagationCache, v) - qf = unpartitioned_graph(partitioned_tensornetwork(bpc)) - v_op = operator_vertex(qf, v) - return copy(qf[v_op]) -end - - -function get_local_term(bpc::BeliefPropagationCache, v) - qf = copy(unpartitioned_graph(partitioned_tensornetwork(bpc))) - return qf[(v, "bra")]*qf[(v, "ket")]*qf[(v, "operator")] -end - function exact_energy(g::AbstractGraph, bpc::BeliefPropagationCache) tn = ITensorNetwork(g) for v in vertices(g) @@ -51,3 +26,38 @@ function exact_energy(g::AbstractGraph, bpc::BeliefPropagationCache) end return ITensors.contract(ITensor[tn[v] for v in vertices(tn)]; sequence = "automatic")[] end + +function renamer(g) + vertex_rename = Dictionary() + for (i,v) in enumerate(vertices(g)) + set!(vertex_rename, v, (i,)) + end + return rename_vertices(v -> vertex_rename[v], g) +end + +function updater(ψ::ITensorNetwork, ψIψ_bpc::BeliefPropagationCache, ψOψ_bpcs::Vector{<:BeliefPropagationCache}; + cache_update_kwargs) + + ψ = copy(ψ) + ψOψ_bpcs = copy.(ψOψ_bpcs) + ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) + ψIψ_bpc = renormalize_messages(ψIψ_bpc) + qf = tensornetwork(ψIψ_bpc) + + for v in vertices(ψ) + v_ket, v_bra = ket_vertex(qf, v), bra_vertex(qf, v) + pv = only(partitionvertices(ψIψ_bpc, [v_ket])) + vn = region_scalar(ψIψ_bpc, pv) + state = (1.0 / sqrt(vn)) * ψ[v] + state_dag = copy(state) + state_dag = replaceinds(dag(state_dag), inds(state_dag), dual_index_map(qf).(inds(state_dag))) + vertices_states = Dictionary([v_ket, v_bra], [state, state_dag]) + ψOψ_bpcs = update_factors.(ψOψ_bpcs, (vertices_states,)) + ψIψ_bpc = update_factors(ψIψ_bpc, vertices_states) + ψ[v] = state + end + + return ψ, ψIψ_bpc, ψOψ_bpcs +end + + diff --git a/src/caches/beliefpropagationcache.jl b/src/caches/beliefpropagationcache.jl index cb074a98..c77d4bbe 100644 --- a/src/caches/beliefpropagationcache.jl +++ b/src/caches/beliefpropagationcache.jl @@ -158,6 +158,15 @@ function environment(bp_cache::BeliefPropagationCache, verts::Vector) return vcat(messages, central_tensors) end +function factors(bp_cache::BeliefPropagationCache, vertices::Vector) + tn = tensornetwork(bp_cache) + return ITensor[tn[vertex] for vertex in vertices] +end + +function factor(bp_cache::BeliefPropagationCache, vertex) + return only(factors(bp_cache, [vertex])) +end + function factor(bp_cache::BeliefPropagationCache, vertex::PartitionVertex) ptn = partitioned_tensornetwork(bp_cache) return collect(eachtensor(subgraph(ptn, vertex))) @@ -318,26 +327,33 @@ function ITensors.scalar(bp_cache::BeliefPropagationCache) return prod(v_scalars) / prod(e_scalars) end -function rescale_messages(bp_cache::BeliefPropagationCache, scalar::Float64, pv::PartitionVertex; scale_all = true) +function renormalize_messages(bp_cache::BeliefPropagationCache) bp_cache = copy(bp_cache) - pedges = boundary_partitionedges(bp_cache, PartitionVertex[pv]; dir=:in) - no_ms = length(pedges) mts = messages(bp_cache) - if scale_all - scale_neg = scalar < 0 ? true : false - c = abs(scalar) ^ (1/no_ms) - - for pe in pedges - mt = only(mts[pe]) - mt *= (c / sum(mt)) - set!(mts, pe, ITensor[mt]) + for pe in partitionedges(partitioned_tensornetwork(bp_cache)) + n = region_scalar(bp_cache, pe) + me, mer = only(mts[pe]), only(mts[reverse(pe)]) + if n >= 0 + set!(mts, pe, ITensor[(1/sqrt(n))*me]) + set!(mts, reverse(pe), ITensor[(1/sqrt(n))*mer]) + else + set!(mts, pe, ITensor[-(1/sqrt(abs(n)))*me]) + set!(mts, reverse(pe), ITensor[(1/sqrt(abs(n)))*mer]) end + end + return bp_cache +end - if scale_neg - mt = only(mts[first(pedges)]) - mt *= -1 - set!(mts, first(pedges), ITensor[mt]) - end +function renormalize_factors(bp_cache::BeliefPropagationCache) + bp_cache = copy(bp_cache) + tn = tensornetwork(bp_cache) + for pv in partitionvertices(partitioned_tensornetwork(bp_cache)) + n = 1.0 / region_scalar(bp_cache, pv) + verts = vertices(bp_cache, pv) + v = first(first(verts)) + n = n ^(1/2) + fs = Dictionary([(v, "ket"), (v, "bra")], n.*factors(bp_cache, [(v, "ket"), (v, "bra")])) + bp_cache = update_factors(bp_cache, fs) end return bp_cache end From 5138e51e21fa031d8c9a7cc3d2881107335883f2 Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 12 Jun 2024 11:39:45 -0400 Subject: [PATCH 12/27] Changes --- src/beliefpropagationdmrg/bp_dmrg.jl | 62 ++++++++++++++++++------ src/beliefpropagationdmrg/bp_inserter.jl | 21 -------- src/beliefpropagationdmrg/bp_updater.jl | 12 ++--- src/beliefpropagationdmrg/main.jl | 13 +++-- src/beliefpropagationdmrg/utils.jl | 56 ++++++++++++--------- src/caches/beliefpropagationcache.jl | 14 ------ 6 files changed, 96 insertions(+), 82 deletions(-) diff --git a/src/beliefpropagationdmrg/bp_dmrg.jl b/src/beliefpropagationdmrg/bp_dmrg.jl index 9feed611..389f4022 100644 --- a/src/beliefpropagationdmrg/bp_dmrg.jl +++ b/src/beliefpropagationdmrg/bp_dmrg.jl @@ -9,7 +9,7 @@ include("bp_inserter.jl") include("bp_updater.jl") include("graphsextensions.jl") -default_bp_update_kwargs(ψ::ITensorNetwork) = is_tree(ψ) ? (;) : (; maxiter = 30, tol = 1e-10) +default_bp_update_kwargs(ψ::ITensorNetwork) = is_tree(ψ) ? (;) : (; maxiter = 50, tol = 1e-14) message_update_f = tns -> default_message_update(tns; normalize = false) @@ -27,28 +27,55 @@ function reduced_bp(state::ITensorNetwork, operators::Vector{ITensorNetwork}, ψ ψOψ_bpcs::Vector{<:BeliefPropagationCache}, v) ψIψ_bpc_mts = messages(ψIψ_bpc) - ψOψ_bpcs = copy.(ψOψ_bpcs) + new_ψOψ_bpcs = BeliefPropagationCache[] for (ψOψ_bpc, operator) in zip(ψOψ_bpcs, operators) - ptn = partitioned_tensornetwork(ψOψ_bpc) + new_ψOψ_bpc = copy(ψOψ_bpc) + ptn = partitioned_tensornetwork(new_ψOψ_bpc) edge_seq = post_order_dfs_edges(underlying_graph(operator), v) broken_edges = setdiff(edges(state), edges(operator)) partition_broken_edges = PartitionEdge.(broken_edges) partition_broken_edges = vcat(partition_broken_edges, reverse.(partition_broken_edges)) - mts = messages(ψOψ_bpc) + mts = messages(new_ψOψ_bpc) for pe in partition_broken_edges set!(mts, pe, copy(ψIψ_bpc_mts[pe])) end partition_edge_seq = PartitionEdge.(edge_seq) - ψOψ_bpc = update(ψOψ_bpc, partition_edge_seq; message_update = message_update_f) + new_ψOψ_bpc = update(new_ψOψ_bpc, partition_edge_seq; message_update = message_update_f) + push!(new_ψOψ_bpcs, new_ψOψ_bpc) + end + + return state, new_ψOψ_bpcs, ψIψ_bpc +end + +function updater(ψ::ITensorNetwork, ψIψ_bpc::BeliefPropagationCache, ψOψ_bpcs::Vector{<:BeliefPropagationCache}; + cache_update_kwargs) + + ψ = copy(ψ) + ψOψ_bpcs = copy.(ψOψ_bpcs) + ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) + ψIψ_bpc = renormalize_messages(ψIψ_bpc) + qf = tensornetwork(ψIψ_bpc) + + for v in vertices(ψ) + v_ket, v_bra = ket_vertex(qf, v), bra_vertex(qf, v) + pv = only(partitionvertices(ψIψ_bpc, [v_ket])) + vn = region_scalar(ψIψ_bpc, pv) + state = (1.0 / sqrt(vn)) * ψ[v] + state_dag = copy(state) + state_dag = replaceinds(dag(state_dag), inds(state_dag), dual_index_map(qf).(inds(state_dag))) + vertices_states = Dictionary([v_ket, v_bra], [state, state_dag]) + ψOψ_bpcs = update_factors.(ψOψ_bpcs, (vertices_states,)) + ψIψ_bpc = update_factors(ψIψ_bpc, vertices_states) + ψ[v] = state end - return state, ψOψ_bpcs, ψIψ_bpc + return ψ, ψIψ_bpc, ψOψ_bpcs end function bp_dmrg(ψ_init::ITensorNetwork, operators::Vector; no_sweeps = 1, bp_update_kwargs = default_bp_update_kwargs(ψ_init), - vertex_order_func = ψ -> _bp_region_plan(ψ; nsites = 1, add_additional_traversal = true), energy_calc_fun) + vertex_order_func = ψ -> bp_region_plan(ψ; nsites = 1, add_additional_traversal = false), energy_calc_fun) L = length(vertices(ψ_init)) state, ψIψ_bpc, ψOψ_bpcs = initialize_caches(ψ_init, operators) @@ -56,33 +83,40 @@ function bp_dmrg(ψ_init::ITensorNetwork, operators::Vector; no_sweeps = 1, bp_u state, ψIψ_bpc, ψOψ_bpcs = updater(state, ψIψ_bpc, ψOψ_bpcs; cache_update_kwargs = bp_update_kwargs) - energy = energy_calc_fun(state, ψIψ_bpc) - println("Initial energy density is $energy") + energy = real(energy_calc_fun(state, ψIψ_bpc)) + println("Initial energy density is $(energy)") energies = [energy] - no_sweeps = 1 for i in 1:no_sweeps println("Beginning sweep $i") for region in regions println("Updating vertex $region") - + v = only(region) + #v = rand(vertices()) #TODO: Do BP on ψOψs but default the messages to be incoming to that region to be those from ψIψ_bpc state, ψOψ_bpcs, ψIψ_bpc = reduced_bp(state, operators, ψIψ_bpc, ψOψ_bpcs, v) local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts = bp_extracter(state, ψOψ_bpcs, ψIψ_bpc, region) #Do an eigsolve - local_state, _ = bp_eigsolve_updater(local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts) + local_state, energy = bp_eigsolve_updater(local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts, last(energies); L) state, ψOψ_bpcs, ψIψ_bpc = bp_inserter(state, ψOψ_bpcs, ψIψ_bpc, local_state, region) state, ψIψ_bpc, ψOψ_bpcs = updater(state, ψIψ_bpc, ψOψ_bpcs; cache_update_kwargs = bp_update_kwargs) - energy = energy_calc_fun(state, ψIψ_bpc) + # if energy < last(energies) + # println("Current energy density is $(energy / L)") + # append!(energies, energy) + # else + # println("Rejected Move") + # end - println("Current energy density is $energy") + + energy = energy_calc_fun(state, ψIψ_bpc) append!(energies, energy) + println("Current energy density is $(energy)") end end diff --git a/src/beliefpropagationdmrg/bp_inserter.jl b/src/beliefpropagationdmrg/bp_inserter.jl index 96b50ad3..19f27587 100644 --- a/src/beliefpropagationdmrg/bp_inserter.jl +++ b/src/beliefpropagationdmrg/bp_inserter.jl @@ -1,30 +1,9 @@ using ITensorNetworks: update_factors -function normalize_state_update_caches(ψ::ITensorNetwork, ψIψ::BeliefPropagationCache, ψOψs::Vector{<:BeliefPropagationCache}) - qf = tensornetwork(ψIψ) - L = length(vertices(ψ)) - cur_norm = scalar(ψIψ) - rescale_coeff = cur_norm^(-1/(2*L)) - ψ = copy(ψ) - for v in vertices(ψ) - form_bra_v, form_ket_v = bra_vertex(qf, v), ket_vertex(qf, v) - state = ψ[v] * rescale_coeff - ψ[v] = state - state_dag = copy(ψ[v]) - state_dag = replaceinds(dag(state_dag), inds(state_dag), dual_index_map(qf).(inds(state_dag))) - vertices_states = Dictionary([form_ket_v, form_bra_v], [state, state_dag]) - ψIψ = update_factors(ψIψ, vertices_states) - ψOψs = update_factors.(ψOψs, (vertices_states, )) - end - - return ψ, ψIψ, ψOψs -end - #TODO: Add support for nsites = 2 function bp_inserter(ψ::AbstractITensorNetwork, ψOψ_bpcs::Vector{<:BeliefPropagationCache}, ψIψ_bpc::BeliefPropagationCache, state::ITensor, region; nsites::Int64 = 1, kwargs...) - @assert nsites == 1 ψ = copy(ψ) form_network = tensornetwork(ψIψ_bpc) states = ITensor[state] diff --git a/src/beliefpropagationdmrg/bp_updater.jl b/src/beliefpropagationdmrg/bp_updater.jl index 51ab51ed..272edfc0 100644 --- a/src/beliefpropagationdmrg/bp_updater.jl +++ b/src/beliefpropagationdmrg/bp_updater.jl @@ -2,7 +2,7 @@ using ITensors: contract using ITensors.ContractionSequenceOptimization: optimal_contraction_sequence using KrylovKit: eigsolve -default_krylov_kwargs() = (; tol = 1e-14, krylovdim = 20, maxiter = 3, verbosity = 0, eager = false, ishermitian = true) +default_krylov_kwargs() = (; tol = 1e-14, maxiter = 1, verbosity = 0, eager = false, ishermitian = true) #TODO: Put inv_sqrt_mts onto ∂ψOψ_bpc_∂r beforehand. Need to do this in an efficient way without #precontracting ∂ψOψ_bpc_∂r and getting the index logic too messy @@ -13,15 +13,15 @@ function get_new_state(∂ψOψ_bpc_∂rs::Vector, inv_sqrt_mts, sqrt_mts, state return noprime(contract([state; (inv_sqrt_mts)])) end -function bp_eigsolve_updater(init::ITensor, ∂ψOψ_bpc_∂rs::Vector, sqrt_mts, inv_sqrt_mts; krylov_kwargs = default_krylov_kwargs()) +function bp_eigsolve_updater(init::ITensor, ∂ψOψ_bpc_∂rs::Vector, sqrt_mts, inv_sqrt_mts, previous_energy; L, krylov_kwargs = default_krylov_kwargs()) - init = noprime(contract([init; sqrt_mts])) - sequences = [optimal_contraction_sequence([init; ∂ψOψ_bpc_∂r]) for ∂ψOψ_bpc_∂r in ∂ψOψ_bpc_∂rs] + gauged_init = noprime(contract([copy(init); sqrt_mts])) + sequences = [optimal_contraction_sequence([gauged_init; ∂ψOψ_bpc_∂r]) for ∂ψOψ_bpc_∂r in ∂ψOψ_bpc_∂rs] get_new_state_ = state -> get_new_state(∂ψOψ_bpc_∂rs, inv_sqrt_mts, sqrt_mts, state; sequences) howmany = 1 - vals, vecs, info = eigsolve(get_new_state_,init,howmany,:SR; krylov_kwargs...) + vals, vecs, info = eigsolve(get_new_state_,gauged_init,howmany,:SR; krylov_kwargs...) state = noprime(contract([first(vecs); inv_sqrt_mts])) - return state, (; info, eigvals=vals) + return state, first(vals) end \ No newline at end of file diff --git a/src/beliefpropagationdmrg/main.jl b/src/beliefpropagationdmrg/main.jl index 05484d24..f7a27edd 100644 --- a/src/beliefpropagationdmrg/main.jl +++ b/src/beliefpropagationdmrg/main.jl @@ -12,15 +12,17 @@ Random.seed!(5634) function main() g_str = "Chain" - g = g_str == "Chain" ? named_grid((12,1); periodic = true) : heavy_hex_lattice_graph(2,2; periodic = true) + g = g_str == "Chain" ? named_grid((24,1); periodic = true) : heavy_hex_lattice_graph(2,2; periodic = true) g = renamer(g) save = true L = length(vertices(g)) - h, hl, J = 1.05, 0.4, 1.0 + h, hl, J = 0.6, 0.0, 1.0 s = siteinds("S=1/2", g) - χ = 1 - #ψ0 = ITensorNetwork(v -> "↑", s) - ψ0 = random_tensornetwork(s; link_space = χ) + χ = 2 + dbetas = [(10, 0.5), (10, 0.25), (20, 0.1)] + ψ0 = ITensorNetwork(v -> "↑", s) + ψ0 = imaginary_time_evo(s, ψ0, ising, dbetas; model_params = (; h, hl, J1 = J) ,bp_update_kwargs = (; maxiter = 10, tol = 1e-10), apply_kwargs = (; cutoff = 1e-12, maxdim = χ)) + #ψ0 = random_tensornetwork(s; link_space = χ) H = ising(s; h, hl, J1 = J) tnos = opsum_to_tno(s, H) @@ -29,6 +31,7 @@ function main() ψfinal, energies = bp_dmrg(ψ0, tnos; no_sweeps = 5, energy_calc_fun) final_mags = expect(ψfinal, "Z", ; alg = "bp") + @show final_mags if save npzwrite("/Users/jtindall/Files/Data/BPDMRG/"*g_str*"ISINGL$(L)h$(h)hl$(hl)chi$(χ).npz", energies = energies, final_mags = final_mags) end diff --git a/src/beliefpropagationdmrg/utils.jl b/src/beliefpropagationdmrg/utils.jl index f9c765ad..b431bb81 100644 --- a/src/beliefpropagationdmrg/utils.jl +++ b/src/beliefpropagationdmrg/utils.jl @@ -6,11 +6,17 @@ using NamedGraphs.GraphsExtensions: decorate_graph_edges, forest_cover, add_edge using NamedGraphs.PartitionedGraphs: PartitionVertex, partitionedge, unpartitioned_graph using ITensorNetworks: BeliefPropagationCache, AbstractITensorNetwork, AbstractFormNetwork, IndsNetwork, ITensorNetwork, insert_linkinds, ttn, union_all_inds, neighbor_vertices, environment, messages, update_factor, message, partitioned_tensornetwork, bra_vertex, ket_vertex, operator_vertex, default_cache_update_kwargs, - dual_index_map, region_scalar, renormalize_messages, scalar_factors_quotient + dual_index_map, region_scalar, renormalize_messages, scalar_factors_quotient, norm_sqr_network using DataGraphs: underlying_graph using ITensorNetworks.ModelHamiltonians: heisenberg -using ITensors: ITensor, noprime, dag, noncommonind, commonind, replaceind, dim, noncommoninds, delta, replaceinds +using ITensors: ITensor, noprime, dag, noncommonind, commonind, replaceind, dim, noncommoninds, delta, replaceinds, Trotter using ITensors.NDTensors: denseblocks +using SplitApplyCombine: group + +function get_local_term(bpc::BeliefPropagationCache, v) + qf = tensornetwork(bpc) + return qf[(v, "ket")]*qf[(v, "operator")]*qf[(v, "bra")] +end function exact_energy(g::AbstractGraph, bpc::BeliefPropagationCache) tn = ITensorNetwork(g) @@ -35,29 +41,35 @@ function renamer(g) return rename_vertices(v -> vertex_rename[v], g) end -function updater(ψ::ITensorNetwork, ψIψ_bpc::BeliefPropagationCache, ψOψ_bpcs::Vector{<:BeliefPropagationCache}; - cache_update_kwargs) - +function imaginary_time_evo(s::IndsNetwork, ψ::ITensorNetwork, model::Function, dbetas::Vector{<:Tuple}; model_params, + bp_update_kwargs = (; maxiter = 10, tol = 1e-10), apply_kwargs = (; cutoff = 1e-12, maxdim = 10)) ψ = copy(ψ) - ψOψ_bpcs = copy.(ψOψ_bpcs) - ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) - ψIψ_bpc = renormalize_messages(ψIψ_bpc) - qf = tensornetwork(ψIψ_bpc) - - for v in vertices(ψ) - v_ket, v_bra = ket_vertex(qf, v), bra_vertex(qf, v) - pv = only(partitionvertices(ψIψ_bpc, [v_ket])) - vn = region_scalar(ψIψ_bpc, pv) - state = (1.0 / sqrt(vn)) * ψ[v] - state_dag = copy(state) - state_dag = replaceinds(dag(state_dag), inds(state_dag), dual_index_map(qf).(inds(state_dag))) - vertices_states = Dictionary([v_ket, v_bra], [state, state_dag]) - ψOψ_bpcs = update_factors.(ψOψ_bpcs, (vertices_states,)) - ψIψ_bpc = update_factors(ψIψ_bpc, vertices_states) - ψ[v] = state + g = underlying_graph(ψ) + + ℋ =model(g; model_params...) + ψψ = norm_sqr_network(ψ) + bpc = BeliefPropagationCache(ψψ, group(v->v[1], vertices(ψψ))) + bpc = update(bpc; bp_update_kwargs...) + L = length(vertices(ψ)) + println("Starting Imaginary Time Evolution") + β = 0 + for (i, period) in enumerate(dbetas) + nbetas, dβ = first(period), last(period) + println("Entering evolution period $i , β = $β, dβ = $dβ") + U = exp(- dβ * ℋ, alg = Trotter{1}()) + gates = Vector{ITensor}(U, s) + for i in 1:nbetas + for gate in gates + ψ, bpc = BP_apply(gate, ψ, bpc; apply_kwargs...) + end + β += dβ + bpc = update(bpc; bp_update_kwargs...) + end + e = sum(expect(ψ, ℋ; alg = "bp")) + println("Energy is $(e / L)") end - return ψ, ψIψ_bpc, ψOψ_bpcs + return ψ end diff --git a/src/caches/beliefpropagationcache.jl b/src/caches/beliefpropagationcache.jl index c77d4bbe..318d43df 100644 --- a/src/caches/beliefpropagationcache.jl +++ b/src/caches/beliefpropagationcache.jl @@ -344,19 +344,5 @@ function renormalize_messages(bp_cache::BeliefPropagationCache) return bp_cache end -function renormalize_factors(bp_cache::BeliefPropagationCache) - bp_cache = copy(bp_cache) - tn = tensornetwork(bp_cache) - for pv in partitionvertices(partitioned_tensornetwork(bp_cache)) - n = 1.0 / region_scalar(bp_cache, pv) - verts = vertices(bp_cache, pv) - v = first(first(verts)) - n = n ^(1/2) - fs = Dictionary([(v, "ket"), (v, "bra")], n.*factors(bp_cache, [(v, "ket"), (v, "bra")])) - bp_cache = update_factors(bp_cache, fs) - end - return bp_cache -end - From 275191a9a42325d90da7e6bb87ff28c63f7c3a8e Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 12 Jun 2024 11:39:54 -0400 Subject: [PATCH 13/27] Changes --- examples/dmrg.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/dmrg.jl b/examples/dmrg.jl index 3a4d016f..de2b22a1 100644 --- a/examples/dmrg.jl +++ b/examples/dmrg.jl @@ -34,16 +34,16 @@ Random.seed!(5634) function main() - g_str = "HeavyHex" + g_str = "Chain" pbc = true g = g_str == "Chain" ? named_grid((24,1); periodic = pbc) : heavy_hex_lattice_graph(2,2; periodic = pbc) g = renamer(g) save = false - chi =1 + chi =2 N = length(vertices(g)) g_mps = renamer(named_grid((N,1))) - h, hl = 1.05, 0.4 + h, hl = 0.6, 0.0 J = 1 s = siteinds("S=1/2",g_mps) @@ -65,7 +65,7 @@ function main() region_observer! = observer(sweep, region, energy) e, psifinal = dmrg( - H, psi0; nsweeps = 20, maxdim = chi, cutoff= 1e-14, nsites = 1, region_observer! + H, psi0; nsweeps = 10, maxdim = chi, cutoff= 1e-14, nsites = 1, region_observer! ) energies = (region_observer!.energy) / N @show last(energies) From 194fba329dbd5c3d10d17d791d5a46cb591f8330 Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 12 Jun 2024 16:05:11 -0400 Subject: [PATCH 14/27] working implementation --- examples/dmrg.jl | 85 --------- examples/imaginary_time_evo.jl | 34 ---- examples/utils.jl | 60 ------- src/beliefpropagationdmrg/bp_dmrg.jl | 169 +++++++----------- src/beliefpropagationdmrg/bp_extracter.jl | 80 +++++++-- src/beliefpropagationdmrg/bp_inserter.jl | 86 +++++++-- src/beliefpropagationdmrg/bp_updater.jl | 51 ++++-- src/beliefpropagationdmrg/graphsextensions.jl | 109 ----------- src/beliefpropagationdmrg/main.jl | 45 ++--- .../tensornetworkoperators.jl | 94 +++++----- src/beliefpropagationdmrg/utils.jl | 75 -------- .../alternating_update/alternating_update.jl | 19 +- .../alternating_update/region_update.jl | 23 ++- src/solvers/dmrg.jl | 19 +- src/solvers/extract/extract.jl | 2 +- src/solvers/insert/insert.jl | 53 ++++-- src/solvers/local_solvers/eigsolve.jl | 2 +- src/solvers/sweep_plans/sweep_plans.jl | 18 +- 18 files changed, 395 insertions(+), 629 deletions(-) delete mode 100644 examples/dmrg.jl delete mode 100644 examples/imaginary_time_evo.jl delete mode 100644 examples/utils.jl delete mode 100644 src/beliefpropagationdmrg/graphsextensions.jl delete mode 100644 src/beliefpropagationdmrg/utils.jl diff --git a/examples/dmrg.jl b/examples/dmrg.jl deleted file mode 100644 index de2b22a1..00000000 --- a/examples/dmrg.jl +++ /dev/null @@ -1,85 +0,0 @@ -using DataGraphs: edge_data, vertex_data -using Dictionaries: Dictionary -using Graphs: nv, vertices -using ITensorMPS: ITensorMPS -using ITensorNetworks: - AbstractITensorNetwork, - BeliefPropagationCache, - ITensorNetworks, - OpSum, - ttn, - apply, - dmrg, - inner, - mpo, - random_mps, - random_ttn, - linkdims, - siteinds, - random_tensornetwork, - maxlinkdim -using ITensorNetworks.ITensorsExtensions: replace_vertices -using ITensorNetworks.ModelHamiltonians: ModelHamiltonians -using ITensors: ITensors, ITensor, expect -using KrylovKit: eigsolve -using NamedGraphs.NamedGraphGenerators: named_comb_tree -using Observers: observer -using NamedGraphs.NamedGraphGenerators: named_grid - -using NPZ - -include("utils.jl") - -Random.seed!(5634) - -function main() - - g_str = "Chain" - pbc = true - g = g_str == "Chain" ? named_grid((24,1); periodic = pbc) : heavy_hex_lattice_graph(2,2; periodic = pbc) - g = renamer(g) - save = false - chi =2 - - N = length(vertices(g)) - g_mps = renamer(named_grid((N,1))) - h, hl = 0.6, 0.0 - J = 1 - s = siteinds("S=1/2",g_mps) - - os = OpSum() - for e in edges(g) - os += J, "Sz", src(e),"Sz",dst(e) - end - for v in vertices(g) - os += h, "Sx", v - os += hl, "Sz", v - end - - H = ttn(os, s) - - psi0 = ttn(random_tensornetwork(s; link_space = chi)) - sweep(; which_sweep, kw...) = which_sweep - energy(; eigvals, kw...) = eigvals[1] - region(; which_region_update, sweep_plan, kw...) = first(sweep_plan[which_region_update]) - region_observer! = observer(sweep, region, energy) - - e, psifinal = dmrg( - H, psi0; nsweeps = 10, maxdim = chi, cutoff= 1e-14, nsites = 1, region_observer! - ) - energies = (region_observer!.energy) / N - @show last(energies) - @show maxlinkdim(psifinal) - - final_mags = expect(psifinal, "Z") - file_name = "/Users/jtindall/Files/Data/DMRG/"*g_str*"ISINGL$(N)h$(h)hl$(hl)chi$(chi)" - if pbc - file_name *= "PBC" - end - if save - npzwrite(file_name*".npz", energies = energies, final_mags = final_mags) - end - -end - -main() \ No newline at end of file diff --git a/examples/imaginary_time_evo.jl b/examples/imaginary_time_evo.jl deleted file mode 100644 index 59d48c8a..00000000 --- a/examples/imaginary_time_evo.jl +++ /dev/null @@ -1,34 +0,0 @@ - -using ITensors: Trotter -using ITensorNetworks: norm_sqr_network, update -using SplitApplyCombine: group - -function imaginary_time_evo(s::IndsNetwork, ψ::ITensorNetwork, model::Function, dbetas::Vector{<:Tuple}, nbetas::Int64; model_params, - bp_update_kwargs = (; maxiter = 10, tol = 1e-10), apply_kwargs = (; cutoff = 1e-12, maxdim = 10)) - ψ = copy(ψ) - g = underlying_graph(ψ) - - ℋ =model(g; model_params...) - ψψ = norm_sqr_network(ψ) - bpc = BeliefPropagationCache(ψψ, group(v->v[1], vertices(ψψ))) - bpc = update(bpc; bp_update_kwargs...) - println("Starting Imaginary Time Evolution") - β = 0 - for (i, period) in enumerate(dbetas) - nbetas, dβ = first(period), last(period) - println("Entering evolution period $i , β = $β, dβ = $dβ") - U = exp(- dβ * ℋ, alg = Trotter{1}()) - gates = Vector{ITensor}(U, s) - for i in 1:nbetas - for gate in gates - ψ, bpc = BP_apply(gate, ψ, bpc; apply_kwargs...) - end - β += dβ - bpc = update(bpc; bp_update_kwargs...) - end - e = sum(expect(ψ, ℋ; alg = "bp")) - println("Energy is $e") - end - - return ψ -end \ No newline at end of file diff --git a/examples/utils.jl b/examples/utils.jl deleted file mode 100644 index c00a04db..00000000 --- a/examples/utils.jl +++ /dev/null @@ -1,60 +0,0 @@ -using ITensors: siteinds, Op, prime, OpSum, apply -using Graphs: AbstractGraph, SimpleGraph, edges, vertices, is_tree, connected_components -using NamedGraphs: NamedGraph, NamedEdge, NamedGraphs, rename_vertices -using NamedGraphs.NamedGraphGenerators: named_grid, named_hexagonal_lattice_graph -using NamedGraphs.GraphsExtensions: decorate_graph_edges, forest_cover, add_edges, rem_edges, add_vertices, rem_vertices, disjoint_union, subgraph, src, dst -using NamedGraphs.PartitionedGraphs: PartitionVertex, partitionedge, unpartitioned_graph -using ITensorNetworks: BeliefPropagationCache, AbstractITensorNetwork, AbstractFormNetwork, IndsNetwork, ITensorNetwork, insert_linkinds, ttn, union_all_inds, - neighbor_vertices, environment, messages, update_factor, message, partitioned_tensornetwork, bra_vertex, ket_vertex, operator_vertex, default_cache_update_kwargs, - dual_index_map -using DataGraphs: underlying_graph -using ITensorNetworks.ModelHamiltonians: heisenberg -using ITensors: ITensor, noprime, dag, noncommonind, commonind, replaceind, dim, noncommoninds, delta, replaceinds -using ITensors.NDTensors: denseblocks -using Dictionaries: set! - -function BP_apply(o::ITensor, ψ::AbstractITensorNetwork, bpc::BeliefPropagationCache; apply_kwargs...) - bpc = copy(bpc) - ψ = copy(ψ) - vs = neighbor_vertices(ψ, o) - envs = environment(bpc, PartitionVertex.(vs)) - singular_values! = Ref(ITensor()) - ψ = noprime(apply(o, ψ; envs, singular_values!, normalize=true, apply_kwargs...)) - ψdag = prime(dag(ψ); sites=[]) - if length(vs) == 2 - v1, v2 = vs - pe = partitionedge(bpc, (v1, "bra") => (v2, "bra")) - mts = messages(bpc) - ind1, ind2 = noncommonind(singular_values![], ψ[v1]), commonind(singular_values![], ψ[v1]) - singular_values![] = denseblocks(replaceind(singular_values![], ind1, ind2')) - set!(mts, pe, ITensor[singular_values![]]) - set!(mts, reverse(pe), ITensor[singular_values![]]) - end - for v in vs - bpc = update_factor(bpc, (v, "ket"), ψ[v]) - bpc = update_factor(bpc, (v, "bra"), ψdag[v]) - end - return ψ, bpc -end - -function smallest_eigvalue(A::AbstractITensorNetwork) - out = reduce(*, [A[v] for v in vertices(A)]) - out = out * combiner(inds(out; plev = 0)) *combiner(inds(out; plev = 1)) - out = array(out) - return minimum(real.(eigvals(out))) -end - -function heavy_hex_lattice_graph(n::Int64, m::Int64; periodic) - """Create heavy-hex lattice geometry""" - g = named_hexagonal_lattice_graph(n, m; periodic) - g = decorate_graph_edges(g) - return g -end - -function renamer(g) - vertex_rename = Dictionary() - for (i,v) in enumerate(vertices(g)) - set!(vertex_rename, v, (i,)) - end - return rename_vertices(v -> vertex_rename[v], g) -end \ No newline at end of file diff --git a/src/beliefpropagationdmrg/bp_dmrg.jl b/src/beliefpropagationdmrg/bp_dmrg.jl index 389f4022..1910c0fa 100644 --- a/src/beliefpropagationdmrg/bp_dmrg.jl +++ b/src/beliefpropagationdmrg/bp_dmrg.jl @@ -1,6 +1,12 @@ using NamedGraphs.GraphsExtensions: is_tree using NamedGraphs.PartitionedGraphs: partitionvertices, partitionedges, PartitionEdge -using ITensorNetworks: ITensorNetwork, QuadraticFormNetwork, BeliefPropagationCache, update, default_message_update +using ITensorNetworks: + ITensorNetwork, + QuadraticFormNetwork, + BeliefPropagationCache, + update, + default_message_update, + delete_messages using ITensors: scalar include("utils.jl") @@ -9,116 +15,65 @@ include("bp_inserter.jl") include("bp_updater.jl") include("graphsextensions.jl") -default_bp_update_kwargs(ψ::ITensorNetwork) = is_tree(ψ) ? (;) : (; maxiter = 50, tol = 1e-14) +default_bp_update_kwargs(ψ::ITensorNetwork) = is_tree(ψ) ? (;) : (; maxiter=20, tol=1e-6) -message_update_f = tns -> default_message_update(tns; normalize = false) +function initialize_caches( + ψ_init::ITensorNetwork, + operators::Vector{ITensorNetwork}; + cache_update_kwargs=default_bp_update_kwargs(ψ_init), +) + ψ = copy(ψ_init) + ψIψ = QuadraticFormNetwork(ψ) + ψIψ_bpc = BeliefPropagationCache(ψIψ) -function initialize_caches(ψ_init::ITensorNetwork, operators::Vector{ITensorNetwork}; cache_update_kwargs = default_bp_update_kwargs(ψ_init)) - ψ = copy(ψ_init) - ψIψ = QuadraticFormNetwork(ψ) - ψIψ_bpc = BeliefPropagationCache(ψIψ) - - ψOψs = QuadraticFormNetwork[QuadraticFormNetwork(operator, ψ) for operator in operators] - ψOψ_bpcs = BeliefPropagationCache[BeliefPropagationCache(ψOψ) for ψOψ in ψOψs] - return (ψ, ψIψ_bpc, ψOψ_bpcs) + ψOψs = QuadraticFormNetwork[QuadraticFormNetwork(operator, ψ) for operator in operators] + ψOψ_bpcs = BeliefPropagationCache[BeliefPropagationCache(ψOψ) for ψOψ in ψOψs] + return (ψ, ψOψ_bpcs, ψIψ_bpc) end -function reduced_bp(state::ITensorNetwork, operators::Vector{ITensorNetwork}, ψIψ_bpc::BeliefPropagationCache, - ψOψ_bpcs::Vector{<:BeliefPropagationCache}, v) - - ψIψ_bpc_mts = messages(ψIψ_bpc) - new_ψOψ_bpcs = BeliefPropagationCache[] - - for (ψOψ_bpc, operator) in zip(ψOψ_bpcs, operators) - new_ψOψ_bpc = copy(ψOψ_bpc) - ptn = partitioned_tensornetwork(new_ψOψ_bpc) - edge_seq = post_order_dfs_edges(underlying_graph(operator), v) - broken_edges = setdiff(edges(state), edges(operator)) - partition_broken_edges = PartitionEdge.(broken_edges) - partition_broken_edges = vcat(partition_broken_edges, reverse.(partition_broken_edges)) - mts = messages(new_ψOψ_bpc) - for pe in partition_broken_edges - set!(mts, pe, copy(ψIψ_bpc_mts[pe])) - end - partition_edge_seq = PartitionEdge.(edge_seq) - new_ψOψ_bpc = update(new_ψOψ_bpc, partition_edge_seq; message_update = message_update_f) - push!(new_ψOψ_bpcs, new_ψOψ_bpc) - end - - return state, new_ψOψ_bpcs, ψIψ_bpc -end - -function updater(ψ::ITensorNetwork, ψIψ_bpc::BeliefPropagationCache, ψOψ_bpcs::Vector{<:BeliefPropagationCache}; - cache_update_kwargs) - - ψ = copy(ψ) - ψOψ_bpcs = copy.(ψOψ_bpcs) - ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) - ψIψ_bpc = renormalize_messages(ψIψ_bpc) - qf = tensornetwork(ψIψ_bpc) - - for v in vertices(ψ) - v_ket, v_bra = ket_vertex(qf, v), bra_vertex(qf, v) - pv = only(partitionvertices(ψIψ_bpc, [v_ket])) - vn = region_scalar(ψIψ_bpc, pv) - state = (1.0 / sqrt(vn)) * ψ[v] - state_dag = copy(state) - state_dag = replaceinds(dag(state_dag), inds(state_dag), dual_index_map(qf).(inds(state_dag))) - vertices_states = Dictionary([v_ket, v_bra], [state, state_dag]) - ψOψ_bpcs = update_factors.(ψOψ_bpcs, (vertices_states,)) - ψIψ_bpc = update_factors(ψIψ_bpc, vertices_states) - ψ[v] = state - end - - return ψ, ψIψ_bpc, ψOψ_bpcs -end - - -function bp_dmrg(ψ_init::ITensorNetwork, operators::Vector; no_sweeps = 1, bp_update_kwargs = default_bp_update_kwargs(ψ_init), - vertex_order_func = ψ -> bp_region_plan(ψ; nsites = 1, add_additional_traversal = false), energy_calc_fun) - - L = length(vertices(ψ_init)) - state, ψIψ_bpc, ψOψ_bpcs = initialize_caches(ψ_init, operators) - regions = vertex_order_func(state) - - state, ψIψ_bpc, ψOψ_bpcs = updater(state, ψIψ_bpc, ψOψ_bpcs; cache_update_kwargs = bp_update_kwargs) - - energy = real(energy_calc_fun(state, ψIψ_bpc)) - println("Initial energy density is $(energy)") - energies = [energy] - - for i in 1:no_sweeps - println("Beginning sweep $i") - for region in regions - println("Updating vertex $region") - - v = only(region) - #v = rand(vertices()) - #TODO: Do BP on ψOψs but default the messages to be incoming to that region to be those from ψIψ_bpc - state, ψOψ_bpcs, ψIψ_bpc = reduced_bp(state, operators, ψIψ_bpc, ψOψ_bpcs, v) - - local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts = bp_extracter(state, ψOψ_bpcs, ψIψ_bpc, region) - - #Do an eigsolve - local_state, energy = bp_eigsolve_updater(local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts, last(energies); L) - - state, ψOψ_bpcs, ψIψ_bpc = bp_inserter(state, ψOψ_bpcs, ψIψ_bpc, local_state, region) - - state, ψIψ_bpc, ψOψ_bpcs = updater(state, ψIψ_bpc, ψOψ_bpcs; cache_update_kwargs = bp_update_kwargs) - - # if energy < last(energies) - # println("Current energy density is $(energy / L)") - # append!(energies, energy) - # else - # println("Rejected Move") - # end - - - energy = energy_calc_fun(state, ψIψ_bpc) - append!(energies, energy) - println("Current energy density is $(energy)") - end +function bp_dmrg( + ψ_init::ITensorNetwork, + operators::Vector{<:ITensorNetwork}; + nsites=1, + no_sweeps=1, + bp_update_kwargs=default_bp_update_kwargs(ψ_init), + energy_calc_fun, +) + L = length(vertices(ψ_init)) + state, ψOψ_bpcs, ψIψ_bpc = initialize_caches(ψ_init, operators) + state_vertices = collect(vertices(state)) + regions = [[v] for v in vcat(state_vertices, reverse(state_vertices))] + + state, ψOψ_bpcs, ψIψ_bpc = renormalize_update_norm_cache( + state, ψOψ_bpcs, ψIψ_bpc; cache_update_kwargs=bp_update_kwargs + ) + + energy = real(energy_calc_fun(state, ψIψ_bpc)) + println("Initial energy density is $(energy)") + energies = [energy] + + for i in 1:no_sweeps + println("Beginning sweep $i") + for region in regions + println("Updating vertex $region") + + local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts = bp_extracter( + state, ψOψ_bpcs, ψIψ_bpc, region + ) + + local_state, energy = bp_eigsolve_updater( + local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts + ) + + state, ψOψ_bpcs, ψIψ_bpc = bp_inserter( + state, ψOψ_bpcs, ψIψ_bpc, local_state, region; bp_update_kwargs + ) + + energy = energy_calc_fun(state, ψIψ_bpc) + append!(energies, energy) + println("Current energy density is $(energy)") end + end - return state, energies + return state, energies end diff --git a/src/beliefpropagationdmrg/bp_extracter.jl b/src/beliefpropagationdmrg/bp_extracter.jl index 5a3f0c08..910f2519 100644 --- a/src/beliefpropagationdmrg/bp_extracter.jl +++ b/src/beliefpropagationdmrg/bp_extracter.jl @@ -1,21 +1,71 @@ using ITensors: scalartype -using ITensorNetworks: ket_vertices, bra_vertices, tensornetwork +using ITensorNetworks: + ket_vertices, bra_vertices, tensornetwork, default_message_update, operator_network using ITensorNetworks.ITensorsExtensions: map_eigvals +function update_caches_effective_environments( + state::ITensorNetwork, + ψOψ_bpcs::Vector{<:BeliefPropagationCache}, + ψIψ_bpc::BeliefPropagationCache, + region, +) + operators = operator_network.(tensornetwork.(ψOψ_bpcs)) -function bp_extracter(ψ::AbstractITensorNetwork, ψOψ_bpcs::Vector{<:BeliefPropagationCache}, ψIψ_bpc::BeliefPropagationCache, region; - regularization = 10*eps(scalartype(ψ)), ishermitian = true) + ψIψ_bpc_mts = messages(ψIψ_bpc) + new_ψOψ_bpcs = BeliefPropagationCache[] - form_network = tensornetwork(ψIψ_bpc) - form_ket_vertices, form_bra_vertices = ket_vertices(form_network, region), bra_vertices(form_network, region) + for (ψOψ_bpc, operator) in zip(ψOψ_bpcs, operators) + new_ψOψ_bpc = copy(ψOψ_bpc) + ptn = partitioned_tensornetwork(new_ψOψ_bpc) + edge_seq = reduce( + vcat, [post_order_dfs_edges(underlying_graph(operator), v) for v in region] + ) + broken_edges = setdiff(edges(state), edges(operator)) + partition_broken_edges = PartitionEdge.(broken_edges) + partition_broken_edges = vcat(partition_broken_edges, reverse.(partition_broken_edges)) + mts = messages(new_ψOψ_bpc) + for pe in partition_broken_edges + set!(mts, pe, copy(ψIψ_bpc_mts[pe])) + end + partition_edge_seq = unique(PartitionEdge.(edge_seq)) + new_ψOψ_bpc = update( + new_ψOψ_bpc, + partition_edge_seq; + message_update=tns -> default_message_update(tns; normalize=false), + ) + push!(new_ψOψ_bpcs, new_ψOψ_bpc) + end - ∂ψOψ_bpc_∂rs = environment.(ψOψ_bpcs, ([form_ket_vertices; form_bra_vertices], )) - state = prod(ψ[v] for v in region) - messages = environment(ψIψ_bpc, partitionvertices(ψIψ_bpc, form_ket_vertices)) - f_sqrt = sqrt ∘ (x -> x + regularization) - f_inv_sqrt = inv ∘ sqrt ∘ (x -> x + regularization) - sqrt_mts = map_eigvals.((f_sqrt, ), messages, first.(inds.(messages)), last.(inds.(messages)); ishermitian) - inv_sqrt_mts = map_eigvals.((f_inv_sqrt, ), messages, first.(inds.(messages)), last.(inds.(messages)); ishermitian) - - return state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts - end \ No newline at end of file + return state, new_ψOψ_bpcs, ψIψ_bpc +end + +function bp_extracter( + ψ::AbstractITensorNetwork, + ψOψ_bpcs::Vector{<:BeliefPropagationCache}, + ψIψ_bpc::BeliefPropagationCache, + region; + regularization=10 * eps(scalartype(ψ)), + ishermitian=true, +) + ψ, ψOψ_bpcs, ψIψ_bpc = update_caches_effective_environments(ψ, ψOψ_bpcs, ψIψ_bpc, region) + + form_network = tensornetwork(ψIψ_bpc) + form_ket_vertices, form_bra_vertices = ket_vertices(form_network, region), + bra_vertices(form_network, region) + + ∂ψOψ_bpc_∂rs = environment.(ψOψ_bpcs, ([form_ket_vertices; form_bra_vertices],)) + state = prod([ψ[v] for v in region]) + messages = environment(ψIψ_bpc, partitionvertices(ψIψ_bpc, form_ket_vertices)) + f_sqrt = sqrt ∘ (x -> x + regularization) + f_inv_sqrt = inv ∘ sqrt ∘ (x -> x + regularization) + sqrt_mts = + map_eigvals.( + (f_sqrt,), messages, first.(inds.(messages)), last.(inds.(messages)); ishermitian + ) + inv_sqrt_mts = + map_eigvals.( + (f_inv_sqrt,), messages, first.(inds.(messages)), last.(inds.(messages)); ishermitian + ) + + return state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts +end diff --git a/src/beliefpropagationdmrg/bp_inserter.jl b/src/beliefpropagationdmrg/bp_inserter.jl index 19f27587..56b08917 100644 --- a/src/beliefpropagationdmrg/bp_inserter.jl +++ b/src/beliefpropagationdmrg/bp_inserter.jl @@ -1,22 +1,74 @@ -using ITensorNetworks: update_factors +using ITensorNetworks: update_factors, edge_tag +using ITensors: uniqueinds, factorize_svd, factorize +using LinearAlgebra: norm -#TODO: Add support for nsites = 2 -function bp_inserter(ψ::AbstractITensorNetwork, ψOψ_bpcs::Vector{<:BeliefPropagationCache}, - ψIψ_bpc::BeliefPropagationCache, state::ITensor, region; nsites::Int64 = 1, kwargs...) +function renormalize_update_norm_cache( + ψ::ITensorNetwork, + ψOψ_bpcs::Vector{<:BeliefPropagationCache}, + ψIψ_bpc::BeliefPropagationCache; + cache_update_kwargs, +) + ψ = copy(ψ) + ψIψ_bpc = delete_messages(ψIψ_bpc) + ψOψ_bpcs = delete_messages.(ψOψ_bpcs) + ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) + ψIψ_bpc = renormalize_messages(ψIψ_bpc) + qf = tensornetwork(ψIψ_bpc) + + for v in vertices(ψ) + v_ket, v_bra = ket_vertex(qf, v), bra_vertex(qf, v) + pv = only(partitionvertices(ψIψ_bpc, [v_ket])) + vn = region_scalar(ψIψ_bpc, pv) + state = (1.0 / sqrt(vn)) * ψ[v] + state_dag = copy(dag(state)) + state_dag = replaceinds( + state_dag, inds(state_dag), dual_index_map(qf).(inds(state_dag)) + ) + vertices_states = Dictionary([v_ket, v_bra], [state, state_dag]) + ψOψ_bpcs = update_factors.(ψOψ_bpcs, (vertices_states,)) + ψIψ_bpc = update_factors(ψIψ_bpc, vertices_states) + ψ[v] = state + end + + return ψ, ψOψ_bpcs, ψIψ_bpc +end - ψ = copy(ψ) - form_network = tensornetwork(ψIψ_bpc) +#TODO: Add support for nsites = 2 +function bp_inserter( + ψ::AbstractITensorNetwork, + ψOψ_bpcs::Vector{<:BeliefPropagationCache}, + ψIψ_bpc::BeliefPropagationCache, + state::ITensor, + region; + nsites::Int64=1, + bp_update_kwargs, + kwargs..., +) + ψ = copy(ψ) + form_network = tensornetwork(ψIψ_bpc) + if length(region) == 1 states = ITensor[state] + else + error("Region lengths of more than 1 not supported for now") + end + + for (state, v) in zip(states, region) + ψ[v] = state + state_dag = copy(ψ[v]) + state_dag = replaceinds( + dag(state_dag), inds(state_dag), dual_index_map(form_network).(inds(state_dag)) + ) + form_bra_v, form_op_v, form_ket_v = bra_vertex(form_network, v), + operator_vertex(form_network, v), + ket_vertex(form_network, v) + vertices_states = Dictionary([form_ket_v, form_bra_v], [state, state_dag]) + ψOψ_bpcs = update_factors.(ψOψ_bpcs, (vertices_states,)) + ψIψ_bpc = update_factors(ψIψ_bpc, vertices_states) + end - for (state, v) in zip(states, region) - ψ[v] = state - state_dag = copy(ψ[v]) - state_dag = replaceinds(dag(state_dag), inds(state_dag), dual_index_map(form_network).(inds(state_dag))) - form_bra_v, form_op_v, form_ket_v = bra_vertex(form_network, v), operator_vertex(form_network, v), ket_vertex(form_network, v) - vertices_states = Dictionary([form_ket_v, form_bra_v], [state, state_dag]) - ψOψ_bpcs = update_factors.(ψOψ_bpcs, (vertices_states,)) - ψIψ_bpc = update_factors(ψIψ_bpc, vertices_states) - end + ψ, ψOψ_bpcs, ψIψ_bpc = renormalize_update_norm_cache( + ψ, ψOψ_bpcs, ψIψ_bpc; cache_update_kwargs=bp_update_kwargs + ) - return ψ, ψOψ_bpcs, ψIψ_bpc -end \ No newline at end of file + return ψ, ψOψ_bpcs, ψIψ_bpc +end diff --git a/src/beliefpropagationdmrg/bp_updater.jl b/src/beliefpropagationdmrg/bp_updater.jl index 272edfc0..1287601d 100644 --- a/src/beliefpropagationdmrg/bp_updater.jl +++ b/src/beliefpropagationdmrg/bp_updater.jl @@ -2,26 +2,45 @@ using ITensors: contract using ITensors.ContractionSequenceOptimization: optimal_contraction_sequence using KrylovKit: eigsolve -default_krylov_kwargs() = (; tol = 1e-14, maxiter = 1, verbosity = 0, eager = false, ishermitian = true) +function default_krylov_kwargs() + return (; tol=1e-14, krylovdim=10, maxiter=1, verbosity=0, eager=false, ishermitian=true) +end #TODO: Put inv_sqrt_mts onto ∂ψOψ_bpc_∂r beforehand. Need to do this in an efficient way without #precontracting ∂ψOψ_bpc_∂r and getting the index logic too messy -function get_new_state(∂ψOψ_bpc_∂rs::Vector, inv_sqrt_mts, sqrt_mts, state::ITensor; sequences = ["automatic" for i in length(∂ψOψ_bpc_∂rs)]) +function get_new_state( + ∂ψOψ_bpc_∂rs::Vector, + inv_sqrt_mts, + sqrt_mts, + state::ITensor; + sequences=["automatic" for i in length(∂ψOψ_bpc_∂rs)], +) state = noprime(contract([state; inv_sqrt_mts])) - states = ITensor[dag(noprime(contract([copy(state); ∂ψOψ_bpc_∂r]; sequence))) for (∂ψOψ_bpc_∂r, sequence) in zip(∂ψOψ_bpc_∂rs, sequences)] + states = ITensor[ + noprime(contract([copy(state); ∂ψOψ_bpc_∂r]; sequence)) for + (∂ψOψ_bpc_∂r, sequence) in zip(∂ψOψ_bpc_∂rs, sequences) + ] state = reduce(+, states) - return noprime(contract([state; (inv_sqrt_mts)])) + return dag(noprime(contract([state; (inv_sqrt_mts)]))) end -function bp_eigsolve_updater(init::ITensor, ∂ψOψ_bpc_∂rs::Vector, sqrt_mts, inv_sqrt_mts, previous_energy; L, krylov_kwargs = default_krylov_kwargs()) - - gauged_init = noprime(contract([copy(init); sqrt_mts])) - sequences = [optimal_contraction_sequence([gauged_init; ∂ψOψ_bpc_∂r]) for ∂ψOψ_bpc_∂r in ∂ψOψ_bpc_∂rs] - get_new_state_ = state -> get_new_state(∂ψOψ_bpc_∂rs, inv_sqrt_mts, sqrt_mts, state; sequences) - howmany = 1 - - vals, vecs, info = eigsolve(get_new_state_,gauged_init,howmany,:SR; krylov_kwargs...) - state = noprime(contract([first(vecs); inv_sqrt_mts])) - - return state, first(vals) -end \ No newline at end of file +function bp_eigsolve_updater( + init::ITensor, + ∂ψOψ_bpc_∂rs::Vector, + sqrt_mts, + inv_sqrt_mts; + krylov_kwargs=default_krylov_kwargs(), +) + gauged_init = noprime(contract([copy(init); sqrt_mts])) + sequences = [ + optimal_contraction_sequence([gauged_init; ∂ψOψ_bpc_∂r]) for ∂ψOψ_bpc_∂r in ∂ψOψ_bpc_∂rs + ] + get_new_state_ = + state -> get_new_state(∂ψOψ_bpc_∂rs, inv_sqrt_mts, sqrt_mts, state; sequences) + howmany = 1 + + vals, vecs, info = eigsolve(get_new_state_, gauged_init, howmany, :SR; krylov_kwargs...) + state = noprime(contract([first(vecs); inv_sqrt_mts])) + + return state, first(vals) +end diff --git a/src/beliefpropagationdmrg/graphsextensions.jl b/src/beliefpropagationdmrg/graphsextensions.jl deleted file mode 100644 index 97c467fa..00000000 --- a/src/beliefpropagationdmrg/graphsextensions.jl +++ /dev/null @@ -1,109 +0,0 @@ -using Graphs: AbstractGraph -using NamedGraphs.GraphsExtensions: a_star, add_edge!, dfs_tree, post_order_dfs_edges -using NamedGraphs.GraphsExtensions: default_root_vertex, degree, degrees, neighbors, edgetype, rem_edge!, vertextype - -#Given a graph, traverse it from start vertex to end vertex, covering each edge exactly once. -#Complexity is O(length(edges(g))) -function eulerian_path(g::AbstractGraph, start_vertex, end_vertex) - #Conditions on g for the required path to exist - if start_vertex != end_vertex - @assert isodd(degree(g, start_vertex) % 2) - @assert isodd(degree(g, end_vertex) % 2) - @assert all(x -> iseven(x), degrees(g, setdiff(vertices(g), [start_vertex, end_vertex]))) - else - @assert all(x -> iseven(x), degrees(g)) - end - - path = vertextype(g)[] - stack = vertextype(g)[] - current_vertex = end_vertex - g_modified = copy(g) - while !isempty(stack) || !iszero(degree(g_modified, current_vertex)) - if iszero(degree(g_modified, current_vertex)) - push!(path, current_vertex) - last_vertex = pop!(stack) - current_vertex = last_vertex - else - push!(stack, current_vertex) - vn = first(neighbors(g_modified, current_vertex)) - rem_edge!(g_modified, edgetype(g_modified)(current_vertex, vn)) - current_vertex = vn - end - end - - push!(path, current_vertex) - - return edgetype(g_modified)[edgetype(g_modified)(path[i], path[i+1]) for i in 1:(length(path) - 1)] -end - -eulerian_cycle(g::AbstractGraph, start_vertex) = eulerian_path(g, start_vertex, start_vertex) - -function make_all_degrees_even(g::AbstractGraph) - g_modified = copy(g) - vertices_odd_degree = collect(filter(v -> isodd(degree(g, v)), vertices(g_modified))) - while !isempty(vertices_odd_degree) - vertex_pairs = [(vertices_odd_degree[i], vertices_odd_degree[j]) for i in 1:length(vertices_odd_degree) for j in (i+1):length(vertices_odd_degree)] - vertex_pair = first(sort(vertex_pairs; by = vp -> length(a_star(g, vp...)))) - add_edge!(g_modified, edgetype(g_modified)(vertex_pair...)) - vertices_odd_degree = filter(v -> v != first(vertex_pair) && v != last(vertex_pair), vertices_odd_degree) - end - return g_modified -end - -#Given a graph, traverse it in a cycle from start_vertex and try to minimise the number of edges traversed more than once -function _eulerian_cycle(g::AbstractGraph, start_vertex; add_additional_traversal = false) - g_modified = make_all_degrees_even(g::AbstractGraph) - path = eulerian_cycle(g_modified, start_vertex) - - !add_additional_traversal && return path - - modified_path = edgetype(g_modified)[] - - for e in path - if src(e) ∉ neighbors(g, dst(e)) - inner_path = a_star(g, src(e), dst(e)) - append!(modified_path, inner_path) - else - push!(modified_path, e) - end - end - - return modified_path -end - -function _bp_region_plan(g::AbstractGraph, start_vertex = default_root_vertex(g); nsites::Int = 1, add_additional_traversal = false) - path = _eulerian_cycle(g, start_vertex; add_additional_traversal) - if nsites == 1 - regions = [[v] for v in vcat(src.(path))] - @assert all( v -> only(v) ∈ vertices(g), regions) - return vcat(regions, reverse(regions)) - else - regions = filter(e -> e ∈ edges(g) || reverse(e) ∈ edges(g), path) - @assert all(e -> e ∈ regions || reverse(e) ∈ regions, edges(g)) - return regions - end -end - -function path_to_path(path) - verts = [] - for e in path - if isempty(verts) || src(e) ≠ last(verts) - push!(verts, src(e)) - push!(verts, dst(e)) - end - end - return [[v] for v in verts] -end - -function bp_region_plan(g::AbstractGraph, start_vertex = default_root_vertex(g); nsites::Int = 1, add_additional_traversal = false) - path = post_order_dfs_edges(g, start_vertex) - if nsites == 1 - regions = path_to_path(path) - @assert all( v -> only(v) ∈ vertices(g), regions) - return vcat(regions, reverse(regions)) - else - regions = filter(e -> e ∈ edges(g) || reverse(e) ∈ edges(g), path) - @assert all(e -> e ∈ regions || reverse(e) ∈ regions, edges(g)) - return regions - end -end \ No newline at end of file diff --git a/src/beliefpropagationdmrg/main.jl b/src/beliefpropagationdmrg/main.jl index f7a27edd..98b7fca1 100644 --- a/src/beliefpropagationdmrg/main.jl +++ b/src/beliefpropagationdmrg/main.jl @@ -11,32 +11,23 @@ include("bp_dmrg.jl") Random.seed!(5634) function main() - g_str = "Chain" - g = g_str == "Chain" ? named_grid((24,1); periodic = true) : heavy_hex_lattice_graph(2,2; periodic = true) - g = renamer(g) - save = true - L = length(vertices(g)) - h, hl, J = 0.6, 0.0, 1.0 - s = siteinds("S=1/2", g) - χ = 2 - dbetas = [(10, 0.5), (10, 0.25), (20, 0.1)] - ψ0 = ITensorNetwork(v -> "↑", s) - ψ0 = imaginary_time_evo(s, ψ0, ising, dbetas; model_params = (; h, hl, J1 = J) ,bp_update_kwargs = (; maxiter = 10, tol = 1e-10), apply_kwargs = (; cutoff = 1e-12, maxdim = χ)) - #ψ0 = random_tensornetwork(s; link_space = χ) - - H = ising(s; h, hl, J1 = J) - tnos = opsum_to_tno(s, H) - - energy_calc_fun = (tn, bp_cache) -> sum(expect(tn, H; alg = "bp", (cache!) = Ref(bp_cache)))/L - - ψfinal, energies = bp_dmrg(ψ0, tnos; no_sweeps = 5, energy_calc_fun) - final_mags = expect(ψfinal, "Z", ; alg = "bp") - @show final_mags - if save - npzwrite("/Users/jtindall/Files/Data/BPDMRG/"*g_str*"ISINGL$(L)h$(h)hl$(hl)chi$(χ).npz", energies = energies, final_mags = final_mags) - end - + g = named_grid((24, 1); periodic=true) + g = renamer(g) + save = true + L = length(vertices(g)) + h, hl, J = 0.6, 0.2, 1.0 + s = siteinds("S=1/2", g) + χ = 2 + ψ0 = random_tensornetwork(s; link_space=χ) + + H = ising(s; h, hl, J1=J) + tnos = opsum_to_tno(s, H) + + energy_calc_fun = + (tn, bp_cache) -> sum(expect(tn, H; alg="bp", (cache!)=Ref(bp_cache))) / L + + ψfinal, energies = bp_dmrg(ψ0, tnos; no_sweeps=5, energy_calc_fun) + return final_mags = expect(ψfinal, "Z", ; alg="bp") end - -main() \ No newline at end of file +main() diff --git a/src/beliefpropagationdmrg/tensornetworkoperators.jl b/src/beliefpropagationdmrg/tensornetworkoperators.jl index bb4f2d90..de0da690 100644 --- a/src/beliefpropagationdmrg/tensornetworkoperators.jl +++ b/src/beliefpropagationdmrg/tensornetworkoperators.jl @@ -1,56 +1,70 @@ using NamedGraphs: NamedGraph, AbstractGraph, vertices, edges, NamedEdge using NamedGraphs.NamedGraphGenerators: named_grid, named_hexagonal_lattice_graph -using NamedGraphs.GraphsExtensions: forest_cover, connected_components, add_edges, add_edge, add_vertices, rem_edges, decorate_graph_edges, rename_vertices +using NamedGraphs.GraphsExtensions: + forest_cover, + connected_components, + add_edges, + add_edge, + add_vertices, + rem_edges, + decorate_graph_edges, + rename_vertices using ITensors: OpSum, siteinds, sites, inds, combiner using ITensors.NDTensors: array -using ITensorNetworks: AbstractITensorNetwork, ITensorNetwork, IndsNetwork, underlying_graph, ttn, maxlinkdim +using ITensorNetworks: + AbstractITensorNetwork, ITensorNetwork, IndsNetwork, underlying_graph, ttn, maxlinkdim using ITensorNetworks.ModelHamiltonians: ising using Dictionaries using LinearAlgebra: eigvals function connect_forests(s::IndsNetwork) - g = underlying_graph(s) - fs = forest_cover(g) - fs_connected = Tuple{IndsNetwork, Vector{NamedEdge}}[] - for f in fs - s_f = copy(s) - verts = vertices(f) - es = edges(f) - c_f = NamedGraph[f[vs] for vs in connected_components(f)] - dummy_es = NamedEdge[NamedEdge(first(vertices(c_f[i])) => first(vertices(c_f[i+1]))) for i in 1:(length(c_f) - 1)] - s_f = rem_edges(s_f, edges(s_f)) - s_f = add_edges(s_f, vcat(es, dummy_es)) - push!(fs_connected, (s_f, dummy_es)) - end - return fs_connected + g = underlying_graph(s) + fs = forest_cover(g) + fs_connected = Tuple{IndsNetwork,Vector{NamedEdge}}[] + for f in fs + s_f = copy(s) + verts = vertices(f) + es = edges(f) + c_f = NamedGraph[f[vs] for vs in connected_components(f)] + dummy_es = NamedEdge[ + NamedEdge(first(vertices(c_f[i])) => first(vertices(c_f[i + 1]))) for + i in 1:(length(c_f) - 1) + ] + s_f = rem_edges(s_f, edges(s_f)) + s_f = add_edges(s_f, vcat(es, dummy_es)) + push!(fs_connected, (s_f, dummy_es)) + end + return fs_connected end -function opsum_to_tno(s::IndsNetwork, H::OpSum; cutoff::Float64 = 1e-14, insert_dummy_inds = false) - s_fs_connected = connect_forests(s) - no_forests = length(s_fs_connected) - tnos = ITensorNetwork[] - for (s_f, dummy_edges) in s_fs_connected - real_es = setdiff(edges(s_f), dummy_edges) - new_opsum = OpSum() - for term in H - if length(sites(term)) == 1 && !iszero(first(term.args)) - new_opsum += (1.0 / no_forests) * term - elseif length(sites(term)) == 2 && !iszero(first(term.args)) - e = NamedEdge(first(sites(term)) => last(sites(term))) - if (e ∈ real_es || reverse(e) ∈ real_es) - new_opsum += term - end - end - end - tno = truncate(ttn(new_opsum, s_f); cutoff) - tno = ITensorNetwork(tno) - if insert_dummy_inds - tno = insert_linkinds(tno, setdiff(edges(s), edges(tno))) +function opsum_to_tno( + s::IndsNetwork, H::OpSum; cutoff::Float64=1e-14, insert_dummy_inds=false +) + s_fs_connected = connect_forests(s) + no_forests = length(s_fs_connected) + tnos = ITensorNetwork[] + for (s_f, dummy_edges) in s_fs_connected + real_es = setdiff(edges(s_f), dummy_edges) + new_opsum = OpSum() + for term in H + if length(sites(term)) == 1 && !iszero(first(term.args)) + new_opsum += (1.0 / no_forests) * term + elseif length(sites(term)) == 2 && !iszero(first(term.args)) + e = NamedEdge(first(sites(term)) => last(sites(term))) + if (e ∈ real_es || reverse(e) ∈ real_es) + new_opsum += term end - push!(tnos, tno) + end end + tno = truncate(ttn(new_opsum, s_f); cutoff) + tno = ITensorNetwork(tno) + if insert_dummy_inds + tno = insert_linkinds(tno, setdiff(edges(s), edges(tno))) + end + push!(tnos, tno) + end - return tnos -end \ No newline at end of file + return tnos +end diff --git a/src/beliefpropagationdmrg/utils.jl b/src/beliefpropagationdmrg/utils.jl deleted file mode 100644 index b431bb81..00000000 --- a/src/beliefpropagationdmrg/utils.jl +++ /dev/null @@ -1,75 +0,0 @@ -using ITensors: siteinds, Op, prime, OpSum, apply -using Graphs: AbstractGraph, SimpleGraph, edges, vertices, is_tree, connected_components -using NamedGraphs: NamedGraph, NamedEdge, NamedGraphs, rename_vertices -using NamedGraphs.NamedGraphGenerators: named_grid, named_hexagonal_lattice_graph -using NamedGraphs.GraphsExtensions: decorate_graph_edges, forest_cover, add_edges, rem_edges, add_vertices, rem_vertices, disjoint_union, subgraph, src, dst -using NamedGraphs.PartitionedGraphs: PartitionVertex, partitionedge, unpartitioned_graph -using ITensorNetworks: BeliefPropagationCache, AbstractITensorNetwork, AbstractFormNetwork, IndsNetwork, ITensorNetwork, insert_linkinds, ttn, union_all_inds, - neighbor_vertices, environment, messages, update_factor, message, partitioned_tensornetwork, bra_vertex, ket_vertex, operator_vertex, default_cache_update_kwargs, - dual_index_map, region_scalar, renormalize_messages, scalar_factors_quotient, norm_sqr_network -using DataGraphs: underlying_graph -using ITensorNetworks.ModelHamiltonians: heisenberg -using ITensors: ITensor, noprime, dag, noncommonind, commonind, replaceind, dim, noncommoninds, delta, replaceinds, Trotter -using ITensors.NDTensors: denseblocks -using SplitApplyCombine: group - -function get_local_term(bpc::BeliefPropagationCache, v) - qf = tensornetwork(bpc) - return qf[(v, "ket")]*qf[(v, "operator")]*qf[(v, "bra")] -end - -function exact_energy(g::AbstractGraph, bpc::BeliefPropagationCache) - tn = ITensorNetwork(g) - for v in vertices(g) - tn[v] = get_local_term(bpc, v) - end - degree_two_sites = filter(v -> degree(tn, v) == 2, vertices(tn)) - while !isempty(degree_two_sites) - v = first(degree_two_sites) - vn = first(neighbors(g, v)) - tn = contract(tn, NamedEdge(v => vn); merged_vertex=vn) - degree_two_sites = filter(v -> degree(tn, v) == 2, vertices(tn)) - end - return ITensors.contract(ITensor[tn[v] for v in vertices(tn)]; sequence = "automatic")[] -end - -function renamer(g) - vertex_rename = Dictionary() - for (i,v) in enumerate(vertices(g)) - set!(vertex_rename, v, (i,)) - end - return rename_vertices(v -> vertex_rename[v], g) -end - -function imaginary_time_evo(s::IndsNetwork, ψ::ITensorNetwork, model::Function, dbetas::Vector{<:Tuple}; model_params, - bp_update_kwargs = (; maxiter = 10, tol = 1e-10), apply_kwargs = (; cutoff = 1e-12, maxdim = 10)) - ψ = copy(ψ) - g = underlying_graph(ψ) - - ℋ =model(g; model_params...) - ψψ = norm_sqr_network(ψ) - bpc = BeliefPropagationCache(ψψ, group(v->v[1], vertices(ψψ))) - bpc = update(bpc; bp_update_kwargs...) - L = length(vertices(ψ)) - println("Starting Imaginary Time Evolution") - β = 0 - for (i, period) in enumerate(dbetas) - nbetas, dβ = first(period), last(period) - println("Entering evolution period $i , β = $β, dβ = $dβ") - U = exp(- dβ * ℋ, alg = Trotter{1}()) - gates = Vector{ITensor}(U, s) - for i in 1:nbetas - for gate in gates - ψ, bpc = BP_apply(gate, ψ, bpc; apply_kwargs...) - end - β += dβ - bpc = update(bpc; bp_update_kwargs...) - end - e = sum(expect(ψ, ℋ; alg = "bp")) - println("Energy is $(e / L)") - end - - return ψ -end - - diff --git a/src/solvers/alternating_update/alternating_update.jl b/src/solvers/alternating_update/alternating_update.jl index ef4f9359..571d24de 100644 --- a/src/solvers/alternating_update/alternating_update.jl +++ b/src/solvers/alternating_update/alternating_update.jl @@ -21,7 +21,7 @@ function alternating_update( inserter=default_inserter(), transform_operator_kwargs=(;), transform_operator=default_transform_operator(), - sweep_plan_func = default_sweep_plan, + sweep_plan_func=default_sweep_plan, kwargs..., ) inserter_kwargs = (; inserter_kwargs..., kwargs...) @@ -107,13 +107,22 @@ end #TODO: Generalise your BP alternating update to operator::Sum{AbstractITensorNetwork}. Shouldn't this # account for the environment correctly and put the BP error precisely on the state only, which is better # conditioned?! -function alternating_update(operators::Vector{ITensorNetwork}, init_state::AbstractITensorNetwork, sweep_plans; kwargs...) - cache_update_kwargs = is_tree(init_state) ? (;) : (; maxiter = 10, tol = 1e-5) - ψOψs = QuadraticFormNetwork[QuadraticFormNetwork(operator, init_state) for operator in operators] +function alternating_update( + operators::Vector{ITensorNetwork}, + init_state::AbstractITensorNetwork, + sweep_plans; + kwargs..., +) + cache_update_kwargs = is_tree(init_state) ? (;) : (; maxiter=10, tol=1e-5) + ψOψs = QuadraticFormNetwork[ + QuadraticFormNetwork(operator, init_state) for operator in operators + ] ψIψ = QuadraticFormNetwork(init_state) ψOψ_bpcs = BeliefPropagationCache[BeliefPropagationCache(ψOψ) for ψOψ in ψOψs] ψIψ_bpc = BeliefPropagationCache(ψIψ) - ψOψ_bpcs = BeliefPropagationCache[update(ψOψ_bpc; cache_update_kwargs...) for ψOψ_bpc in ψOψ_bpcs] + ψOψ_bpcs = BeliefPropagationCache[ + update(ψOψ_bpc; cache_update_kwargs...) for ψOψ_bpc in ψOψ_bpcs + ] ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) projected_operators = (ψOψ_bpcs, ψIψ_bpc) return alternating_update(projected_operators, init_state, sweep_plans; kwargs...) diff --git a/src/solvers/alternating_update/region_update.jl b/src/solvers/alternating_update/region_update.jl index 135597d2..d741ca0c 100644 --- a/src/solvers/alternating_update/region_update.jl +++ b/src/solvers/alternating_update/region_update.jl @@ -119,13 +119,16 @@ function region_update( return state, projected_operator end -function region_update(projected_operators, state; outputlevel, +function region_update( + projected_operators, + state; + outputlevel, which_sweep, sweep_plan, which_region_update, region_printer, - (region_observer!)) - + (region_observer!), +) (region, region_kwargs) = sweep_plan[which_region_update] (; extracter, @@ -139,13 +142,19 @@ function region_update(projected_operators, state; outputlevel, internal_kwargs, ) = region_kwargs ψOψ_bpcs, ψIψ_bpc = first(projected_operators), last(projected_operators) - + #Fix extracter, update and inserter to work with sum of ψOψ_bpcs - local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts = extracter(state, ψOψ_bpcs, ψIψ_bpc, region; extracter_kwargs...) + local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts = extracter( + state, ψOψ_bpcs, ψIψ_bpc, region; extracter_kwargs... + ) - local_state, _ = updater(local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts; updater_kwargs...) + local_state, _ = updater( + local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts; updater_kwargs... + ) - state, ψOψ_bpcs, ψIψ_bpc, spec, info = inserter(state, ψOψ_bpcs, ψIψ_bpc, local_state, region; inserter_kwargs...) + state, ψOψ_bpcs, ψIψ_bpc, spec, info = inserter( + state, ψOψ_bpcs, ψIψ_bpc, local_state, region; inserter_kwargs... + ) all_kwargs = (; which_region_update, diff --git a/src/solvers/dmrg.jl b/src/solvers/dmrg.jl index 607e476b..2870acd7 100644 --- a/src/solvers/dmrg.jl +++ b/src/solvers/dmrg.jl @@ -30,10 +30,10 @@ function ITensorMPS.dmrg( nsweeps, nsites=2, updater=bp_eigsolve_updater, - inserter = bp_inserter, - extracter = bp_extracter, - sweep_plan_func = bp_sweep_plan, - bp_sweep_kwargs = (;), + inserter=bp_inserter, + extracter=bp_extracter, + sweep_plan_func=bp_sweep_plan, + bp_sweep_kwargs=(;), (region_observer!)=nothing, kwargs..., ) @@ -42,7 +42,16 @@ function ITensorMPS.dmrg( region_observer!, ValuesObserver((; eigvals=eigvals_ref)) ) state = alternating_update( - operators, init_state; nsweeps, nsites, updater, region_observer!, inserter, extracter, sweep_plan_func, kwargs... + operators, + init_state; + nsweeps, + nsites, + updater, + region_observer!, + inserter, + extracter, + sweep_plan_func, + kwargs..., ) eigval = only(eigvals_ref[]) return eigval, state diff --git a/src/solvers/extract/extract.jl b/src/solvers/extract/extract.jl index 19a49dfa..feb57c2f 100644 --- a/src/solvers/extract/extract.jl +++ b/src/solvers/extract/extract.jl @@ -23,4 +23,4 @@ function default_extracter(state, projected_operator, region, ortho; internal_kw end projected_operator = position(projected_operator, state, region) return state, projected_operator, local_tensor -end \ No newline at end of file +end diff --git a/src/solvers/insert/insert.jl b/src/solvers/insert/insert.jl index b61d6c34..e7183ad5 100644 --- a/src/solvers/insert/insert.jl +++ b/src/solvers/insert/insert.jl @@ -48,9 +48,15 @@ function default_inserter( return state, nothing end -function bp_inserter(ψ::AbstractITensorNetwork, ψAψ_bpcs::Vector{<:BeliefPropagationCache}, - ψIψ_bpc::BeliefPropagationCache, state::ITensor, region; cache_update_kwargs = (;), kwargs...) - +function bp_inserter( + ψ::AbstractITensorNetwork, + ψAψ_bpcs::Vector{<:BeliefPropagationCache}, + ψIψ_bpc::BeliefPropagationCache, + state::ITensor, + region; + cache_update_kwargs=(;), + kwargs..., +) spec = nothing form_network = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) @@ -62,8 +68,12 @@ function bp_inserter(ψ::AbstractITensorNetwork, ψAψ_bpcs::Vector{<:BeliefProp elseif length(region) == 2 v1, v2 = region[1], region[2] e = edgetype(ψ)(v1, v2) - pe = partitionedge(ψIψ_bpc, ket_vertex(form_network, v1) => bra_vertex(form_network, v2)) - stateᵥ₁, stateᵥ₂, spec = factorize_svd(state,uniqueinds(ψ[v1], ψ[v2]); ortho="none", tags=edge_tag(e),kwargs...) + pe = partitionedge( + ψIψ_bpc, ket_vertex(form_network, v1) => bra_vertex(form_network, v2) + ) + stateᵥ₁, stateᵥ₂, spec = factorize_svd( + state, uniqueinds(ψ[v1], ψ[v2]); ortho="none", tags=edge_tag(e), kwargs... + ) states = noprime.([stateᵥ₁, stateᵥ₂]) #TODO: Insert spec into the message tensor guess here?! end @@ -72,23 +82,36 @@ function bp_inserter(ψ::AbstractITensorNetwork, ψAψ_bpcs::Vector{<:BeliefProp state = states[i] state_dag = copy(state) form_bra_v, form_ket_v = bra_vertex(form_network, v), ket_vertex(form_network, v) - ψ[v] =state - state_dag = replaceinds(dag(state_dag), inds(state_dag), dual_index_map(form_network).(inds(state_dag))) - ψAψ_bpcs = BeliefPropagationCache[update_factor(ψAψ_bpc, form_ket_v, state) for ψAψ_bpc in ψAψ_bpcs] - ψAψ_bpcs = BeliefPropagationCache[update_factor(ψAψ_bpc, form_bra_v, state_dag) for ψAψ_bpc in ψAψ_bpcs] + ψ[v] = state + state_dag = replaceinds( + dag(state_dag), inds(state_dag), dual_index_map(form_network).(inds(state_dag)) + ) + ψAψ_bpcs = BeliefPropagationCache[ + update_factor(ψAψ_bpc, form_ket_v, state) for ψAψ_bpc in ψAψ_bpcs + ] + ψAψ_bpcs = BeliefPropagationCache[ + update_factor(ψAψ_bpc, form_bra_v, state_dag) for ψAψ_bpc in ψAψ_bpcs + ] ψIψ_bpc = update_factor(ψIψ_bpc, form_ket_v, state) ψIψ_bpc = update_factor(ψIψ_bpc, form_bra_v, state_dag) end - - ψAψ_bpcs = BeliefPropagationCache[update(ψAψ_bpc; cache_update_kwargs...) for ψAψ_bpc in ψAψ_bpcs] + ψAψ_bpcs = BeliefPropagationCache[ + update(ψAψ_bpc; cache_update_kwargs...) for ψAψ_bpc in ψAψ_bpcs + ] ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) updated_ψIψ = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) - numerator_terms = [scalar(unpartitioned_graph(partitioned_tensornetwork(ψAψ_bpc)); cache! = Ref(ψAψ_bpc), alg = "bp") for ψAψ_bpc in ψAψ_bpcs] - eigval = sum(numerator_terms) / scalar(updated_ψIψ; cache! = Ref(ψIψ_bpc), alg = "bp") + numerator_terms = [ + scalar( + unpartitioned_graph(partitioned_tensornetwork(ψAψ_bpc)); + (cache!)=Ref(ψAψ_bpc), + alg="bp", + ) for ψAψ_bpc in ψAψ_bpcs + ] + eigval = sum(numerator_terms) / scalar(updated_ψIψ; (cache!)=Ref(ψIψ_bpc), alg="bp") @show eigval - @show scalar(only(ψAψ_bpcs); alg = "exact") / scalar(ψIψ_bpc; alg = "exact") + @show scalar(only(ψAψ_bpcs); alg="exact") / scalar(ψIψ_bpc; alg="exact") return ψ, ψAψ_bpcs, ψIψ_bpc, spec, (; eigvals=[eigval]) -end \ No newline at end of file +end diff --git a/src/solvers/local_solvers/eigsolve.jl b/src/solvers/local_solvers/eigsolve.jl index 5b083ee9..ed993d80 100644 --- a/src/solvers/local_solvers/eigsolve.jl +++ b/src/solvers/local_solvers/eigsolve.jl @@ -31,4 +31,4 @@ function eigsolve_updater( eager, ) return vecs[1], (; info, eigvals=vals) -end \ No newline at end of file +end diff --git a/src/solvers/sweep_plans/sweep_plans.jl b/src/solvers/sweep_plans/sweep_plans.jl index 12ea8b88..d497494e 100644 --- a/src/solvers/sweep_plans/sweep_plans.jl +++ b/src/solvers/sweep_plans/sweep_plans.jl @@ -143,22 +143,20 @@ function default_sweep_plans( return sweep_plans end -function bp_sweep_plan(g::AbstractGraph; +function bp_sweep_plan( + g::AbstractGraph; root_vertex=GraphsExtensions.default_root_vertex(graph), region_kwargs, nsites::Int, - es = vcat(collect(edges(g)), collect(reverse(edges(g)))), - vs = vcat(reverse(collect(vertices(g))), collect(vertices(g)))) - region_kwargs = (; internal_kwargs = (;), region_kwargs...) + es=vcat(collect(edges(g)), collect(reverse(edges(g)))), + vs=vcat(reverse(collect(vertices(g))), collect(vertices(g))), +) + region_kwargs = (; internal_kwargs=(;), region_kwargs...) if nsites == 2 - return collect( - flatten(map(e -> [([src(e), dst(e)], region_kwargs)], es)) - ) + return collect(flatten(map(e -> [([src(e), dst(e)], region_kwargs)], es))) elseif nsites == 1 - return collect( - flatten(map(v -> [([v], region_kwargs)], vs)) - ) + return collect(flatten(map(v -> [([v], region_kwargs)], vs))) end end From 50369c11b1b3dc6c03577c3a95c15665ff20973d Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 12 Jun 2024 16:05:25 -0400 Subject: [PATCH 15/27] working implementation --- src/lib/ModelHamiltonians/src/ModelHamiltonians.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/ModelHamiltonians/src/ModelHamiltonians.jl b/src/lib/ModelHamiltonians/src/ModelHamiltonians.jl index 0f6f3383..53bf6adf 100644 --- a/src/lib/ModelHamiltonians/src/ModelHamiltonians.jl +++ b/src/lib/ModelHamiltonians/src/ModelHamiltonians.jl @@ -108,7 +108,7 @@ heisenberg(N::Integer; kwargs...) = heisenberg(path_graph(N); kwargs...) """ Next-to-nearest-neighbor Ising model (ZZX) on a general graph """ -function ising(g::AbstractGraph; J1=-1, J2=0, h=0, hl = 0) +function ising(g::AbstractGraph; J1=-1, J2=0, h=0, hl=0) (; J1, J2, h, hl) = map(to_callable, (; J1, J2, h, hl)) ℋ = OpSum() for e in edges(g) From 0e5e5d875a3e01d141473ecedabeed5786479c37 Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 12 Jun 2024 16:16:47 -0400 Subject: [PATCH 16/27] Remove old changes --- src/abstractitensornetwork.jl | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/abstractitensornetwork.jl b/src/abstractitensornetwork.jl index 9803ee51..34c2db07 100644 --- a/src/abstractitensornetwork.jl +++ b/src/abstractitensornetwork.jl @@ -797,23 +797,6 @@ end is_multi_edge(tn::AbstractITensorNetwork, e) = length(linkinds(tn, e)) > 1 is_multi_edge(tn::AbstractITensorNetwork) = Base.Fix1(is_multi_edge, tn) -function edges_equal(e1s, e2s) - if length(e1s) != length(e2s) - return false - end - for e in e1s - if e ∉ e2s && reverse(e) ∉ e2s - return false - end - end - return true -end - - -function edges_equal(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork) - return edges_equal(edges(tn1), edges(tn2)) -end - """Add two itensornetworks together by growing the bond dimension. The network structures need to be have the same vertex names, same site index on each vertex """ function ITensorMPS.add(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork) @assert issetequal(vertices(tn1), vertices(tn2)) @@ -823,14 +806,13 @@ function ITensorMPS.add(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork edges_tn1, edges_tn2 = edges(tn1), edges(tn2) - if !edges_equal(tn1, tn2) + if !issetequal(tn1, tn2) new_edges = union(edges_tn1, edges_tn2) tn1 = insert_linkinds(tn1, new_edges) tn2 = insert_linkinds(tn2, new_edges) end edges_tn1, edges_tn2 = edges(tn1), edges(tn2) - @assert edges_equal(tn1, tn2) tn12 = copy(tn1) new_edge_indices = Dict( @@ -852,7 +834,6 @@ function ITensorMPS.add(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork e1_v = filter(x -> src(x) == v || dst(x) == v, edges_tn1) e2_v = filter(x -> src(x) == v || dst(x) == v, edges_tn2) - @assert edges_equal(e1_v, e2_v) tn1v_linkinds = Index[only(linkinds(tn1, e)) for e in e1_v] tn2v_linkinds = Index[only(linkinds(tn2, e)) for e in e1_v] tn12v_linkinds = Index[new_edge_indices[e] for e in e1_v] From 4bc0183b3855d316e8aae2457b88eb16f755a0e0 Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 12 Jun 2024 16:20:31 -0400 Subject: [PATCH 17/27] Revert --- .../alternating_update/alternating_update.jl | 27 +------- .../alternating_update/region_update.jl | 61 +------------------ 2 files changed, 3 insertions(+), 85 deletions(-) diff --git a/src/solvers/alternating_update/alternating_update.jl b/src/solvers/alternating_update/alternating_update.jl index 571d24de..86ef9da6 100644 --- a/src/solvers/alternating_update/alternating_update.jl +++ b/src/solvers/alternating_update/alternating_update.jl @@ -4,7 +4,7 @@ using NamedGraphs.GraphsExtensions: GraphsExtensions function alternating_update( operator, - init_state; + init_state::AbstractTTN; nsweeps, # define default for each solver implementation nsites, # define default for each level of solver implementation updater, # this specifies the update performed locally @@ -21,7 +21,6 @@ function alternating_update( inserter=default_inserter(), transform_operator_kwargs=(;), transform_operator=default_transform_operator(), - sweep_plan_func=default_sweep_plan, kwargs..., ) inserter_kwargs = (; inserter_kwargs..., kwargs...) @@ -104,30 +103,6 @@ function alternating_update(operator::AbstractTTN, init_state::AbstractTTN; kwar return alternating_update(projected_operator, init_state; kwargs...) end -#TODO: Generalise your BP alternating update to operator::Sum{AbstractITensorNetwork}. Shouldn't this -# account for the environment correctly and put the BP error precisely on the state only, which is better -# conditioned?! -function alternating_update( - operators::Vector{ITensorNetwork}, - init_state::AbstractITensorNetwork, - sweep_plans; - kwargs..., -) - cache_update_kwargs = is_tree(init_state) ? (;) : (; maxiter=10, tol=1e-5) - ψOψs = QuadraticFormNetwork[ - QuadraticFormNetwork(operator, init_state) for operator in operators - ] - ψIψ = QuadraticFormNetwork(init_state) - ψOψ_bpcs = BeliefPropagationCache[BeliefPropagationCache(ψOψ) for ψOψ in ψOψs] - ψIψ_bpc = BeliefPropagationCache(ψIψ) - ψOψ_bpcs = BeliefPropagationCache[ - update(ψOψ_bpc; cache_update_kwargs...) for ψOψ_bpc in ψOψ_bpcs - ] - ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) - projected_operators = (ψOψ_bpcs, ψIψ_bpc) - return alternating_update(projected_operators, init_state, sweep_plans; kwargs...) -end - function alternating_update( operator::AbstractTTN, init_state::AbstractTTN, sweep_plans; kwargs... ) diff --git a/src/solvers/alternating_update/region_update.jl b/src/solvers/alternating_update/region_update.jl index d741ca0c..d60adbb8 100644 --- a/src/solvers/alternating_update/region_update.jl +++ b/src/solvers/alternating_update/region_update.jl @@ -41,7 +41,7 @@ end function region_update( projected_operator, - state::AbstractTTN; + state; outputlevel, which_sweep, sweep_plan, @@ -117,61 +117,4 @@ function region_update( update_observer!(region_observer!; all_kwargs...) !(isnothing(region_printer)) && region_printer(; all_kwargs...) return state, projected_operator -end - -function region_update( - projected_operators, - state; - outputlevel, - which_sweep, - sweep_plan, - which_region_update, - region_printer, - (region_observer!), -) - (region, region_kwargs) = sweep_plan[which_region_update] - (; - extracter, - extracter_kwargs, - updater, - updater_kwargs, - inserter, - inserter_kwargs, - transform_operator, - transform_operator_kwargs, - internal_kwargs, - ) = region_kwargs - ψOψ_bpcs, ψIψ_bpc = first(projected_operators), last(projected_operators) - - #Fix extracter, update and inserter to work with sum of ψOψ_bpcs - local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts = extracter( - state, ψOψ_bpcs, ψIψ_bpc, region; extracter_kwargs... - ) - - local_state, _ = updater( - local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts; updater_kwargs... - ) - - state, ψOψ_bpcs, ψIψ_bpc, spec, info = inserter( - state, ψOψ_bpcs, ψIψ_bpc, local_state, region; inserter_kwargs... - ) - - all_kwargs = (; - which_region_update, - sweep_plan, - total_sweep_steps=length(sweep_plan), - end_of_sweep=(which_region_update == length(sweep_plan)), - state, - region, - which_sweep, - spec, - outputlevel, - info..., - region_kwargs..., - internal_kwargs..., - ) - update_observer!(region_observer!; all_kwargs...) - !(isnothing(region_printer)) && region_printer(; all_kwargs...) - - return state, (ψOψ_bpcs, ψIψ_bpc) -end +end \ No newline at end of file From 9e14f14866467bd66b077c8e34aee0fb3755b31d Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 12 Jun 2024 16:21:47 -0400 Subject: [PATCH 18/27] Revert --- src/abstractitensornetwork.jl | 4 +++- src/solvers/alternating_update/alternating_update.jl | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/abstractitensornetwork.jl b/src/abstractitensornetwork.jl index 34c2db07..06bd5e27 100644 --- a/src/abstractitensornetwork.jl +++ b/src/abstractitensornetwork.jl @@ -806,13 +806,14 @@ function ITensorMPS.add(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork edges_tn1, edges_tn2 = edges(tn1), edges(tn2) - if !issetequal(tn1, tn2) + if !issetequal(edges_tn1, edges_tn2) new_edges = union(edges_tn1, edges_tn2) tn1 = insert_linkinds(tn1, new_edges) tn2 = insert_linkinds(tn2, new_edges) end edges_tn1, edges_tn2 = edges(tn1), edges(tn2) + @assert issetequal(edges_tn1, edges_tn2) tn12 = copy(tn1) new_edge_indices = Dict( @@ -833,6 +834,7 @@ function ITensorMPS.add(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork e1_v = filter(x -> src(x) == v || dst(x) == v, edges_tn1) e2_v = filter(x -> src(x) == v || dst(x) == v, edges_tn2) + @assert issetequal(e1_v, e2_v) tn1v_linkinds = Index[only(linkinds(tn1, e)) for e in e1_v] tn2v_linkinds = Index[only(linkinds(tn2, e)) for e in e1_v] diff --git a/src/solvers/alternating_update/alternating_update.jl b/src/solvers/alternating_update/alternating_update.jl index 86ef9da6..2cd5de71 100644 --- a/src/solvers/alternating_update/alternating_update.jl +++ b/src/solvers/alternating_update/alternating_update.jl @@ -28,7 +28,6 @@ function alternating_update( nsweeps, init_state; root_vertex, - sweep_plan_func, extracter, extracter_kwargs, updater, @@ -53,7 +52,7 @@ end function alternating_update( projected_operator, - init_state, + init_state::AbstractTTN, sweep_plans; outputlevel=default_outputlevel(), checkdone=default_checkdone(), # From 0a7355e428b92676e945dae83a204d6f7388ac04 Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 12 Jun 2024 16:22:39 -0400 Subject: [PATCH 19/27] Revert --- src/solvers/dmrg.jl | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/src/solvers/dmrg.jl b/src/solvers/dmrg.jl index 2870acd7..d7931923 100644 --- a/src/solvers/dmrg.jl +++ b/src/solvers/dmrg.jl @@ -24,39 +24,6 @@ function ITensorMPS.dmrg( return eigval, state end -function ITensorMPS.dmrg( - operators::Vector{ITensorNetwork}, - init_state; - nsweeps, - nsites=2, - updater=bp_eigsolve_updater, - inserter=bp_inserter, - extracter=bp_extracter, - sweep_plan_func=bp_sweep_plan, - bp_sweep_kwargs=(;), - (region_observer!)=nothing, - kwargs..., -) - eigvals_ref = Ref{Any}() - region_observer! = compose_observers( - region_observer!, ValuesObserver((; eigvals=eigvals_ref)) - ) - state = alternating_update( - operators, - init_state; - nsweeps, - nsites, - updater, - region_observer!, - inserter, - extracter, - sweep_plan_func, - kwargs..., - ) - eigval = only(eigvals_ref[]) - return eigval, state -end - """ Overload of `KrylovKit.eigsolve`. """ From b07b9788506f9072891243de0ea918d2260d030f Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 12 Jun 2024 16:23:06 -0400 Subject: [PATCH 20/27] Revert --- src/solvers/dmrg.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/solvers/dmrg.jl b/src/solvers/dmrg.jl index d7931923..19511505 100644 --- a/src/solvers/dmrg.jl +++ b/src/solvers/dmrg.jl @@ -6,7 +6,7 @@ Overload of `ITensors.ITensorMPS.dmrg`. """ function ITensorMPS.dmrg( operator, - init_state::AbstractTTN; + init_state; nsweeps, nsites=2, updater=eigsolve_updater, @@ -20,7 +20,7 @@ function ITensorMPS.dmrg( state = alternating_update( operator, init_state; nsweeps, nsites, updater, region_observer!, kwargs... ) - eigval = first(eigvals_ref[]) + eigval = only(eigvals_ref[]) return eigval, state end From 440c2677d4e4d8ae0dc4e176c4e38f003a290108 Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 12 Jun 2024 16:23:28 -0400 Subject: [PATCH 21/27] Revert --- src/beliefpropagationdmrg/graphsextensions.jl | 132 ++++++++++++ src/beliefpropagationdmrg/main.jl | 9 +- .../tensornetworkoperators.jl | 9 +- src/beliefpropagationdmrg/utils.jl | 202 ++++++++++++++++++ src/caches/beliefpropagationcache.jl | 21 +- src/expect.jl | 9 +- src/formnetworks/bilinearformnetwork.jl | 2 +- .../alternating_update/region_update.jl | 2 +- 8 files changed, 357 insertions(+), 29 deletions(-) create mode 100644 src/beliefpropagationdmrg/graphsextensions.jl create mode 100644 src/beliefpropagationdmrg/utils.jl diff --git a/src/beliefpropagationdmrg/graphsextensions.jl b/src/beliefpropagationdmrg/graphsextensions.jl new file mode 100644 index 00000000..d605f58a --- /dev/null +++ b/src/beliefpropagationdmrg/graphsextensions.jl @@ -0,0 +1,132 @@ +using Graphs: AbstractGraph +using NamedGraphs.GraphsExtensions: a_star, add_edge!, dfs_tree, post_order_dfs_edges +using NamedGraphs.GraphsExtensions: + default_root_vertex, degree, degrees, neighbors, edgetype, rem_edge!, vertextype + +#Given a graph, traverse it from start vertex to end vertex, covering each edge exactly once. +#Complexity is O(length(edges(g))) +function eulerian_path(g::AbstractGraph, start_vertex, end_vertex) + #Conditions on g for the required path to exist + if start_vertex != end_vertex + @assert isodd(degree(g, start_vertex) % 2) + @assert isodd(degree(g, end_vertex) % 2) + @assert all( + x -> iseven(x), degrees(g, setdiff(vertices(g), [start_vertex, end_vertex])) + ) + else + @assert all(x -> iseven(x), degrees(g)) + end + + path = vertextype(g)[] + stack = vertextype(g)[] + current_vertex = end_vertex + g_modified = copy(g) + while !isempty(stack) || !iszero(degree(g_modified, current_vertex)) + if iszero(degree(g_modified, current_vertex)) + push!(path, current_vertex) + last_vertex = pop!(stack) + current_vertex = last_vertex + else + push!(stack, current_vertex) + vn = first(neighbors(g_modified, current_vertex)) + rem_edge!(g_modified, edgetype(g_modified)(current_vertex, vn)) + current_vertex = vn + end + end + + push!(path, current_vertex) + + return edgetype(g_modified)[ + edgetype(g_modified)(path[i], path[i + 1]) for i in 1:(length(path) - 1) + ] +end + +function eulerian_cycle(g::AbstractGraph, start_vertex) + return eulerian_path(g, start_vertex, start_vertex) +end + +function make_all_degrees_even(g::AbstractGraph) + g_modified = copy(g) + vertices_odd_degree = collect(filter(v -> isodd(degree(g, v)), vertices(g_modified))) + while !isempty(vertices_odd_degree) + vertex_pairs = [ + (vertices_odd_degree[i], vertices_odd_degree[j]) for + i in 1:length(vertices_odd_degree) for j in (i + 1):length(vertices_odd_degree) + ] + vertex_pair = first(sort(vertex_pairs; by=vp -> length(a_star(g, vp...)))) + add_edge!(g_modified, edgetype(g_modified)(vertex_pair...)) + vertices_odd_degree = filter( + v -> v != first(vertex_pair) && v != last(vertex_pair), vertices_odd_degree + ) + end + return g_modified +end + +#Given a graph, traverse it in a cycle from start_vertex and try to minimise the number of edges traversed more than once +function _eulerian_cycle(g::AbstractGraph, start_vertex; add_additional_traversal=false) + g_modified = make_all_degrees_even(g::AbstractGraph) + path = eulerian_cycle(g_modified, start_vertex) + + !add_additional_traversal && return path + + modified_path = edgetype(g_modified)[] + + for e in path + if src(e) ∉ neighbors(g, dst(e)) + inner_path = a_star(g, src(e), dst(e)) + append!(modified_path, inner_path) + else + push!(modified_path, e) + end + end + + return modified_path +end + +function _bp_region_plan( + g::AbstractGraph, + start_vertex=default_root_vertex(g); + nsites::Int=1, + add_additional_traversal=false, +) + path = _eulerian_cycle(g, start_vertex; add_additional_traversal) + if nsites == 1 + regions = [[v] for v in vcat(src.(path))] + @assert all(v -> only(v) ∈ vertices(g), regions) + return vcat(regions, reverse(regions)) + else + regions = [e for e in path] + regions = filter(e -> e ∈ edges(g) || reverse(e) ∈ edges(g), regions) + regions = [[src(e), dst(e)] for e in regions] + return vcat(regions, reverse(regions)) + end +end + +function path_to_path(path) + verts = [] + for e in path + if isempty(verts) || src(e) ≠ last(verts) + push!(verts, src(e)) + push!(verts, dst(e)) + end + end + return [[v] for v in verts] +end + +function bp_region_plan( + g::AbstractGraph, + start_vertex=default_root_vertex(g); + nsites::Int=1, + add_additional_traversal=false, +) + path = post_order_dfs_edges(g, start_vertex) + if nsites == 1 + regions = path_to_path(path) + @assert all(v -> only(v) ∈ vertices(g), regions) + return vcat(regions, reverse(regions)) + else + regions = filter(e -> e ∈ edges(g) || reverse(e) ∈ edges(g), path) + @assert all(e -> e ∈ regions || reverse(e) ∈ regions, edges(g)) + return regions + end +end diff --git a/src/beliefpropagationdmrg/main.jl b/src/beliefpropagationdmrg/main.jl index 98b7fca1..b2bb690f 100644 --- a/src/beliefpropagationdmrg/main.jl +++ b/src/beliefpropagationdmrg/main.jl @@ -1,6 +1,5 @@ using ITensorNetworks: random_tensornetwork using NamedGraphs.NamedGraphGenerators: named_comb_tree -using NPZ using ITensors: expect using Random @@ -12,16 +11,14 @@ Random.seed!(5634) function main() g = named_grid((24, 1); periodic=true) - g = renamer(g) - save = true L = length(vertices(g)) - h, hl, J = 0.6, 0.2, 1.0 + h, hlongitudinal, J = 0.6, 0.2, 1.0 s = siteinds("S=1/2", g) χ = 2 ψ0 = random_tensornetwork(s; link_space=χ) - H = ising(s; h, hl, J1=J) - tnos = opsum_to_tno(s, H) + H = ising(s; h, hl=hlongitudinal, J1=J) + tnos = opsum_to_tnos(s, H) energy_calc_fun = (tn, bp_cache) -> sum(expect(tn, H; alg="bp", (cache!)=Ref(bp_cache))) / L diff --git a/src/beliefpropagationdmrg/tensornetworkoperators.jl b/src/beliefpropagationdmrg/tensornetworkoperators.jl index de0da690..4dc971ac 100644 --- a/src/beliefpropagationdmrg/tensornetworkoperators.jl +++ b/src/beliefpropagationdmrg/tensornetworkoperators.jl @@ -19,6 +19,7 @@ using Dictionaries using LinearAlgebra: eigvals +#Convert the forests in forest_cover to trees by adding "dummy" edges and keep track of them function connect_forests(s::IndsNetwork) g = underlying_graph(s) fs = forest_cover(g) @@ -39,9 +40,8 @@ function connect_forests(s::IndsNetwork) return fs_connected end -function opsum_to_tno( - s::IndsNetwork, H::OpSum; cutoff::Float64=1e-14, insert_dummy_inds=false -) +#Convert an Opsum to a vector of tensor network operators whose sum matches opsum +function opsum_to_tnos(s::IndsNetwork, H::OpSum; cutoff::Float64=1e-14) s_fs_connected = connect_forests(s) no_forests = length(s_fs_connected) tnos = ITensorNetwork[] @@ -60,9 +60,6 @@ function opsum_to_tno( end tno = truncate(ttn(new_opsum, s_f); cutoff) tno = ITensorNetwork(tno) - if insert_dummy_inds - tno = insert_linkinds(tno, setdiff(edges(s), edges(tno))) - end push!(tnos, tno) end diff --git a/src/beliefpropagationdmrg/utils.jl b/src/beliefpropagationdmrg/utils.jl new file mode 100644 index 00000000..eb10c096 --- /dev/null +++ b/src/beliefpropagationdmrg/utils.jl @@ -0,0 +1,202 @@ +using ITensors: siteinds, Op, prime, OpSum, apply +using Graphs: AbstractGraph, SimpleGraph, edges, vertices, is_tree, connected_components +using NamedGraphs: NamedGraph, NamedEdge, NamedGraphs, rename_vertices +using NamedGraphs.NamedGraphGenerators: named_grid, named_hexagonal_lattice_graph +using NamedGraphs.GraphsExtensions: + decorate_graph_edges, + forest_cover, + add_edges, + rem_edges, + add_vertices, + rem_vertices, + disjoint_union, + subgraph, + src, + dst +using NamedGraphs.PartitionedGraphs: PartitionVertex, partitionedge, unpartitioned_graph +using ITensorNetworks: + BeliefPropagationCache, + AbstractITensorNetwork, + AbstractFormNetwork, + IndsNetwork, + ITensorNetwork, + insert_linkinds, + ttn, + union_all_inds, + neighbor_vertices, + environment, + messages, + update_factor, + message, + partitioned_tensornetwork, + bra_vertex, + ket_vertex, + operator_vertex, + default_cache_update_kwargs, + dual_index_map, + region_scalar, + renormalize_messages, + scalar_factors_quotient, + norm_sqr_network +using DataGraphs: underlying_graph +using ITensorNetworks.ModelHamiltonians: heisenberg +using ITensors: + ITensor, + noprime, + dag, + noncommonind, + commonind, + replaceind, + dim, + noncommoninds, + delta, + replaceinds, + Trotter, + apply +using ITensors.NDTensors: denseblocks +using SplitApplyCombine: group + +using ITensors: siteinds, Op, prime, OpSum, apply +using Graphs: AbstractGraph, SimpleGraph, edges, vertices, is_tree, connected_components +using NamedGraphs: NamedGraph, NamedEdge, NamedGraphs, rename_vertices +using NamedGraphs.NamedGraphGenerators: named_grid, named_hexagonal_lattice_graph +using NamedGraphs.GraphsExtensions: + decorate_graph_edges, + forest_cover, + add_edges, + rem_edges, + add_vertices, + rem_vertices, + disjoint_union, + subgraph, + src, + dst +using NamedGraphs.PartitionedGraphs: PartitionVertex, partitionedge, unpartitioned_graph +using ITensorNetworks: + BeliefPropagationCache, + AbstractITensorNetwork, + AbstractFormNetwork, + IndsNetwork, + ITensorNetwork, + insert_linkinds, + ttn, + union_all_inds, + neighbor_vertices, + environment, + messages, + update_factor, + message, + partitioned_tensornetwork, + bra_vertex, + ket_vertex, + operator_vertex, + default_cache_update_kwargs, + dual_index_map +using DataGraphs: underlying_graph +using ITensorNetworks.ModelHamiltonians: heisenberg +using ITensors: + ITensor, + noprime, + dag, + noncommonind, + commonind, + replaceind, + dim, + noncommoninds, + delta, + replaceinds +using ITensors.NDTensors: denseblocks +using Dictionaries: set! + +function BP_apply( + o::ITensor, ψ::AbstractITensorNetwork, bpc::BeliefPropagationCache; apply_kwargs... +) + bpc = copy(bpc) + ψ = copy(ψ) + vs = neighbor_vertices(ψ, o) + envs = environment(bpc, PartitionVertex.(vs)) + singular_values! = Ref(ITensor()) + ψ = noprime(apply(o, ψ; envs, singular_values!, normalize=true, apply_kwargs...)) + ψdag = prime(dag(ψ); sites=[]) + if length(vs) == 2 + v1, v2 = vs + pe = partitionedge(bpc, (v1, "bra") => (v2, "bra")) + mts = messages(bpc) + ind1, ind2 = noncommonind(singular_values![], ψ[v1]), + commonind(singular_values![], ψ[v1]) + singular_values![] = denseblocks(replaceind(singular_values![], ind1, ind2')) + set!(mts, pe, ITensor[singular_values![]]) + set!(mts, reverse(pe), ITensor[singular_values![]]) + end + for v in vs + bpc = update_factor(bpc, (v, "ket"), ψ[v]) + bpc = update_factor(bpc, (v, "bra"), ψdag[v]) + end + return ψ, bpc +end + +function get_local_term(bpc::BeliefPropagationCache, v) + qf = tensornetwork(bpc) + return qf[(v, "ket")] * qf[(v, "operator")] * qf[(v, "bra")] +end + +function exact_energy(g::AbstractGraph, bpc::BeliefPropagationCache) + tn = ITensorNetwork(g) + for v in vertices(g) + tn[v] = get_local_term(bpc, v) + end + degree_two_sites = filter(v -> degree(tn, v) == 2, vertices(tn)) + while !isempty(degree_two_sites) + v = first(degree_two_sites) + vn = first(neighbors(g, v)) + tn = contract(tn, NamedEdge(v => vn); merged_vertex=vn) + degree_two_sites = filter(v -> degree(tn, v) == 2, vertices(tn)) + end + return ITensors.contract(ITensor[tn[v] for v in vertices(tn)]; sequence="automatic")[] +end + +function renamer(g) + vertex_rename = Dictionary() + for (i, v) in enumerate(vertices(g)) + set!(vertex_rename, v, (i,)) + end + return rename_vertices(v -> vertex_rename[v], g) +end + +function imaginary_time_evo( + s::IndsNetwork, + ψ::ITensorNetwork, + model::Function, + dbetas::Vector{<:Tuple}; + model_params, + bp_update_kwargs=(; maxiter=10, tol=1e-10), + apply_kwargs=(; cutoff=1e-12, maxdim=10), +) + ψ = copy(ψ) + g = underlying_graph(ψ) + + ℋ = model(g; model_params...) + ψψ = norm_sqr_network(ψ) + bpc = BeliefPropagationCache(ψψ, group(v -> v[1], vertices(ψψ))) + bpc = update(bpc; bp_update_kwargs...) + L = length(vertices(ψ)) + println("Starting Imaginary Time Evolution") + β = 0 + for (i, period) in enumerate(dbetas) + nbetas, dβ = first(period), last(period) + println("Entering evolution period $i , β = $β, dβ = $dβ") + U = exp(-dβ * ℋ; alg=Trotter{1}()) + gates = Vector{ITensor}(U, s) + for i in 1:nbetas + for gate in gates + ψ, bpc = BP_apply(gate, ψ, bpc; apply_kwargs...) + end + β += dβ + bpc = update(bpc; bp_update_kwargs...) + end + e = sum(expect(ψ, ℋ; alg="bp")) + println("Energy is $(e / L)") + end + + return ψ +end diff --git a/src/caches/beliefpropagationcache.jl b/src/caches/beliefpropagationcache.jl index 318d43df..ceb357df 100644 --- a/src/caches/beliefpropagationcache.jl +++ b/src/caches/beliefpropagationcache.jl @@ -17,7 +17,7 @@ default_message(inds_e) = ITensor[denseblocks(delta(i)) for i in inds_e] #default_message(inds_e) = ITensor[denseblocks(delta(inds_e))] default_messages(ptn::PartitionedGraph) = Dictionary() default_message_norm(m::ITensor) = norm(m) -function default_message_update(contract_list::Vector{ITensor}; normalize = true, kwargs...) +function default_message_update(contract_list::Vector{ITensor}; normalize=true, kwargs...) sequence = optimal_contraction_sequence(contract_list) updated_messages = contract(contract_list; sequence, kwargs...) message_norm = norm(updated_messages) @@ -133,6 +133,10 @@ function set_messages(cache::BeliefPropagationCache, messages) ) end +function delete_messages(cache::BeliefPropagationCache) + return BeliefPropagationCache(partitioned_tensornetwork(cache)) +end + function environment( bp_cache::BeliefPropagationCache, partition_vertices::Vector{<:PartitionVertex}; @@ -327,22 +331,15 @@ function ITensors.scalar(bp_cache::BeliefPropagationCache) return prod(v_scalars) / prod(e_scalars) end +#Renormalize all messages such that = 1 on all edges function renormalize_messages(bp_cache::BeliefPropagationCache) bp_cache = copy(bp_cache) mts = messages(bp_cache) for pe in partitionedges(partitioned_tensornetwork(bp_cache)) - n = region_scalar(bp_cache, pe) + n = region_scalar(bp_cache, pe) me, mer = only(mts[pe]), only(mts[reverse(pe)]) - if n >= 0 - set!(mts, pe, ITensor[(1/sqrt(n))*me]) - set!(mts, reverse(pe), ITensor[(1/sqrt(n))*mer]) - else - set!(mts, pe, ITensor[-(1/sqrt(abs(n)))*me]) - set!(mts, reverse(pe), ITensor[(1/sqrt(abs(n)))*mer]) - end + set!(mts, pe, ITensor[(1 / sqrt(n)) * me]) + set!(mts, reverse(pe), ITensor[(1 / sqrt(n)) * mer]) end return bp_cache end - - - diff --git a/src/expect.jl b/src/expect.jl index cd60ca28..a9fdfdaf 100644 --- a/src/expect.jl +++ b/src/expect.jl @@ -25,7 +25,10 @@ function ITensorMPS.expect( end function ITensorMPS.expect( - ψIψ::AbstractFormNetwork, ops::Scaled{ComplexF64, Prod{Op}}; contract_kwargs=(; sequence="automatic"), kwargs... + ψIψ::AbstractFormNetwork, + ops::Scaled{ComplexF64,Prod{Op}}; + contract_kwargs=(; sequence="automatic"), + kwargs..., ) scalar = first(ops.args) iszero(scalar) && return 0.0 @@ -33,7 +36,7 @@ function ITensorMPS.expect( vs = site.(ops[1:n_ops]) op_strings = which_op.(ops[1:n_ops]) ψIψ_vs = [ψIψ[operator_vertex(ψIψ, v)] for v in vs] - sinds = [commonind(ψIψ[ket_vertex(ψIψ, v)], ψIψ_vs[i]) for (i,v) in enumerate(vs)] + sinds = [commonind(ψIψ[ket_vertex(ψIψ, v)], ψIψ_vs[i]) for (i, v) in enumerate(vs)] operators = [ITensors.op(op_strings[i], sinds[i]) for i in 1:n_ops] ∂ψIψ_∂v = environment(ψIψ, operator_vertices(ψIψ, vs); kwargs...) numerator = contract(vcat(∂ψIψ_∂v, operators); contract_kwargs...)[] @@ -86,4 +89,4 @@ function ITensorMPS.expect( ψ::AbstractITensorNetwork, op::String; alg=default_expect_alg(), kwargs... ) return expect(ψ, op, vertices(ψ); alg, kwargs...) -end \ No newline at end of file +end diff --git a/src/formnetworks/bilinearformnetwork.jl b/src/formnetworks/bilinearformnetwork.jl index 4dda5b0a..11d298c5 100644 --- a/src/formnetworks/bilinearformnetwork.jl +++ b/src/formnetworks/bilinearformnetwork.jl @@ -86,4 +86,4 @@ function update( tensornetwork(blf), ket_state, ket_vertex(blf, original_ket_state_vertex) ) return blf -end \ No newline at end of file +end diff --git a/src/solvers/alternating_update/region_update.jl b/src/solvers/alternating_update/region_update.jl index d60adbb8..b92adc8c 100644 --- a/src/solvers/alternating_update/region_update.jl +++ b/src/solvers/alternating_update/region_update.jl @@ -117,4 +117,4 @@ function region_update( update_observer!(region_observer!; all_kwargs...) !(isnothing(region_printer)) && region_printer(; all_kwargs...) return state, projected_operator -end \ No newline at end of file +end From ed7befa7ed8289e1f0c458b2f5e7a993cdaea613 Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 12 Jun 2024 16:24:34 -0400 Subject: [PATCH 22/27] Remove files --- src/beliefpropagationdmrg/graphsextensions.jl | 132 ------------ src/beliefpropagationdmrg/utils.jl | 202 ------------------ 2 files changed, 334 deletions(-) delete mode 100644 src/beliefpropagationdmrg/graphsextensions.jl delete mode 100644 src/beliefpropagationdmrg/utils.jl diff --git a/src/beliefpropagationdmrg/graphsextensions.jl b/src/beliefpropagationdmrg/graphsextensions.jl deleted file mode 100644 index d605f58a..00000000 --- a/src/beliefpropagationdmrg/graphsextensions.jl +++ /dev/null @@ -1,132 +0,0 @@ -using Graphs: AbstractGraph -using NamedGraphs.GraphsExtensions: a_star, add_edge!, dfs_tree, post_order_dfs_edges -using NamedGraphs.GraphsExtensions: - default_root_vertex, degree, degrees, neighbors, edgetype, rem_edge!, vertextype - -#Given a graph, traverse it from start vertex to end vertex, covering each edge exactly once. -#Complexity is O(length(edges(g))) -function eulerian_path(g::AbstractGraph, start_vertex, end_vertex) - #Conditions on g for the required path to exist - if start_vertex != end_vertex - @assert isodd(degree(g, start_vertex) % 2) - @assert isodd(degree(g, end_vertex) % 2) - @assert all( - x -> iseven(x), degrees(g, setdiff(vertices(g), [start_vertex, end_vertex])) - ) - else - @assert all(x -> iseven(x), degrees(g)) - end - - path = vertextype(g)[] - stack = vertextype(g)[] - current_vertex = end_vertex - g_modified = copy(g) - while !isempty(stack) || !iszero(degree(g_modified, current_vertex)) - if iszero(degree(g_modified, current_vertex)) - push!(path, current_vertex) - last_vertex = pop!(stack) - current_vertex = last_vertex - else - push!(stack, current_vertex) - vn = first(neighbors(g_modified, current_vertex)) - rem_edge!(g_modified, edgetype(g_modified)(current_vertex, vn)) - current_vertex = vn - end - end - - push!(path, current_vertex) - - return edgetype(g_modified)[ - edgetype(g_modified)(path[i], path[i + 1]) for i in 1:(length(path) - 1) - ] -end - -function eulerian_cycle(g::AbstractGraph, start_vertex) - return eulerian_path(g, start_vertex, start_vertex) -end - -function make_all_degrees_even(g::AbstractGraph) - g_modified = copy(g) - vertices_odd_degree = collect(filter(v -> isodd(degree(g, v)), vertices(g_modified))) - while !isempty(vertices_odd_degree) - vertex_pairs = [ - (vertices_odd_degree[i], vertices_odd_degree[j]) for - i in 1:length(vertices_odd_degree) for j in (i + 1):length(vertices_odd_degree) - ] - vertex_pair = first(sort(vertex_pairs; by=vp -> length(a_star(g, vp...)))) - add_edge!(g_modified, edgetype(g_modified)(vertex_pair...)) - vertices_odd_degree = filter( - v -> v != first(vertex_pair) && v != last(vertex_pair), vertices_odd_degree - ) - end - return g_modified -end - -#Given a graph, traverse it in a cycle from start_vertex and try to minimise the number of edges traversed more than once -function _eulerian_cycle(g::AbstractGraph, start_vertex; add_additional_traversal=false) - g_modified = make_all_degrees_even(g::AbstractGraph) - path = eulerian_cycle(g_modified, start_vertex) - - !add_additional_traversal && return path - - modified_path = edgetype(g_modified)[] - - for e in path - if src(e) ∉ neighbors(g, dst(e)) - inner_path = a_star(g, src(e), dst(e)) - append!(modified_path, inner_path) - else - push!(modified_path, e) - end - end - - return modified_path -end - -function _bp_region_plan( - g::AbstractGraph, - start_vertex=default_root_vertex(g); - nsites::Int=1, - add_additional_traversal=false, -) - path = _eulerian_cycle(g, start_vertex; add_additional_traversal) - if nsites == 1 - regions = [[v] for v in vcat(src.(path))] - @assert all(v -> only(v) ∈ vertices(g), regions) - return vcat(regions, reverse(regions)) - else - regions = [e for e in path] - regions = filter(e -> e ∈ edges(g) || reverse(e) ∈ edges(g), regions) - regions = [[src(e), dst(e)] for e in regions] - return vcat(regions, reverse(regions)) - end -end - -function path_to_path(path) - verts = [] - for e in path - if isempty(verts) || src(e) ≠ last(verts) - push!(verts, src(e)) - push!(verts, dst(e)) - end - end - return [[v] for v in verts] -end - -function bp_region_plan( - g::AbstractGraph, - start_vertex=default_root_vertex(g); - nsites::Int=1, - add_additional_traversal=false, -) - path = post_order_dfs_edges(g, start_vertex) - if nsites == 1 - regions = path_to_path(path) - @assert all(v -> only(v) ∈ vertices(g), regions) - return vcat(regions, reverse(regions)) - else - regions = filter(e -> e ∈ edges(g) || reverse(e) ∈ edges(g), path) - @assert all(e -> e ∈ regions || reverse(e) ∈ regions, edges(g)) - return regions - end -end diff --git a/src/beliefpropagationdmrg/utils.jl b/src/beliefpropagationdmrg/utils.jl deleted file mode 100644 index eb10c096..00000000 --- a/src/beliefpropagationdmrg/utils.jl +++ /dev/null @@ -1,202 +0,0 @@ -using ITensors: siteinds, Op, prime, OpSum, apply -using Graphs: AbstractGraph, SimpleGraph, edges, vertices, is_tree, connected_components -using NamedGraphs: NamedGraph, NamedEdge, NamedGraphs, rename_vertices -using NamedGraphs.NamedGraphGenerators: named_grid, named_hexagonal_lattice_graph -using NamedGraphs.GraphsExtensions: - decorate_graph_edges, - forest_cover, - add_edges, - rem_edges, - add_vertices, - rem_vertices, - disjoint_union, - subgraph, - src, - dst -using NamedGraphs.PartitionedGraphs: PartitionVertex, partitionedge, unpartitioned_graph -using ITensorNetworks: - BeliefPropagationCache, - AbstractITensorNetwork, - AbstractFormNetwork, - IndsNetwork, - ITensorNetwork, - insert_linkinds, - ttn, - union_all_inds, - neighbor_vertices, - environment, - messages, - update_factor, - message, - partitioned_tensornetwork, - bra_vertex, - ket_vertex, - operator_vertex, - default_cache_update_kwargs, - dual_index_map, - region_scalar, - renormalize_messages, - scalar_factors_quotient, - norm_sqr_network -using DataGraphs: underlying_graph -using ITensorNetworks.ModelHamiltonians: heisenberg -using ITensors: - ITensor, - noprime, - dag, - noncommonind, - commonind, - replaceind, - dim, - noncommoninds, - delta, - replaceinds, - Trotter, - apply -using ITensors.NDTensors: denseblocks -using SplitApplyCombine: group - -using ITensors: siteinds, Op, prime, OpSum, apply -using Graphs: AbstractGraph, SimpleGraph, edges, vertices, is_tree, connected_components -using NamedGraphs: NamedGraph, NamedEdge, NamedGraphs, rename_vertices -using NamedGraphs.NamedGraphGenerators: named_grid, named_hexagonal_lattice_graph -using NamedGraphs.GraphsExtensions: - decorate_graph_edges, - forest_cover, - add_edges, - rem_edges, - add_vertices, - rem_vertices, - disjoint_union, - subgraph, - src, - dst -using NamedGraphs.PartitionedGraphs: PartitionVertex, partitionedge, unpartitioned_graph -using ITensorNetworks: - BeliefPropagationCache, - AbstractITensorNetwork, - AbstractFormNetwork, - IndsNetwork, - ITensorNetwork, - insert_linkinds, - ttn, - union_all_inds, - neighbor_vertices, - environment, - messages, - update_factor, - message, - partitioned_tensornetwork, - bra_vertex, - ket_vertex, - operator_vertex, - default_cache_update_kwargs, - dual_index_map -using DataGraphs: underlying_graph -using ITensorNetworks.ModelHamiltonians: heisenberg -using ITensors: - ITensor, - noprime, - dag, - noncommonind, - commonind, - replaceind, - dim, - noncommoninds, - delta, - replaceinds -using ITensors.NDTensors: denseblocks -using Dictionaries: set! - -function BP_apply( - o::ITensor, ψ::AbstractITensorNetwork, bpc::BeliefPropagationCache; apply_kwargs... -) - bpc = copy(bpc) - ψ = copy(ψ) - vs = neighbor_vertices(ψ, o) - envs = environment(bpc, PartitionVertex.(vs)) - singular_values! = Ref(ITensor()) - ψ = noprime(apply(o, ψ; envs, singular_values!, normalize=true, apply_kwargs...)) - ψdag = prime(dag(ψ); sites=[]) - if length(vs) == 2 - v1, v2 = vs - pe = partitionedge(bpc, (v1, "bra") => (v2, "bra")) - mts = messages(bpc) - ind1, ind2 = noncommonind(singular_values![], ψ[v1]), - commonind(singular_values![], ψ[v1]) - singular_values![] = denseblocks(replaceind(singular_values![], ind1, ind2')) - set!(mts, pe, ITensor[singular_values![]]) - set!(mts, reverse(pe), ITensor[singular_values![]]) - end - for v in vs - bpc = update_factor(bpc, (v, "ket"), ψ[v]) - bpc = update_factor(bpc, (v, "bra"), ψdag[v]) - end - return ψ, bpc -end - -function get_local_term(bpc::BeliefPropagationCache, v) - qf = tensornetwork(bpc) - return qf[(v, "ket")] * qf[(v, "operator")] * qf[(v, "bra")] -end - -function exact_energy(g::AbstractGraph, bpc::BeliefPropagationCache) - tn = ITensorNetwork(g) - for v in vertices(g) - tn[v] = get_local_term(bpc, v) - end - degree_two_sites = filter(v -> degree(tn, v) == 2, vertices(tn)) - while !isempty(degree_two_sites) - v = first(degree_two_sites) - vn = first(neighbors(g, v)) - tn = contract(tn, NamedEdge(v => vn); merged_vertex=vn) - degree_two_sites = filter(v -> degree(tn, v) == 2, vertices(tn)) - end - return ITensors.contract(ITensor[tn[v] for v in vertices(tn)]; sequence="automatic")[] -end - -function renamer(g) - vertex_rename = Dictionary() - for (i, v) in enumerate(vertices(g)) - set!(vertex_rename, v, (i,)) - end - return rename_vertices(v -> vertex_rename[v], g) -end - -function imaginary_time_evo( - s::IndsNetwork, - ψ::ITensorNetwork, - model::Function, - dbetas::Vector{<:Tuple}; - model_params, - bp_update_kwargs=(; maxiter=10, tol=1e-10), - apply_kwargs=(; cutoff=1e-12, maxdim=10), -) - ψ = copy(ψ) - g = underlying_graph(ψ) - - ℋ = model(g; model_params...) - ψψ = norm_sqr_network(ψ) - bpc = BeliefPropagationCache(ψψ, group(v -> v[1], vertices(ψψ))) - bpc = update(bpc; bp_update_kwargs...) - L = length(vertices(ψ)) - println("Starting Imaginary Time Evolution") - β = 0 - for (i, period) in enumerate(dbetas) - nbetas, dβ = first(period), last(period) - println("Entering evolution period $i , β = $β, dβ = $dβ") - U = exp(-dβ * ℋ; alg=Trotter{1}()) - gates = Vector{ITensor}(U, s) - for i in 1:nbetas - for gate in gates - ψ, bpc = BP_apply(gate, ψ, bpc; apply_kwargs...) - end - β += dβ - bpc = update(bpc; bp_update_kwargs...) - end - e = sum(expect(ψ, ℋ; alg="bp")) - println("Energy is $(e / L)") - end - - return ψ -end From 322dca4e9f33267809110e36da9ab79967171ad0 Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 12 Jun 2024 16:26:32 -0400 Subject: [PATCH 23/27] Revert --- src/solvers/sweep_plans/sweep_plans.jl | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/solvers/sweep_plans/sweep_plans.jl b/src/solvers/sweep_plans/sweep_plans.jl index d497494e..69221995 100644 --- a/src/solvers/sweep_plans/sweep_plans.jl +++ b/src/solvers/sweep_plans/sweep_plans.jl @@ -1,4 +1,4 @@ -using Graphs: AbstractEdge, dst, src, edges +using Graphs: AbstractEdge, dst, src using NamedGraphs.GraphsExtensions: GraphsExtensions direction(step_number) = isodd(step_number) ? Base.Forward : Base.Reverse @@ -143,23 +143,6 @@ function default_sweep_plans( return sweep_plans end -function bp_sweep_plan( - g::AbstractGraph; - root_vertex=GraphsExtensions.default_root_vertex(graph), - region_kwargs, - nsites::Int, - es=vcat(collect(edges(g)), collect(reverse(edges(g)))), - vs=vcat(reverse(collect(vertices(g))), collect(vertices(g))), -) - region_kwargs = (; internal_kwargs=(;), region_kwargs...) - - if nsites == 2 - return collect(flatten(map(e -> [([src(e), dst(e)], region_kwargs)], es))) - elseif nsites == 1 - return collect(flatten(map(v -> [([v], region_kwargs)], vs))) - end -end - function default_sweep_plan( graph::AbstractGraph; root_vertex=GraphsExtensions.default_root_vertex(graph), From 54f41c0c3f8a813a28c2cd8d0fa3d499251e54fe Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 12 Jun 2024 16:27:51 -0400 Subject: [PATCH 24/27] Revert --- src/solvers/insert/insert.jl | 70 +----------------------------------- 1 file changed, 1 insertion(+), 69 deletions(-) diff --git a/src/solvers/insert/insert.jl b/src/solvers/insert/insert.jl index e7183ad5..7776ca9e 100644 --- a/src/solvers/insert/insert.jl +++ b/src/solvers/insert/insert.jl @@ -46,72 +46,4 @@ function default_inserter( state[v] *= phi state = set_ortho_region(state, [v]) return state, nothing -end - -function bp_inserter( - ψ::AbstractITensorNetwork, - ψAψ_bpcs::Vector{<:BeliefPropagationCache}, - ψIψ_bpc::BeliefPropagationCache, - state::ITensor, - region; - cache_update_kwargs=(;), - kwargs..., -) - spec = nothing - - form_network = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) - ψAψ_bpcs = BeliefPropagationCache[reset_messages(ψAψ_bpc) for ψAψ_bpc in ψAψ_bpcs] - ψIψ_bpc = reset_messages(ψIψ_bpc) - @show messages(ψIψ_bpc) - if length(region) == 1 - states = [state] - elseif length(region) == 2 - v1, v2 = region[1], region[2] - e = edgetype(ψ)(v1, v2) - pe = partitionedge( - ψIψ_bpc, ket_vertex(form_network, v1) => bra_vertex(form_network, v2) - ) - stateᵥ₁, stateᵥ₂, spec = factorize_svd( - state, uniqueinds(ψ[v1], ψ[v2]); ortho="none", tags=edge_tag(e), kwargs... - ) - states = noprime.([stateᵥ₁, stateᵥ₂]) - #TODO: Insert spec into the message tensor guess here?! - end - - for (i, v) in enumerate(region) - state = states[i] - state_dag = copy(state) - form_bra_v, form_ket_v = bra_vertex(form_network, v), ket_vertex(form_network, v) - ψ[v] = state - state_dag = replaceinds( - dag(state_dag), inds(state_dag), dual_index_map(form_network).(inds(state_dag)) - ) - ψAψ_bpcs = BeliefPropagationCache[ - update_factor(ψAψ_bpc, form_ket_v, state) for ψAψ_bpc in ψAψ_bpcs - ] - ψAψ_bpcs = BeliefPropagationCache[ - update_factor(ψAψ_bpc, form_bra_v, state_dag) for ψAψ_bpc in ψAψ_bpcs - ] - ψIψ_bpc = update_factor(ψIψ_bpc, form_ket_v, state) - ψIψ_bpc = update_factor(ψIψ_bpc, form_bra_v, state_dag) - end - - ψAψ_bpcs = BeliefPropagationCache[ - update(ψAψ_bpc; cache_update_kwargs...) for ψAψ_bpc in ψAψ_bpcs - ] - - ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) - - updated_ψIψ = unpartitioned_graph(partitioned_tensornetwork(ψIψ_bpc)) - numerator_terms = [ - scalar( - unpartitioned_graph(partitioned_tensornetwork(ψAψ_bpc)); - (cache!)=Ref(ψAψ_bpc), - alg="bp", - ) for ψAψ_bpc in ψAψ_bpcs - ] - eigval = sum(numerator_terms) / scalar(updated_ψIψ; (cache!)=Ref(ψIψ_bpc), alg="bp") - @show eigval - @show scalar(only(ψAψ_bpcs); alg="exact") / scalar(ψIψ_bpc; alg="exact") - return ψ, ψAψ_bpcs, ψIψ_bpc, spec, (; eigvals=[eigval]) -end +end \ No newline at end of file From dc0e132db0fdcadfc739a8a0d28c8d1881f18c0a Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 12 Jun 2024 16:29:42 -0400 Subject: [PATCH 25/27] Revert --- src/abstractitensornetwork.jl | 2 +- src/lib/ITensorsExtensions/src/itensor.jl | 1 - src/solvers/insert/insert.jl | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/abstractitensornetwork.jl b/src/abstractitensornetwork.jl index 06bd5e27..b7d75327 100644 --- a/src/abstractitensornetwork.jl +++ b/src/abstractitensornetwork.jl @@ -834,8 +834,8 @@ function ITensorMPS.add(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork e1_v = filter(x -> src(x) == v || dst(x) == v, edges_tn1) e2_v = filter(x -> src(x) == v || dst(x) == v, edges_tn2) - @assert issetequal(e1_v, e2_v) + @assert issetequal(e1_v, e2_v) tn1v_linkinds = Index[only(linkinds(tn1, e)) for e in e1_v] tn2v_linkinds = Index[only(linkinds(tn2, e)) for e in e1_v] tn12v_linkinds = Index[new_edge_indices[e] for e in e1_v] diff --git a/src/lib/ITensorsExtensions/src/itensor.jl b/src/lib/ITensorsExtensions/src/itensor.jl index 4e01e0d8..8c834830 100644 --- a/src/lib/ITensorsExtensions/src/itensor.jl +++ b/src/lib/ITensorsExtensions/src/itensor.jl @@ -20,7 +20,6 @@ using ITensors.NDTensors: NDTensors, Block, Tensor, - array, blockdim, blockoffsets, denseblocks, diff --git a/src/solvers/insert/insert.jl b/src/solvers/insert/insert.jl index 7776ca9e..36671b48 100644 --- a/src/solvers/insert/insert.jl +++ b/src/solvers/insert/insert.jl @@ -46,4 +46,4 @@ function default_inserter( state[v] *= phi state = set_ortho_region(state, [v]) return state, nothing -end \ No newline at end of file +end From 2af39845c329228fb425d8fb8005379aa1e1acd9 Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 12 Jun 2024 16:43:29 -0400 Subject: [PATCH 26/27] revert --- src/solvers/insert/insert.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/solvers/insert/insert.jl b/src/solvers/insert/insert.jl index 36671b48..9e0005c3 100644 --- a/src/solvers/insert/insert.jl +++ b/src/solvers/insert/insert.jl @@ -22,6 +22,7 @@ function default_inserter( indsTe = inds(state[ortho_vert]) L, phi, spec = factorize(phi, indsTe; tags=tags(state, e), maxdim, mindim, cutoff) state[ortho_vert] = L + else v = ortho_vert end From 30786bc205ca2c3da408c6273de76a5e5d21fa97 Mon Sep 17 00:00:00 2001 From: Joey Date: Fri, 14 Jun 2024 11:43:20 -0400 Subject: [PATCH 27/27] Working version --- src/beliefpropagationdmrg/bp_dmrg.jl | 88 ++++++----------- src/beliefpropagationdmrg/bp_extracter.jl | 82 +++++++++------- src/beliefpropagationdmrg/bp_inserter.jl | 97 ++++++++++++------- src/beliefpropagationdmrg/bp_updater.jl | 2 +- src/beliefpropagationdmrg/main.jl | 10 +- .../tensornetworkoperators.jl | 67 ------------- 6 files changed, 149 insertions(+), 197 deletions(-) delete mode 100644 src/beliefpropagationdmrg/tensornetworkoperators.jl diff --git a/src/beliefpropagationdmrg/bp_dmrg.jl b/src/beliefpropagationdmrg/bp_dmrg.jl index 1910c0fa..bc02dc10 100644 --- a/src/beliefpropagationdmrg/bp_dmrg.jl +++ b/src/beliefpropagationdmrg/bp_dmrg.jl @@ -1,12 +1,6 @@ using NamedGraphs.GraphsExtensions: is_tree using NamedGraphs.PartitionedGraphs: partitionvertices, partitionedges, PartitionEdge -using ITensorNetworks: - ITensorNetwork, - QuadraticFormNetwork, - BeliefPropagationCache, - update, - default_message_update, - delete_messages +using ITensorNetworks: ITensorNetwork, QuadraticFormNetwork, BeliefPropagationCache, update, default_message_update, delete_messages using ITensors: scalar include("utils.jl") @@ -15,65 +9,47 @@ include("bp_inserter.jl") include("bp_updater.jl") include("graphsextensions.jl") -default_bp_update_kwargs(ψ::ITensorNetwork) = is_tree(ψ) ? (;) : (; maxiter=20, tol=1e-6) +default_bp_update_kwargs(ψ::ITensorNetwork) = is_tree(ψ) ? (;) : (; maxiter = 50, tol = 1e-8) -function initialize_caches( - ψ_init::ITensorNetwork, - operators::Vector{ITensorNetwork}; - cache_update_kwargs=default_bp_update_kwargs(ψ_init), -) - ψ = copy(ψ_init) - ψIψ = QuadraticFormNetwork(ψ) - ψIψ_bpc = BeliefPropagationCache(ψIψ) - - ψOψs = QuadraticFormNetwork[QuadraticFormNetwork(operator, ψ) for operator in operators] - ψOψ_bpcs = BeliefPropagationCache[BeliefPropagationCache(ψOψ) for ψOψ in ψOψs] - return (ψ, ψOψ_bpcs, ψIψ_bpc) +function initialize_cache(ψ_init::ITensorNetwork; cache_update_kwargs = default_bp_update_kwargs(ψ_init)) + ψ = copy(ψ_init) + ψIψ = QuadraticFormNetwork(ψ) + ψIψ_bpc = BeliefPropagationCache(ψIψ) + return (ψ, ψIψ_bpc) end -function bp_dmrg( - ψ_init::ITensorNetwork, - operators::Vector{<:ITensorNetwork}; - nsites=1, - no_sweeps=1, - bp_update_kwargs=default_bp_update_kwargs(ψ_init), - energy_calc_fun, -) - L = length(vertices(ψ_init)) - state, ψOψ_bpcs, ψIψ_bpc = initialize_caches(ψ_init, operators) - state_vertices = collect(vertices(state)) - regions = [[v] for v in vcat(state_vertices, reverse(state_vertices))] +function bp_dmrg(ψ_init::ITensorNetwork, H::OpSum; nsites = 1, no_sweeps = 1, bp_update_kwargs = default_bp_update_kwargs(ψ_init)) - state, ψOψ_bpcs, ψIψ_bpc = renormalize_update_norm_cache( - state, ψOψ_bpcs, ψIψ_bpc; cache_update_kwargs=bp_update_kwargs - ) + L = length(vertices(ψ_init)) + state, ψIψ_bpc = initialize_cache(ψ_init) + state_vertices, state_edges = collect(vertices(state)), edges(state) + if nsites == 1 + regions = [[v] for v in vcat(state_vertices, reverse(state_vertices))] + else + regions = [[src(e), dst(e)] for e in vcat(state_edges, reverse(state_edges))] + end + state, ψIψ_bpc = renormalize_update_norm_cache(state, ψIψ_bpc; cache_update_kwargs = bp_update_kwargs) - energy = real(energy_calc_fun(state, ψIψ_bpc)) - println("Initial energy density is $(energy)") - energies = [energy] + energy = sum(expect(state, H; alg="bp", (cache!)=Ref(ψIψ_bpc))) / L + println("Initial energy density is $(energy)") + energies = [energy] - for i in 1:no_sweeps - println("Beginning sweep $i") - for region in regions - println("Updating vertex $region") + for i in 1:no_sweeps + println("Beginning sweep $i") + for region in regions + println("Updating vertex $region") - local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts = bp_extracter( - state, ψOψ_bpcs, ψIψ_bpc, region - ) + local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts, ψ, ψIψ_bpc = bp_extracter_V3(state, H, ψIψ_bpc, region) - local_state, energy = bp_eigsolve_updater( - local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts - ) + local_state, energy = bp_eigsolve_updater(local_state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts) - state, ψOψ_bpcs, ψIψ_bpc = bp_inserter( - state, ψOψ_bpcs, ψIψ_bpc, local_state, region; bp_update_kwargs - ) + state, ψIψ_bpc = bp_inserter(state, ψIψ_bpc, local_state, region; bp_update_kwargs) - energy = energy_calc_fun(state, ψIψ_bpc) - append!(energies, energy) - println("Current energy density is $(energy)") + energy = sum(expect(state, H; alg="bp", (cache!)=Ref(ψIψ_bpc))) / L + append!(energies, energy) + println("Current energy density is $(energy)") + end end - end - return state, energies + return state, energies end diff --git a/src/beliefpropagationdmrg/bp_extracter.jl b/src/beliefpropagationdmrg/bp_extracter.jl index 910f2519..00b6f099 100644 --- a/src/beliefpropagationdmrg/bp_extracter.jl +++ b/src/beliefpropagationdmrg/bp_extracter.jl @@ -1,59 +1,71 @@ -using ITensors: scalartype +using ITensors: scalartype, which_op, name, names using ITensorNetworks: ket_vertices, bra_vertices, tensornetwork, default_message_update, operator_network using ITensorNetworks.ITensorsExtensions: map_eigvals -function update_caches_effective_environments( - state::ITensorNetwork, - ψOψ_bpcs::Vector{<:BeliefPropagationCache}, - ψIψ_bpc::BeliefPropagationCache, - region, -) - operators = operator_network.(tensornetwork.(ψOψ_bpcs)) +function effective_environments(state::ITensorNetwork, H::OpSum, ψIψ_bpc::BeliefPropagationCache, region) + environments = Vector{ITensor}[] + s = siteinds(state) + op_tensors = Vector{ITensor}(H, s) + for (i, term) in enumerate(H) + if length(sites(term)) == 1 && !iszero(first(term.args)) + path = a_star(state, only(sites(term)), only(region)) + ψOψ_qf = QuadraticFormNetwork(state) - ψIψ_bpc_mts = messages(ψIψ_bpc) - new_ψOψ_bpcs = BeliefPropagationCache[] + ψOψ_qf[(only(sites(term)), "operator")] = op_tensors[i] + elseif length(sites(term)) == 2 && !iszero(first(term.args)) + v1, v2 = first(sites(term)), last(sites(term)) + path = a_star(state, v1, only(region)) + if v2 ∉ src.(path) && v2 ∉ dst.(path) + prepend!(path, NamedEdge[NamedEdge(v2 => v1)]) + end + Ov1, Ov2 = factorize_svd(op_tensors[i], s[v1], s[v1]'; cutoff = 1e-16) + ψOψ_qf = QuadraticFormNetwork(state) + ψOψ_qf[(v1, "operator")] = Ov1 + ψOψ_qf[(v2, "operator")] = Ov2 + else + path = nothing + end + if !isnothing(path) + env = ITensor(1.0) + path = vcat(src.(path)) + for v in path + env *= get_local_term(ψOψ_qf, v) + vns = neighbors(state, v) + for vn in vns + if vn ∉ path && vn != only(region) + env *= only(message(ψIψ_bpc, PartitionEdge(vn => v))) + end + end + end + for vn in neighbors(state, only(region)) + if vn ∉ path + env *= only(message(ψIψ_bpc, PartitionEdge(vn => only(region)))) + end + end + env *= ψOψ_qf[(only(region), "operator")] - for (ψOψ_bpc, operator) in zip(ψOψ_bpcs, operators) - new_ψOψ_bpc = copy(ψOψ_bpc) - ptn = partitioned_tensornetwork(new_ψOψ_bpc) - edge_seq = reduce( - vcat, [post_order_dfs_edges(underlying_graph(operator), v) for v in region] - ) - broken_edges = setdiff(edges(state), edges(operator)) - partition_broken_edges = PartitionEdge.(broken_edges) - partition_broken_edges = vcat(partition_broken_edges, reverse.(partition_broken_edges)) - mts = messages(new_ψOψ_bpc) - for pe in partition_broken_edges - set!(mts, pe, copy(ψIψ_bpc_mts[pe])) + push!(environments, [env]) end - partition_edge_seq = unique(PartitionEdge.(edge_seq)) - new_ψOψ_bpc = update( - new_ψOψ_bpc, - partition_edge_seq; - message_update=tns -> default_message_update(tns; normalize=false), - ) - push!(new_ψOψ_bpcs, new_ψOψ_bpc) end - return state, new_ψOψ_bpcs, ψIψ_bpc + return environments end function bp_extracter( ψ::AbstractITensorNetwork, - ψOψ_bpcs::Vector{<:BeliefPropagationCache}, + H::OpSum, ψIψ_bpc::BeliefPropagationCache, region; regularization=10 * eps(scalartype(ψ)), ishermitian=true, ) - ψ, ψOψ_bpcs, ψIψ_bpc = update_caches_effective_environments(ψ, ψOψ_bpcs, ψIψ_bpc, region) form_network = tensornetwork(ψIψ_bpc) form_ket_vertices, form_bra_vertices = ket_vertices(form_network, region), bra_vertices(form_network, region) - ∂ψOψ_bpc_∂rs = environment.(ψOψ_bpcs, ([form_ket_vertices; form_bra_vertices],)) + ∂ψOψ_bpc_∂rs = effective_environments(ψ, H, ψIψ_bpc, region) state = prod([ψ[v] for v in region]) messages = environment(ψIψ_bpc, partitionvertices(ψIψ_bpc, form_ket_vertices)) f_sqrt = sqrt ∘ (x -> x + regularization) @@ -67,5 +79,5 @@ function bp_extracter( (f_inv_sqrt,), messages, first.(inds.(messages)), last.(inds.(messages)); ishermitian ) - return state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts -end + return state, ∂ψOψ_bpc_∂rs, sqrt_mts, inv_sqrt_mts, ψ, ψIψ_bpc +end \ No newline at end of file diff --git a/src/beliefpropagationdmrg/bp_inserter.jl b/src/beliefpropagationdmrg/bp_inserter.jl index 56b08917..70aa91ad 100644 --- a/src/beliefpropagationdmrg/bp_inserter.jl +++ b/src/beliefpropagationdmrg/bp_inserter.jl @@ -33,42 +33,69 @@ function renormalize_update_norm_cache( return ψ, ψOψ_bpcs, ψIψ_bpc end +function renormalize_update_norm_cache( + ψ::ITensorNetwork, + ψIψ_bpc::BeliefPropagationCache; + cache_update_kwargs, + ) + ψ = copy(ψ) + ψIψ_bpc = delete_messages(ψIψ_bpc) + ψIψ_bpc = update(ψIψ_bpc; cache_update_kwargs...) + ψIψ_bpc = renormalize_messages(ψIψ_bpc) + qf = tensornetwork(ψIψ_bpc) + + for v in vertices(ψ) + v_ket, v_bra = ket_vertex(qf, v), bra_vertex(qf, v) + pv = only(partitionvertices(ψIψ_bpc, [v_ket])) + vn = region_scalar(ψIψ_bpc, pv) + state = (1.0 / sqrt(vn)) * ψ[v] + state_dag = copy(dag(state)) + state_dag = replaceinds( + state_dag, inds(state_dag), dual_index_map(qf).(inds(state_dag)) + ) + vertices_states = Dictionary([v_ket, v_bra], [state, state_dag]) + ψIψ_bpc = update_factors(ψIψ_bpc, vertices_states) + ψ[v] = state + end + + return ψ, ψIψ_bpc +end + #TODO: Add support for nsites = 2 function bp_inserter( - ψ::AbstractITensorNetwork, - ψOψ_bpcs::Vector{<:BeliefPropagationCache}, - ψIψ_bpc::BeliefPropagationCache, - state::ITensor, - region; - nsites::Int64=1, - bp_update_kwargs, - kwargs..., -) - ψ = copy(ψ) - form_network = tensornetwork(ψIψ_bpc) - if length(region) == 1 - states = ITensor[state] - else - error("Region lengths of more than 1 not supported for now") - end - - for (state, v) in zip(states, region) - ψ[v] = state - state_dag = copy(ψ[v]) - state_dag = replaceinds( - dag(state_dag), inds(state_dag), dual_index_map(form_network).(inds(state_dag)) + ψ::AbstractITensorNetwork, + ψIψ_bpc::BeliefPropagationCache, + state::ITensor, + region; + nsites::Int64=1, + bp_update_kwargs, + kwargs..., + ) + ψ = copy(ψ) + form_network = tensornetwork(ψIψ_bpc) + if length(region) == 1 + states = ITensor[state] + else + error("Region lengths of more than 1 not supported for now") + end + + for (state, v) in zip(states, region) + ψ[v] = state + state_dag = copy(ψ[v]) + state_dag = replaceinds( + dag(state_dag), inds(state_dag), dual_index_map(form_network).(inds(state_dag)) + ) + form_bra_v, form_op_v, form_ket_v = bra_vertex(form_network, v), + operator_vertex(form_network, v), + ket_vertex(form_network, v) + vertices_states = Dictionary([form_ket_v, form_bra_v], [state, state_dag]) + ψIψ_bpc = update_factors(ψIψ_bpc, vertices_states) + end + + ψ, ψIψ_bpc = renormalize_update_norm_cache( + ψ, ψIψ_bpc; cache_update_kwargs=bp_update_kwargs ) - form_bra_v, form_op_v, form_ket_v = bra_vertex(form_network, v), - operator_vertex(form_network, v), - ket_vertex(form_network, v) - vertices_states = Dictionary([form_ket_v, form_bra_v], [state, state_dag]) - ψOψ_bpcs = update_factors.(ψOψ_bpcs, (vertices_states,)) - ψIψ_bpc = update_factors(ψIψ_bpc, vertices_states) + + return ψ, ψIψ_bpc end - - ψ, ψOψ_bpcs, ψIψ_bpc = renormalize_update_norm_cache( - ψ, ψOψ_bpcs, ψIψ_bpc; cache_update_kwargs=bp_update_kwargs - ) - - return ψ, ψOψ_bpcs, ψIψ_bpc -end + diff --git a/src/beliefpropagationdmrg/bp_updater.jl b/src/beliefpropagationdmrg/bp_updater.jl index 1287601d..ff247cc1 100644 --- a/src/beliefpropagationdmrg/bp_updater.jl +++ b/src/beliefpropagationdmrg/bp_updater.jl @@ -3,7 +3,7 @@ using ITensors.ContractionSequenceOptimization: optimal_contraction_sequence using KrylovKit: eigsolve function default_krylov_kwargs() - return (; tol=1e-14, krylovdim=10, maxiter=1, verbosity=0, eager=false, ishermitian=true) + return (; tol=1e-15, krylovdim=100, maxiter=100, verbosity=0, eager=false, ishermitian=true) end #TODO: Put inv_sqrt_mts onto ∂ψOψ_bpc_∂r beforehand. Need to do this in an efficient way without diff --git a/src/beliefpropagationdmrg/main.jl b/src/beliefpropagationdmrg/main.jl index b2bb690f..8a7094c5 100644 --- a/src/beliefpropagationdmrg/main.jl +++ b/src/beliefpropagationdmrg/main.jl @@ -6,6 +6,8 @@ using Random include("graphsextensions.jl") include("tensornetworkoperators.jl") include("bp_dmrg.jl") +include("bp_dmrg_V2.jl") +include("utils.jl") Random.seed!(5634) @@ -14,16 +16,18 @@ function main() L = length(vertices(g)) h, hlongitudinal, J = 0.6, 0.2, 1.0 s = siteinds("S=1/2", g) - χ = 2 + χ = 3 ψ0 = random_tensornetwork(s; link_space=χ) H = ising(s; h, hl=hlongitudinal, J1=J) - tnos = opsum_to_tnos(s, H) + #tnos = opsum_to_tnos_V2(s, H) + #tno = reduce(+, tnos) energy_calc_fun = (tn, bp_cache) -> sum(expect(tn, H; alg="bp", (cache!)=Ref(bp_cache))) / L - ψfinal, energies = bp_dmrg(ψ0, tnos; no_sweeps=5, energy_calc_fun) + #ψfinal, energies = bp_dmrg(ψ0, tnos; no_sweeps=5, energy_calc_fun) + ψfinal, energies = bp_dmrg(ψ0, H; no_sweeps=5) return final_mags = expect(ψfinal, "Z", ; alg="bp") end diff --git a/src/beliefpropagationdmrg/tensornetworkoperators.jl b/src/beliefpropagationdmrg/tensornetworkoperators.jl deleted file mode 100644 index 4dc971ac..00000000 --- a/src/beliefpropagationdmrg/tensornetworkoperators.jl +++ /dev/null @@ -1,67 +0,0 @@ -using NamedGraphs: NamedGraph, AbstractGraph, vertices, edges, NamedEdge -using NamedGraphs.NamedGraphGenerators: named_grid, named_hexagonal_lattice_graph -using NamedGraphs.GraphsExtensions: - forest_cover, - connected_components, - add_edges, - add_edge, - add_vertices, - rem_edges, - decorate_graph_edges, - rename_vertices - -using ITensors: OpSum, siteinds, sites, inds, combiner -using ITensors.NDTensors: array -using ITensorNetworks: - AbstractITensorNetwork, ITensorNetwork, IndsNetwork, underlying_graph, ttn, maxlinkdim -using ITensorNetworks.ModelHamiltonians: ising -using Dictionaries - -using LinearAlgebra: eigvals - -#Convert the forests in forest_cover to trees by adding "dummy" edges and keep track of them -function connect_forests(s::IndsNetwork) - g = underlying_graph(s) - fs = forest_cover(g) - fs_connected = Tuple{IndsNetwork,Vector{NamedEdge}}[] - for f in fs - s_f = copy(s) - verts = vertices(f) - es = edges(f) - c_f = NamedGraph[f[vs] for vs in connected_components(f)] - dummy_es = NamedEdge[ - NamedEdge(first(vertices(c_f[i])) => first(vertices(c_f[i + 1]))) for - i in 1:(length(c_f) - 1) - ] - s_f = rem_edges(s_f, edges(s_f)) - s_f = add_edges(s_f, vcat(es, dummy_es)) - push!(fs_connected, (s_f, dummy_es)) - end - return fs_connected -end - -#Convert an Opsum to a vector of tensor network operators whose sum matches opsum -function opsum_to_tnos(s::IndsNetwork, H::OpSum; cutoff::Float64=1e-14) - s_fs_connected = connect_forests(s) - no_forests = length(s_fs_connected) - tnos = ITensorNetwork[] - for (s_f, dummy_edges) in s_fs_connected - real_es = setdiff(edges(s_f), dummy_edges) - new_opsum = OpSum() - for term in H - if length(sites(term)) == 1 && !iszero(first(term.args)) - new_opsum += (1.0 / no_forests) * term - elseif length(sites(term)) == 2 && !iszero(first(term.args)) - e = NamedEdge(first(sites(term)) => last(sites(term))) - if (e ∈ real_es || reverse(e) ∈ real_es) - new_opsum += term - end - end - end - tno = truncate(ttn(new_opsum, s_f); cutoff) - tno = ITensorNetwork(tno) - push!(tnos, tno) - end - - return tnos -end