From e153279667094f63ba3674d41696b12788c5d0c7 Mon Sep 17 00:00:00 2001 From: annamariadziubyna Date: Fri, 26 Jul 2024 11:03:46 +0200 Subject: [PATCH] rename cl_h to potts_h --- docs/src/api.md | 2 +- docs/src/clh.md | 2 +- docs/src/lattice.md | 10 +-- examples/bp.jl | 12 +-- examples/temp.jl | 14 +-- src/bp.jl | 160 ++++++++++++++++----------------- src/potts_hamiltonian.jl | 182 +++++++++++++++++++------------------- src/truncate.jl | 50 +++++------ test/bp_1site.jl | 18 ++-- test/bp_2site.jl | 56 ++++++------ test/potts_hamiltonian.jl | 76 ++++++++-------- test/utils.jl | 6 +- 12 files changed, 294 insertions(+), 294 deletions(-) diff --git a/docs/src/api.md b/docs/src/api.md index 05a7aad..8a78487 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -31,7 +31,7 @@ interaction_energy get_neighbors MergedEnergy update_message -merge_vertices_cl_h +merge_vertices_potts_h projector SparseCSC ``` diff --git a/docs/src/clh.md b/docs/src/clh.md index 4e76131..c588b01 100644 --- a/docs/src/clh.md +++ b/docs/src/clh.md @@ -17,7 +17,7 @@ instance = "$(@__DIR__)/../../src/instances/square_diagonal/5x5/diagonal.txt" ig = ising_graph(instance) # Create Potts Hamiltonian -cl_h = potts_hamiltonian( +potts_h = potts_hamiltonian( ig, cluster_assignment_rule = super_square_lattice((5,5,4)) ) diff --git a/docs/src/lattice.md b/docs/src/lattice.md index 32ac431..5f2ddc6 100644 --- a/docs/src/lattice.md +++ b/docs/src/lattice.md @@ -27,12 +27,12 @@ m = 5 n = 5 t = 4 -cl_h = potts_hamiltonian( +potts_h = potts_hamiltonian( ig, cluster_assignment_rule = super_square_lattice((m, n, t)) ) -println("Number of nodes in oryginal instance: ", length(LabelledGraphs.vertices(ig)), "\n", " Number of nodes in Potts Hamiltonian: ", length(LabelledGraphs.vertices(cl_h))) +println("Number of nodes in oryginal instance: ", length(LabelledGraphs.vertices(ig)), "\n", " Number of nodes in Potts Hamiltonian: ", length(LabelledGraphs.vertices(potts_h))) ``` ## Pegasus graphs @@ -61,12 +61,12 @@ m = 3 n = 3 t = 3 -cl_h = potts_hamiltonian( +potts_h = potts_hamiltonian( ig, cluster_assignment_rule = pegasus_lattice((m, n, t)) ) -println("Number of nodes in original instance: ", length(LabelledGraphs.vertices(ig)), "\n", " Number of nodes in Potts Hamiltonian: ", length(LabelledGraphs.vertices(cl_h))/2) +println("Number of nodes in original instance: ", length(LabelledGraphs.vertices(ig)), "\n", " Number of nodes in Potts Hamiltonian: ", length(LabelledGraphs.vertices(potts_h))/2) ``` @@ -96,7 +96,7 @@ m = 6 n = 6 t = 4 -cl_h = potts_hamiltonian( +potts_h = potts_hamiltonian( ig, cluster_assignment_rule = zephyr_lattice((m, n, t)) ) diff --git a/examples/bp.jl b/examples/bp.jl index 5e3f596..b327460 100644 --- a/examples/bp.jl +++ b/examples/bp.jl @@ -48,22 +48,22 @@ function create_larger_example_potts_hamiltonian_tree() 9 => (3, 3, 1), ) - cl_h = potts_hamiltonian( + potts_h = potts_hamiltonian( ig, Dict{NTuple{3,Int},Int}(), spectrum = full_spectrum, cluster_assignment_rule = assignment_rule, ) - ig, cl_h + ig, potts_h end -ig, cl_h = create_larger_example_potts_hamiltonian_tree() +ig, potts_h = create_larger_example_potts_hamiltonian_tree() beta = 0.1 iter = 0 -beliefs = belief_propagation(cl_h, beta; iter = iter) +beliefs = belief_propagation(potts_h, beta; iter = iter) -for v in vertices(cl_h) - en = get_prop(cl_h, v, :spectrum).energies +for v in vertices(potts_h) + en = get_prop(potts_h, v, :spectrum).energies println("vertex ", v, " energy = ", en .- minimum(en), " bp = ", beliefs[v]) end diff --git a/examples/temp.jl b/examples/temp.jl index fcf510a..6f99cf0 100644 --- a/examples/temp.jl +++ b/examples/temp.jl @@ -88,27 +88,27 @@ function potts_hamiltonian(fname::String, Nx::Integer = 240, Ny::Integer = 320) N = loaded_rmf["N"] clusters = super_square_lattice((Nx, Ny, 1)) - cl_h = LabelledGraph{MetaDiGraph}(sort(collect(values(clusters)))) - for v ∈ cl_h.labels + potts_h = LabelledGraph{MetaDiGraph}(sort(collect(values(clusters)))) + for v ∈ potts_h.labels x, y = v sp = Spectrum( Vector{Real}(undef, 1), Array{Vector{Int}}(undef, 1, 1), Vector{Int}(undef, 1), ) - set_props!(cl_h, v, Dict(:cluster => v, :spectrum => sp)) + set_props!(potts_h, v, Dict(:cluster => v, :spectrum => sp)) end for (index, value) in factors if length(index) == 2 y, x = index Eng = sum(functions[value]) - set_props!(cl_h, (x + 1, y + 1), Dict(:eng => Eng)) + set_props!(potts_h, (x + 1, y + 1), Dict(:eng => Eng)) elseif length(index) == 4 y1, x1, y2, x2 = index - add_edge!(cl_h, (x1 + 1, y1 + 1), (x2 + 1, y2 + 1)) + add_edge!(potts_h, (x1 + 1, y1 + 1), (x2 + 1, y2 + 1)) Eng = sum(functions[value], dims = 2) set_props!( - cl_h, + potts_h, (x1 + 1, y1 + 1), (x2 + 1, y2 + 1), Dict( @@ -127,7 +127,7 @@ function potts_hamiltonian(fname::String, Nx::Integer = 240, Ny::Integer = 320) end end - cl_h + potts_h end diff --git a/src/bp.jl b/src/bp.jl index 7575813..0b62afb 100644 --- a/src/bp.jl +++ b/src/bp.jl @@ -5,7 +5,7 @@ export belief_propagation, get_neighbors, MergedEnergy, update_message, - merge_vertices_cl_h, + merge_vertices_potts_h, local_energy, interaction_energy, SparseCSC @@ -15,7 +15,7 @@ $(TYPEDSIGNATURES) Perform loopy belief propagation on a given Potts Hamiltonian. # Arguments: -- `cl_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labelled graph. +- `potts_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labelled graph. - `beta::Real`: The inverse temperature parameter for the belief propagation algorithm. - `tol::Real (optional, default=1e-6)`: The convergence tolerance. The algorithm stops when the message updates between iterations are smaller than this value. - `iter::Int (optional, default=1)`: The maximum number of iterations to perform. @@ -24,13 +24,13 @@ Perform loopy belief propagation on a given Potts Hamiltonian. - `beliefs::Dict`: A dictionary where keys are vertices of Potts Hamiltonian, and values are the resulting beliefs after belief propagation. -The function implements loopy belief propagation on the given Potts Hamiltonian `cl_h` to calculate beliefs for each vertex. +The function implements loopy belief propagation on the given Potts Hamiltonian `potts_h` to calculate beliefs for each vertex. Belief propagation is an iterative algorithm that computes beliefs by passing messages between vertices and edges of the Potts Hamiltonian. The algorithm continues until convergence or until the specified maximum number of iterations is reached. The beliefs are computed based on the inverse temperature parameter `beta`, which controls the influence of energy values on the beliefs. """ function belief_propagation( - cl_h::LabelledGraph{S,T}, + potts_h::LabelledGraph{S,T}, beta::Real; tol = 1e-6, iter = 1, @@ -39,8 +39,8 @@ function belief_propagation( messages_ev = Dict() # Initialize messages with uniform probabilities - for v in vertices(cl_h) - for (n, pv, _) in get_neighbors(cl_h, v) + for v in vertices(potts_h) + for (n, pv, _) in get_neighbors(potts_h, v) push!(messages_ev, (n, v) => ones(maximum(pv))) end end @@ -51,16 +51,16 @@ function belief_propagation( while !converged && iteration < iter # Set an appropriate number of iterations and convergence threshold iteration += 1 old_messages_ev = deepcopy(messages_ev) - for v in vertices(cl_h) + for v in vertices(potts_h) #update messages from vertex to edge node_messages = Dict() - for (n1, pv1, _) ∈ get_neighbors(cl_h, v) + for (n1, pv1, _) ∈ get_neighbors(potts_h, v) node_messages[n1, v] = messages_ev[n1, v][pv1] end - for (n1, pv1, _) ∈ get_neighbors(cl_h, v) - E_local = get_prop(cl_h, v, :spectrum).energies + for (n1, pv1, _) ∈ get_neighbors(potts_h, v) + E_local = get_prop(potts_h, v, :spectrum).energies temp = exp.(-(E_local .- minimum(E_local)) * beta) - for (n2, pv2, _) in get_neighbors(cl_h, v) + for (n2, pv2, _) in get_neighbors(potts_h, v) if n1 == n2 continue end @@ -72,8 +72,8 @@ function belief_propagation( end #update messages from edge to vertex - for v in vertices(cl_h) - for (n, _, en) ∈ get_neighbors(cl_h, v) + for v in vertices(potts_h) + for (n, _, en) ∈ get_neighbors(potts_h, v) messages_ev[n, v] = update_message(en, messages_ve[n, v], beta) end end @@ -86,10 +86,10 @@ function belief_propagation( end beliefs = Dict() - for v in vertices(cl_h) - E_local = get_prop(cl_h, v, :spectrum).energies + for v in vertices(potts_h) + E_local = get_prop(potts_h, v, :spectrum).energies beliefs[v] = exp.(-E_local * beta) - for (n, pv, _) ∈ get_neighbors(cl_h, v) + for (n, pv, _) ∈ get_neighbors(potts_h, v) beliefs[v] .*= messages_ev[n, v][pv] end beliefs[v] = -log.(beliefs[v]) ./ beta @@ -104,7 +104,7 @@ $(TYPEDSIGNATURES) Returns the neighbors of a given vertex in a Potts Hamiltonian. # Arguments: -- `cl_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. +- `potts_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. - `vertex::NTuple`: The vertex for which neighbors are to be retrieved. # Returns: @@ -118,19 +118,19 @@ This function retrieves the neighbors of a given vertex in a Potts Hamiltonian g It iterates through the edges of the graph and identifies edges connected to the specified vertex. For each neighboring edge, it extracts and returns the neighboring vertex, the associated projector, and the energy. """ -function get_neighbors(cl_h::LabelledGraph{S,T}, vertex::NTuple) where {S,T} +function get_neighbors(potts_h::LabelledGraph{S,T}, vertex::NTuple) where {S,T} neighbors = [] - for edge in edges(cl_h) + for edge in edges(potts_h) src_node, dst_node = src(edge), dst(edge) if src_node == vertex - en = get_prop(cl_h, src_node, dst_node, :en) - idx_pv = get_prop(cl_h, src_node, dst_node, :ipl) - pv = get_projector!(get_prop(cl_h, :pool_of_projectors), idx_pv, :CPU) + en = get_prop(potts_h, src_node, dst_node, :en) + idx_pv = get_prop(potts_h, src_node, dst_node, :ipl) + pv = get_projector!(get_prop(potts_h, :pool_of_projectors), idx_pv, :CPU) push!(neighbors, (dst_node, pv, en)) elseif dst_node == vertex - en = get_prop(cl_h, src_node, dst_node, :en)' - idx_pv = get_prop(cl_h, src_node, dst_node, :ipr) - pv = get_projector!(get_prop(cl_h, :pool_of_projectors), idx_pv, :CPU) + en = get_prop(potts_h, src_node, dst_node, :en)' + idx_pv = get_prop(potts_h, src_node, dst_node, :ipr) + pv = get_projector!(get_prop(potts_h, :pool_of_projectors), idx_pv, :CPU) push!(neighbors, (src_node, pv, en)) end end @@ -258,41 +258,41 @@ $(TYPEDSIGNATURES) Constructs a Potts Hamiltonian for a given Potts Hamiltonian with a 2-site cluster approximation used in Pegasus graph. # Arguments: -- `cl_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labelled graph. +- `potts_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labelled graph. - `beta::Real`: The inverse temperature parameter for the 2-site cluster Hamiltonian construction. # Returns: -- `new_cl_h::LabelledGraph{MetaDiGraph}`: A new labelled graph representing the 2-site cluster Hamiltonian. +- `new_potts_h::LabelledGraph{MetaDiGraph}`: A new labelled graph representing the 2-site cluster Hamiltonian. -This function constructs a Potts Hamiltonian `cl_h` by applying a 2-site cluster approximation. +This function constructs a Potts Hamiltonian `potts_h` by applying a 2-site cluster approximation. It combines and merges vertices and edges of the original graph to create a simplified representation of the Hamiltonian. -The resulting `new_cl_h` graph represents the 2-site cluster Hamiltonian with simplified interactions between clusters. +The resulting `new_potts_h` graph represents the 2-site cluster Hamiltonian with simplified interactions between clusters. The energy values, projectors, and spectra associated with the new vertices and edges are computed based on the provided temperature parameter `beta`. """ -function potts_hamiltonian_2site(cl_h::LabelledGraph{S,T}, beta::Real) where {S,T} +function potts_hamiltonian_2site(potts_h::LabelledGraph{S,T}, beta::Real) where {S,T} - unified_vertices = unique([vertex[1:2] for vertex in vertices(cl_h)]) - new_cl_h = LabelledGraph{MetaDiGraph}(unified_vertices) + unified_vertices = unique([vertex[1:2] for vertex in vertices(potts_h)]) + new_potts_h = LabelledGraph{MetaDiGraph}(unified_vertices) new_lp = PoolOfProjectors{Int}() vertx = Set() - for v in vertices(cl_h) + for v in vertices(potts_h) i, j, _ = v if (i, j) ∈ vertx continue end - E1 = local_energy(cl_h, (i, j, 1)) - E2 = local_energy(cl_h, (i, j, 2)) - E = energy_2site(cl_h, i, j) .+ reshape(E1, :, 1) .+ reshape(E2, 1, :) + E1 = local_energy(potts_h, (i, j, 1)) + E2 = local_energy(potts_h, (i, j, 2)) + E = energy_2site(potts_h, i, j) .+ reshape(E1, :, 1) .+ reshape(E2, 1, :) sp = Spectrum(reshape(E, :), [], []) - set_props!(new_cl_h, (i, j), Dict(:spectrum => sp)) + set_props!(new_potts_h, (i, j), Dict(:spectrum => sp)) push!(vertx, (i, j)) end edge_states = Set() - for e ∈ edges(cl_h) + for e ∈ edges(potts_h) if e in edge_states continue end @@ -304,16 +304,16 @@ function potts_hamiltonian_2site(cl_h::LabelledGraph{S,T}, beta::Real) where {S, continue end - add_edge!(new_cl_h, (v1, v2), (w1, w2)) + add_edge!(new_potts_h, (v1, v2), (w1, w2)) - E, pl, pr = merge_vertices_cl_h(cl_h, beta, v, w) + E, pl, pr = merge_vertices_potts_h(potts_h, beta, v, w) ipl = add_projector!(new_lp, pl) ipr = add_projector!(new_lp, pr) - set_props!(new_cl_h, (v1, v2), (w1, w2), Dict(:ipl => ipl, :en => E, :ipr => ipr)) + set_props!(new_potts_h, (v1, v2), (w1, w2), Dict(:ipl => ipl, :en => E, :ipr => ipr)) push!(edge_states, sort([(v1, v2), (w1, w2)])) end - set_props!(new_cl_h, Dict(:pool_of_projectors => new_lp)) - new_cl_h + set_props!(new_potts_h, Dict(:pool_of_projectors => new_lp)) + new_potts_h end """ @@ -322,7 +322,7 @@ $(TYPEDSIGNATURES) Merge two vertices in a Potts Hamiltonian to create a single merged vertex. # Arguments: -- `cl_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. +- `potts_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. - `β::Real`: The temperature parameter controlling the influence of energy values. - `node1::NTuple{3, Int64}`: The coordinates of the first vertex to merge. - `node2::NTuple{3, Int64}`: The coordinates of the second vertex to merge. @@ -332,15 +332,15 @@ Merge two vertices in a Potts Hamiltonian to create a single merged vertex. - `pl::AbstractVector`: The merged left projector. - `pr::AbstractVector`: The merged right projector. -This function merges two vertices in a Potts Hamiltonian graph `cl_h` to create a single merged vertex. +This function merges two vertices in a Potts Hamiltonian graph `potts_h` to create a single merged vertex. The merging process combines projectors and energy values associated with the original vertices based on the provided temperature parameter `β`. The merged energy values, left projector `pl`, and right projector `pr` are computed based on the interactions between the original vertices and their respective projectors. """ -function merge_vertices_cl_h( - cl_h::LabelledGraph{S,T}, +function merge_vertices_potts_h( + potts_h::LabelledGraph{S,T}, β::Real, node1::NTuple{3,Int64}, node2::NTuple{3,Int64}, @@ -348,18 +348,18 @@ function merge_vertices_cl_h( i1, j1, _ = node1 i2, j2, _ = node2 - p21l = projector(cl_h, (i1, j1, 2), (i2, j2, 1)) - p22l = projector(cl_h, (i1, j1, 2), (i2, j2, 2)) - p12l = projector(cl_h, (i1, j1, 1), (i2, j2, 2)) - p11l = projector(cl_h, (i1, j1, 1), (i2, j2, 1)) + p21l = projector(potts_h, (i1, j1, 2), (i2, j2, 1)) + p22l = projector(potts_h, (i1, j1, 2), (i2, j2, 2)) + p12l = projector(potts_h, (i1, j1, 1), (i2, j2, 2)) + p11l = projector(potts_h, (i1, j1, 1), (i2, j2, 1)) p1l, (p11l, p12l) = fuse_projectors((p11l, p12l)) p2l, (p21l, p22l) = fuse_projectors((p21l, p22l)) - p11r = projector(cl_h, (i2, j2, 1), (i1, j1, 1)) - p21r = projector(cl_h, (i2, j2, 1), (i1, j1, 2)) - p12r = projector(cl_h, (i2, j2, 2), (i1, j1, 1)) - p22r = projector(cl_h, (i2, j2, 2), (i1, j1, 2)) + p11r = projector(potts_h, (i2, j2, 1), (i1, j1, 1)) + p21r = projector(potts_h, (i2, j2, 1), (i1, j1, 2)) + p12r = projector(potts_h, (i2, j2, 2), (i1, j1, 1)) + p22r = projector(potts_h, (i2, j2, 2), (i1, j1, 2)) p1r, (p11r, p21r) = fuse_projectors((p11r, p21r)) p2r, (p12r, p22r) = fuse_projectors((p12r, p22r)) @@ -367,10 +367,10 @@ function merge_vertices_cl_h( pl = outer_projector(p1l, p2l) pr = outer_projector(p1r, p2r) - e11 = interaction_energy(cl_h, (i1, j1, 1), (i2, j2, 1)) - e12 = interaction_energy(cl_h, (i1, j1, 1), (i2, j2, 2)) - e21 = interaction_energy(cl_h, (i1, j1, 2), (i2, j2, 1)) - e22 = interaction_energy(cl_h, (i1, j1, 2), (i2, j2, 2)) + e11 = interaction_energy(potts_h, (i1, j1, 1), (i2, j2, 1)) + e12 = interaction_energy(potts_h, (i1, j1, 1), (i2, j2, 2)) + e21 = interaction_energy(potts_h, (i1, j1, 2), (i2, j2, 1)) + e22 = interaction_energy(potts_h, (i1, j1, 2), (i2, j2, 2)) e11 = e11[p11l, p11r] e21 = e21[p21l, p21r] @@ -386,19 +386,19 @@ $(TYPEDSIGNATURES) Get the local energy associated with a vertex in a Potts Hamiltonian. # Arguments: -- `cl_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. +- `potts_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. - `v::NTuple{3, Int64}`: The coordinates of the vertex for which the local energy is requested. # Returns: - `local_energy::AbstractVector`: An abstract vector containing the local energy values associated with the specified vertex. -This function retrieves the local energy values associated with a given vertex `v` in a Potts Hamiltonian graph `cl_h`. +This function retrieves the local energy values associated with a given vertex `v` in a Potts Hamiltonian graph `potts_h`. If the vertex exists in the graph and has associated energy values, it returns those values; otherwise, it returns a vector of zeros. The local energy values are typically obtained from the spectrum associated with the vertex. """ -function local_energy(cl_h::LabelledGraph{S,T}, v::NTuple{3,Int64}) where {S,T} - has_vertex(cl_h, v) ? get_prop(cl_h, v, :spectrum).energies : zeros(1) +function local_energy(potts_h::LabelledGraph{S,T}, v::NTuple{3,Int64}) where {S,T} + has_vertex(potts_h, v) ? get_prop(potts_h, v, :spectrum).energies : zeros(1) end """ @@ -407,28 +407,28 @@ $(TYPEDSIGNATURES) Get the interaction energy between two vertices in a Potts Hamiltonian. # Arguments: -- `cl_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. +- `potts_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. - `v::NTuple{3, Int64}`: The coordinates of the first vertex. - `w::NTuple{3, Int64}`: The coordinates of the second vertex. # Returns: - `interaction_energy::AbstractMatrix`: An abstract matrix containing the interaction energy values between the specified vertices. -This function retrieves the interaction energy values between two vertices, `v` and `w`, in a Potts Hamiltonian graph `cl_h`. +This function retrieves the interaction energy values between two vertices, `v` and `w`, in a Potts Hamiltonian graph `potts_h`. If there is a directed edge from `w` to `v`, it returns the corresponding energy values; if there is a directed edge from `v` to `w`, it returns the transpose of the energy values; otherwise, it returns a matrix of zeros. The interaction energy values represent the energy associated with the interaction or connection between the two vertices. """ function interaction_energy( - cl_h::LabelledGraph{S,T}, + potts_h::LabelledGraph{S,T}, v::NTuple{3,Int64}, w::NTuple{3,Int64}, ) where {S,T} - if has_edge(cl_h, w, v) - get_prop(cl_h, w, v, :en)' - elseif has_edge(cl_h, v, w) - get_prop(cl_h, v, w, :en) + if has_edge(potts_h, w, v) + get_prop(potts_h, w, v, :en)' + elseif has_edge(potts_h, v, w) + get_prop(potts_h, v, w, :en) else zeros(1, 1) end @@ -440,7 +440,7 @@ $(TYPEDSIGNATURES) Get the projector associated with an edge between two vertices in a Potts Hamiltonian. # Arguments: -- `cl_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. +- `potts_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. - `v::NTuple{N, Int64}`: The coordinates of one of the two vertices connected by the edge. - `w::NTuple{N, Int64}`: The coordinates of the other vertex connected by the edge. @@ -448,26 +448,26 @@ Get the projector associated with an edge between two vertices in a Potts Hamilt - `p::AbstractVector`: An abstract vector representing the projector associated with the specified edge. This function retrieves the projector associated with an edge between two vertices, `v` and `w`, -in a Potts Hamiltonian graph `cl_h`. +in a Potts Hamiltonian graph `potts_h`. If there is a directed edge from `w` to `v`, it returns the index of right projector (`:ipr`); if there is a directed edge from `v` to `w`, it returns the index of left projector (`:ipl`). If no edge exists between the vertices, it returns a vector of ones. """ function projector( - cl_h::LabelledGraph{S,T}, + potts_h::LabelledGraph{S,T}, v::NTuple{N,Int64}, w::NTuple{N,Int64}, ) where {S,T,N} - if has_edge(cl_h, w, v) - idx_p = get_prop(cl_h, w, v, :ipr) - p = get_projector!(get_prop(cl_h, :pool_of_projectors), idx_p, :CPU) - elseif has_edge(cl_h, v, w) - idx_p = get_prop(cl_h, v, w, :ipl) - p = get_projector!(get_prop(cl_h, :pool_of_projectors), idx_p, :CPU) + if has_edge(potts_h, w, v) + idx_p = get_prop(potts_h, w, v, :ipr) + p = get_projector!(get_prop(potts_h, :pool_of_projectors), idx_p, :CPU) + elseif has_edge(potts_h, v, w) + idx_p = get_prop(potts_h, v, w, :ipl) + p = get_projector!(get_prop(potts_h, :pool_of_projectors), idx_p, :CPU) else p = ones( Int, - v ∈ vertices(cl_h) ? length(get_prop(cl_h, v, :spectrum).energies) : 1, + v ∈ vertices(potts_h) ? length(get_prop(potts_h, v, :spectrum).energies) : 1, ) end end diff --git a/src/potts_hamiltonian.jl b/src/potts_hamiltonian.jl index 0eca945..a70a9d9 100644 --- a/src/potts_hamiltonian.jl +++ b/src/potts_hamiltonian.jl @@ -52,7 +52,7 @@ This function constructs a Potts Hamiltonian from an Ising graph by introducing - `cluster_assignment_rule::Dict{Int, L}`: A dictionary specifying the assignment rule that maps Ising graph vertices to clusters. It can be `super_square_lattice`, `pegasus_lattice` or `zephyr_lattice`. # Returns: -- `cl_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labelled graph. +- `potts_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labelled graph. The `potts_hamiltonian` function takes an Ising graph (`ig`) as input and constructs a Potts Hamiltonian by introducing a natural order in Potts Hamiltonian coordinates. @@ -88,7 +88,7 @@ This function constructs a Potts Hamiltonian from an Ising graph by introducing - `cluster_assignment_rule::Dict{Int, T}`: A dictionary specifying the assignment rule that maps Ising graph vertices to clusters. It can be `super_square_lattice`, `pegasus_lattice` or `zephyr_lattice`. # Returns: -- `cl_h::LabelledGraph{MetaDiGraph}`: The Potts Hamiltonian represented as a labelled graph. +- `potts_h::LabelledGraph{MetaDiGraph}`: The Potts Hamiltonian represented as a labelled graph. The `potts_hamiltonian` function takes an Ising graph (`ig`) as input and constructs a Potts Hamiltonian by introducing a natural order in Potts Hamiltonian coordinates. It allows you to specify the number of @@ -102,17 +102,17 @@ function potts_hamiltonian( spectrum::Function = full_spectrum, cluster_assignment_rule::Dict{Int,T}, ) where {T} - cl_h = LabelledGraph{MetaDiGraph}(sort(unique(values(cluster_assignment_rule)))) + potts_h = LabelledGraph{MetaDiGraph}(sort(unique(values(cluster_assignment_rule)))) lp = PoolOfProjectors{Int}() for (v, cl) ∈ split_into_clusters(ig, cluster_assignment_rule) sp = spectrum(cl, num_states = get(num_states_cl, v, basis_size(cl))) - set_props!(cl_h, v, Dict(:cluster => cl, :spectrum => sp)) + set_props!(potts_h, v, Dict(:cluster => cl, :spectrum => sp)) end - for (i, v) ∈ enumerate(vertices(cl_h)), w ∈ vertices(cl_h)[i+1:end] - cl1, cl2 = get_prop(cl_h, v, :cluster), get_prop(cl_h, w, :cluster) + for (i, v) ∈ enumerate(vertices(potts_h)), w ∈ vertices(potts_h)[i+1:end] + cl1, cl2 = get_prop(potts_h, v, :cluster), get_prop(potts_h, w, :cluster) outer_edges, J = inter_cluster_edges(ig, cl1, cl2) if !isempty(outer_edges) @@ -122,8 +122,8 @@ function potts_hamiltonian( ind2 = reshape(ind2, length(ind2)) JJ = J[ind1, ind2] - states_v = get_prop(cl_h, v, :spectrum).states - states_w = get_prop(cl_h, w, :spectrum).states + states_v = get_prop(potts_h, v, :spectrum).states + states_w = get_prop(potts_h, w, :spectrum).states pl, unique_states_v = rank_reveal([s[ind1] for s ∈ states_v], :PE) pr, unique_states_w = rank_reveal([s[ind2] for s ∈ states_w], :PE) @@ -131,17 +131,17 @@ function potts_hamiltonian( ipl = add_projector!(lp, pl) ipr = add_projector!(lp, pr) - add_edge!(cl_h, v, w) + add_edge!(potts_h, v, w) set_props!( - cl_h, + potts_h, v, w, Dict(:outer_edges => outer_edges, :ipl => ipl, :en => en, :ipr => ipr), ) end end - set_props!(cl_h, Dict(:pool_of_projectors => lp)) - cl_h + set_props!(potts_h, Dict(:pool_of_projectors => lp)) + potts_h end """ @@ -157,7 +157,7 @@ This function constructs a Potts Hamiltonian from an Ising graph by introducing - `cluster_assignment_rule::Dict{Int, T}`: A dictionary specifying the assignment rule that maps Ising graph vertices to clusters. It can be `super_square_lattice`, `pegasus_lattice` or `zephyr_lattice`. # Returns: -- `cl_h::LabelledGraph{MetaDiGraph}`: The Potts Hamiltonian represented as a labelled graph. +- `potts_h::LabelledGraph{MetaDiGraph}`: The Potts Hamiltonian represented as a labelled graph. The `potts_hamiltonian` function takes an Ising graph (`ig`) as input and constructs a Potts Hamiltonian by introducing a natural order in Potts Hamiltonian coordinates. @@ -219,7 +219,7 @@ This function decodes a state from a Potts Hamiltonian into Ising graph spin val returns a dictionary mapping each Ising graph vertex to its corresponding spin value. # Arguments: -- `cl_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. +- `potts_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. - `state::Vector{Int}`: The state to be decoded, represented as an array of state indices for each vertex in the Potts Hamiltonian. # Returns: @@ -229,13 +229,13 @@ This function assumes that the state has the same order as the vertices in the P It decodes the state consistently based on the cluster assignments and spectra of the Potts Hamiltonian. """ function decode_potts_hamiltonian_state( - cl_h::LabelledGraph{S,T}, + potts_h::LabelledGraph{S,T}, state::Vector{Int}, ) where {S,T} ret = Dict{Int,Int}() - for (i, vert) ∈ zip(state, vertices(cl_h)) - spins = get_prop(cl_h, vert, :cluster).labels - states = get_prop(cl_h, vert, :spectrum).states + for (i, vert) ∈ zip(state, vertices(potts_h)) + spins = get_prop(potts_h, vert, :cluster).labels + states = get_prop(potts_h, vert, :spectrum).states if length(states) > 0 curr_state = states[i] merge!(ret, Dict(k => v for (k, v) ∈ zip(spins, curr_state))) @@ -253,30 +253,30 @@ This function calculates the energy of a given state in a Potts Hamiltonian. The state is represented as a dictionary mapping each Ising graph vertex to its corresponding spin value. # Arguments: -- `cl_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. +- `potts_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. - `σ::Dict{T, Int}`: A dictionary mapping Ising graph vertices to their spin values. # Returns: -- `en_cl_h::Float64`: The energy of the state in the Potts Hamiltonian. +- `en_potts_h::Float64`: The energy of the state in the Potts Hamiltonian. This function computes the energy by summing the energies associated with individual clusters and the interaction energies between clusters. It takes into account the cluster spectra and projectors stored in the Potts Hamiltonian. """ -function energy(cl_h::LabelledGraph{S,T}, σ::Dict{T,Int}) where {S,T} - en_cl_h = 0.0 - for v ∈ vertices(cl_h) - en_cl_h += get_prop(cl_h, v, :spectrum).energies[σ[v]] +function energy(potts_h::LabelledGraph{S,T}, σ::Dict{T,Int}) where {S,T} + en_potts_h = 0.0 + for v ∈ vertices(potts_h) + en_potts_h += get_prop(potts_h, v, :spectrum).energies[σ[v]] end - for edge ∈ edges(cl_h) - idx_pl = get_prop(cl_h, edge, :ipl) - pl = get_projector!(get_prop(cl_h, :pool_of_projectors), idx_pl, :CPU) - idx_pr = get_prop(cl_h, edge, :ipr) - pr = get_projector!(get_prop(cl_h, :pool_of_projectors), idx_pr, :CPU) - en = get_prop(cl_h, edge, :en) - en_cl_h += en[pl[σ[src(edge)]], pr[σ[dst(edge)]]] + for edge ∈ edges(potts_h) + idx_pl = get_prop(potts_h, edge, :ipl) + pl = get_projector!(get_prop(potts_h, :pool_of_projectors), idx_pl, :CPU) + idx_pr = get_prop(potts_h, edge, :ipr) + pr = get_projector!(get_prop(potts_h, :pool_of_projectors), idx_pr, :CPU) + en = get_prop(potts_h, edge, :en) + en_potts_h += en[pl[σ[src(edge)]], pr[σ[dst(edge)]]] end - en_cl_h + en_potts_h end """ @@ -287,7 +287,7 @@ Calculate the interaction energy between two nodes in a Potts Hamiltonian. This function computes the interaction energy between two specified nodes in a Potts Hamiltonian, represented as a labeled graph. # Arguments: -- `cl_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. +- `potts_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. - `i::Int`: The index of the first site. - `j::Int`: The index of the second site. @@ -298,21 +298,21 @@ The function checks if there is an interaction edge between the two sites (i, j) If such edges exist, it retrieves the interaction energy matrix, projectors, and calculates the interaction energy. If no interaction edge is found, it returns a zero matrix. """ -function energy_2site(cl_h::LabelledGraph{S,T}, i::Int, j::Int) where {S,T} +function energy_2site(potts_h::LabelledGraph{S,T}, i::Int, j::Int) where {S,T} # matrix of interaction energies between two nodes - if has_edge(cl_h, (i, j, 1), (i, j, 2)) - en12 = copy(get_prop(cl_h, (i, j, 1), (i, j, 2), :en)) - idx_pl = get_prop(cl_h, (i, j, 1), (i, j, 2), :ipl) - pl = copy(get_projector!(get_prop(cl_h, :pool_of_projectors), idx_pl, :CPU)) - idx_pr = get_prop(cl_h, (i, j, 1), (i, j, 2), :ipr) - pr = copy(get_projector!(get_prop(cl_h, :pool_of_projectors), idx_pr, :CPU)) + if has_edge(potts_h, (i, j, 1), (i, j, 2)) + en12 = copy(get_prop(potts_h, (i, j, 1), (i, j, 2), :en)) + idx_pl = get_prop(potts_h, (i, j, 1), (i, j, 2), :ipl) + pl = copy(get_projector!(get_prop(potts_h, :pool_of_projectors), idx_pl, :CPU)) + idx_pr = get_prop(potts_h, (i, j, 1), (i, j, 2), :ipr) + pr = copy(get_projector!(get_prop(potts_h, :pool_of_projectors), idx_pr, :CPU)) int_eng = en12[pl, pr] - elseif has_edge(cl_h, (i, j, 2), (i, j, 1)) - en21 = copy(get_prop(cl_h, (i, j, 2), (i, j, 1), :en)) - idx_pl = get_prop(cl_h, (i, j, 2), (i, j, 1), :ipl) - pl = copy(get_projector!(get_prop(cl_h, :pool_of_projectors), idx_pl, :CPU)) - idx_pr = get_prop(cl_h, (i, j, 2), (i, j, 1), :ipr) - pr = copy(get_projector!(get_prop(cl_h, :pool_of_projectors), idx_pr, :CPU)) + elseif has_edge(potts_h, (i, j, 2), (i, j, 1)) + en21 = copy(get_prop(potts_h, (i, j, 2), (i, j, 1), :en)) + idx_pl = get_prop(potts_h, (i, j, 2), (i, j, 1), :ipl) + pl = copy(get_projector!(get_prop(potts_h, :pool_of_projectors), idx_pl, :CPU)) + idx_pr = get_prop(potts_h, (i, j, 2), (i, j, 1), :ipr) + pr = copy(get_projector!(get_prop(potts_h, :pool_of_projectors), idx_pr, :CPU)) int_eng = en21[pl, pr]' else int_eng = zeros(1, 1) @@ -328,9 +328,9 @@ Calculate the bond energy between two clusters in a Potts Hamiltonian. This function computes the bond energy between two specified clusters (cluster nodes) in a Potts Hamiltonian, represented as a labeled graph. # Arguments: -- `cl_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. -- `cl_h_u::NTuple{N, Int64}`: The coordinates of the first cluster. -- `cl_h_v::NTuple{N, Int64}`: The coordinates of the second cluster. +- `potts_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. +- `potts_h_u::NTuple{N, Int64}`: The coordinates of the first cluster. +- `potts_h_v::NTuple{N, Int64}`: The coordinates of the second cluster. - `σ::Int`: Index for which the bond energy is calculated. # Returns: @@ -341,23 +341,23 @@ If such edges exist, it retrieves the bond energy matrix and projectors and calc If no bond edge is found, it returns a zero vector. """ function bond_energy( - cl_h::LabelledGraph{S,T}, - cl_h_u::NTuple{N,Int64}, - cl_h_v::NTuple{N,Int64}, + potts_h::LabelledGraph{S,T}, + potts_h_u::NTuple{N,Int64}, + potts_h_v::NTuple{N,Int64}, σ::Int, ) where {S,T,N} - if has_edge(cl_h, cl_h_u, cl_h_v) - ipu, en, ipv = get_prop.(Ref(cl_h), Ref(cl_h_u), Ref(cl_h_v), (:ipl, :en, :ipr)) - pu = get_projector!(get_prop(cl_h, :pool_of_projectors), ipu, :CPU) - pv = get_projector!(get_prop(cl_h, :pool_of_projectors), ipv, :CPU) + if has_edge(potts_h, potts_h_u, potts_h_v) + ipu, en, ipv = get_prop.(Ref(potts_h), Ref(potts_h_u), Ref(potts_h_v), (:ipl, :en, :ipr)) + pu = get_projector!(get_prop(potts_h, :pool_of_projectors), ipu, :CPU) + pv = get_projector!(get_prop(potts_h, :pool_of_projectors), ipv, :CPU) @inbounds energies = en[pu, pv[σ]] - elseif has_edge(cl_h, cl_h_v, cl_h_u) - ipv, en, ipu = get_prop.(Ref(cl_h), Ref(cl_h_v), Ref(cl_h_u), (:ipl, :en, :ipr)) - pu = get_projector!(get_prop(cl_h, :pool_of_projectors), ipu, :CPU) - pv = get_projector!(get_prop(cl_h, :pool_of_projectors), ipv, :CPU) + elseif has_edge(potts_h, potts_h_v, potts_h_u) + ipv, en, ipu = get_prop.(Ref(potts_h), Ref(potts_h_v), Ref(potts_h_u), (:ipl, :en, :ipr)) + pu = get_projector!(get_prop(potts_h, :pool_of_projectors), ipu, :CPU) + pv = get_projector!(get_prop(potts_h, :pool_of_projectors), ipv, :CPU) @inbounds energies = en[pv[σ], pu] else - energies = zeros(cluster_size(cl_h, cl_h_u)) + energies = zeros(cluster_size(potts_h, potts_h_u)) end end @@ -424,42 +424,42 @@ This function truncates a given Potts Hamiltonian by selecting a subset of state The resulting truncated Hamiltonian contains only the selected states for each cluster. # Arguments: -- `cl_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. +- `potts_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. - `states::Dict`: A dictionary specifying the states to be retained for each cluster. # Returns: -- `new_cl_h::LabelledGraph{MetaDiGraph}`: The truncated Potts Hamiltonian with reduced states. +- `new_potts_h::LabelledGraph{MetaDiGraph}`: The truncated Potts Hamiltonian with reduced states. -The function creates a new Potts Hamiltonian `new_cl_h` with the same structure as the input `cl_h`. -It then updates the spectrum of each cluster in `new_cl_h` by selecting the specified states from the original spectrum. +The function creates a new Potts Hamiltonian `new_potts_h` with the same structure as the input `potts_h`. +It then updates the spectrum of each cluster in `new_potts_h` by selecting the specified states from the original spectrum. Additionally, it updates the interactions and projectors between clusters based on the retained states. -The resulting `new_cl_h` represents a truncated version of the original Hamiltonian. +The resulting `new_potts_h` represents a truncated version of the original Hamiltonian. """ -function truncate_potts_hamiltonian(cl_h::LabelledGraph{S,T}, states::Dict) where {S,T} +function truncate_potts_hamiltonian(potts_h::LabelledGraph{S,T}, states::Dict) where {S,T} - new_cl_h = LabelledGraph{MetaDiGraph}(vertices(cl_h)) + new_potts_h = LabelledGraph{MetaDiGraph}(vertices(potts_h)) new_lp = PoolOfProjectors{Int}() - for v ∈ vertices(new_cl_h) - cl = get_prop(cl_h, v, :cluster) - sp = get_prop(cl_h, v, :spectrum) + for v ∈ vertices(new_potts_h) + cl = get_prop(potts_h, v, :cluster) + sp = get_prop(potts_h, v, :spectrum) if sp.states == Vector{Int64}[] sp = Spectrum(sp.energies[states[v]], sp.states, [1]) else sp = Spectrum(sp.energies[states[v]], sp.states[states[v]]) end - set_props!(new_cl_h, v, Dict(:cluster => cl, :spectrum => sp)) + set_props!(new_potts_h, v, Dict(:cluster => cl, :spectrum => sp)) end - for e ∈ edges(cl_h) + for e ∈ edges(potts_h) v, w = src(e), dst(e) - add_edge!(new_cl_h, v, w) - outer_edges = get_prop(cl_h, v, w, :outer_edges) - ipl = get_prop(cl_h, v, w, :ipl) - pl = get_projector!(get_prop(cl_h, :pool_of_projectors), ipl, :CPU) - ipr = get_prop(cl_h, v, w, :ipr) - pr = get_projector!(get_prop(cl_h, :pool_of_projectors), ipr, :CPU) - en = get_prop(cl_h, v, w, :en) + add_edge!(new_potts_h, v, w) + outer_edges = get_prop(potts_h, v, w, :outer_edges) + ipl = get_prop(potts_h, v, w, :ipl) + pl = get_projector!(get_prop(potts_h, :pool_of_projectors), ipl, :CPU) + ipr = get_prop(potts_h, v, w, :ipr) + pr = get_projector!(get_prop(potts_h, :pool_of_projectors), ipr, :CPU) + en = get_prop(potts_h, v, w, :en) pl = pl[states[v]] pr = pr[states[w]] pl_transition, pl_unique = rank_reveal(pl, :PE) @@ -468,15 +468,15 @@ function truncate_potts_hamiltonian(cl_h::LabelledGraph{S,T}, states::Dict) wher ipl = add_projector!(new_lp, pl_transition) ipr = add_projector!(new_lp, pr_transition) set_props!( - new_cl_h, + new_potts_h, v, w, Dict(:outer_edges => outer_edges, :ipl => ipl, :en => en, :ipr => ipr), ) end - set_props!(new_cl_h, Dict(:pool_of_projectors => new_lp)) + set_props!(new_potts_h, Dict(:pool_of_projectors => new_lp)) - new_cl_h + new_potts_h end function potts_hamiltonian( @@ -493,25 +493,25 @@ function potts_hamiltonian( X, Y = loaded_rmf["Nx"], loaded_rmf["Ny"] clusters = super_square_lattice((X, Y, 1)) - cl_h = LabelledGraph{MetaDiGraph}(sort(collect(values(clusters)))) + potts_h = LabelledGraph{MetaDiGraph}(sort(collect(values(clusters)))) lp = PoolOfProjectors{Int}() - for v ∈ cl_h.labels - set_props!(cl_h, v, Dict(:cluster => v)) + for v ∈ potts_h.labels + set_props!(potts_h, v, Dict(:cluster => v)) end for (index, value) in factors if length(index) == 2 y, x = index Eng = functions[value]' sp = Spectrum(collect(Eng), Vector{Vector{Int}}[], zeros(Int, N[y+1, x+1])) - set_props!(cl_h, (x + 1, y + 1), Dict(:spectrum => sp)) + set_props!(potts_h, (x + 1, y + 1), Dict(:spectrum => sp)) elseif length(index) == 4 y1, x1, y2, x2 = index - add_edge!(cl_h, (x1 + 1, y1 + 1), (x2 + 1, y2 + 1)) + add_edge!(potts_h, (x1 + 1, y1 + 1), (x2 + 1, y2 + 1)) Eng = functions[value] ipl = add_projector!(lp, collect(1:N[y1+1, x1+1])) ipr = add_projector!(lp, collect(1:N[y2+1, x2+1])) set_props!( - cl_h, + potts_h, (x1 + 1, y1 + 1), (x2 + 1, y2 + 1), Dict( @@ -530,6 +530,6 @@ function potts_hamiltonian( end end - set_props!(cl_h, Dict(:pool_of_projectors => lp, :Nx => X, :Ny => Y)) - cl_h + set_props!(potts_h, Dict(:pool_of_projectors => lp, :Nx => X, :Ny => Y)) + potts_h end diff --git a/src/truncate.jl b/src/truncate.jl index e397782..df29241 100644 --- a/src/truncate.jl +++ b/src/truncate.jl @@ -12,7 +12,7 @@ This function employs belief propagation (BP) to approximate the most probable s associated with a single-site cluster. It then truncates the Potts Hamiltonian based on the most probable states. # Arguments: -- `cl_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. +- `potts_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. - `num_states::Int`: The maximum number of most probable states to keep. - `beta::Real (optional)`: The inverse temperature parameter for the BP algorithm. Default is 1.0. - `tol::Real (optional)`: The tolerance value for convergence in BP. Default is 1e-10. @@ -22,19 +22,19 @@ associated with a single-site cluster. It then truncates the Potts Hamiltonian b - `LabelledGraph{S, T}`: A truncated Potts Hamiltonian. """ function truncate_potts_hamiltonian_1site_BP( - cl_h::LabelledGraph{S,T}, + potts_h::LabelledGraph{S,T}, num_states::Int; beta = 1.0, tol = 1e-10, iter = 1, ) where {S,T} states = Dict() - beliefs = belief_propagation(cl_h, beta; tol = tol, iter = iter) - for node in vertices(cl_h) + beliefs = belief_propagation(potts_h, beta; tol = tol, iter = iter) + for node in vertices(potts_h) indices = partialsortperm(beliefs[node], 1:min(num_states, length(beliefs[node]))) push!(states, node => indices) end - truncate_potts_hamiltonian(cl_h, states) + truncate_potts_hamiltonian(potts_h, states) end """ @@ -46,33 +46,33 @@ This function truncates a Potts Hamiltonian by considering 2-site energy states to keep. It computes the energies for all 2-site combinations and selects the states that maximize the probability. # Arguments: -- `cl_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. +- `potts_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labeled graph. - `num_states::Int`: The maximum number of most probable states to keep. # Returns: - `LabelledGraph{S, T}`: A truncated Potts Hamiltonian. """ function truncate_potts_hamiltonian_2site_energy( - cl_h::LabelledGraph{S,T}, + potts_h::LabelledGraph{S,T}, num_states::Int, ) where {S,T} # TODO: name to be clean to make it consistent with square2 and squarestar2 states = Dict() - for node in vertices(cl_h) + for node in vertices(potts_h) if node in keys(states) continue end i, j, _ = node - E1 = copy(get_prop(cl_h, (i, j, 1), :spectrum).energies) - E2 = copy(get_prop(cl_h, (i, j, 2), :spectrum).energies) - E = energy_2site(cl_h, i, j) .+ reshape(E1, :, 1) .+ reshape(E2, 1, :) + E1 = copy(get_prop(potts_h, (i, j, 1), :spectrum).energies) + E2 = copy(get_prop(potts_h, (i, j, 2), :spectrum).energies) + E = energy_2site(potts_h, i, j) .+ reshape(E1, :, 1) .+ reshape(E2, 1, :) sx, sy = size(E) E = reshape(E, sx * sy) ind1, ind2 = select_numstate_best(E, sx, num_states) push!(states, (i, j, 1) => ind1) push!(states, (i, j, 2) => ind2) end - truncate_potts_hamiltonian(cl_h, states) + truncate_potts_hamiltonian(potts_h, states) end function load_file(filename) @@ -96,7 +96,7 @@ This function truncates a Potts Hamiltonian by considering 2-site belief propaga to keep. It computes the beliefs for all 2-site combinations and selects the states that maximize the probability. # Arguments: -- `cl_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labelled graph. +- `potts_h::LabelledGraph{S, T}`: The Potts Hamiltonian represented as a labelled graph. - `beliefs::Dict`: A dictionary containing belief values for 2-site interactions. - `num_states::Int`: The maximum number of most probable states to keep. - `beta::Real (optional)`: The inverse temperature parameter (default is 1.0). @@ -105,7 +105,7 @@ to keep. It computes the beliefs for all 2-site combinations and selects the sta - `LabelledGraph{S, T}`: A truncated Potts Hamiltonian. """ function truncate_potts_hamiltonian_2site_BP( - cl_h::LabelledGraph{S,T}, + potts_h::LabelledGraph{S,T}, beliefs::Dict, num_states::Int, result_folder::String = "results_folder", @@ -115,14 +115,14 @@ function truncate_potts_hamiltonian_2site_BP( states = Dict() saved_states = load_file(joinpath(result_folder, "$(inst).jld2")) - for node in vertices(cl_h) + for node in vertices(potts_h) if node in keys(states) continue end i, j, _ = node sx = - has_vertex(cl_h, (i, j, 1)) ? - length(get_prop(cl_h, (i, j, 1), :spectrum).energies) : 1 + has_vertex(potts_h, (i, j, 1)) ? + length(get_prop(potts_h, (i, j, 1), :spectrum).energies) : 1 E = beliefs[(i, j)] ind1, ind2 = select_numstate_best(E, sx, num_states) push!(states, (i, j, 1) => ind1) @@ -130,7 +130,7 @@ function truncate_potts_hamiltonian_2site_BP( end path = joinpath(result_folder, "$(inst).jld2") save_object(string(path), states) - truncate_potts_hamiltonian(cl_h, states) + truncate_potts_hamiltonian(potts_h, states) end """ @@ -172,7 +172,7 @@ function select_numstate_best(E, sx, num_states) end function truncate_potts_hamiltonian( - cl_h, + potts_h, β, cs, result_folder, @@ -183,10 +183,10 @@ function truncate_potts_hamiltonian( states = Dict() saved_states = load_file(joinpath(result_folder, "$(inst).jld2")) if isnothing(saved_states) - new_cl_h = potts_hamiltonian_2site(cl_h, β) - beliefs = belief_propagation(new_cl_h, β; tol = 1e-6, iter = iter) - cl_h = truncate_potts_hamiltonian_2site_BP( - cl_h, + new_potts_h = potts_hamiltonian_2site(potts_h, β) + beliefs = belief_propagation(new_potts_h, β; tol = 1e-6, iter = iter) + potts_h = truncate_potts_hamiltonian_2site_BP( + potts_h, beliefs, cs, result_folder, @@ -195,7 +195,7 @@ function truncate_potts_hamiltonian( ) else states = saved_states - cl_h = truncate_potts_hamiltonian(cl_h, states) + potts_h = truncate_potts_hamiltonian(potts_h, states) end - cl_h + potts_h end diff --git a/test/bp_1site.jl b/test/bp_1site.jl index 7742aa6..1fa3be7 100644 --- a/test/bp_1site.jl +++ b/test/bp_1site.jl @@ -21,14 +21,14 @@ function create_larger_example_potts_hamiltonian_tree_basic() assignment_rule = Dict(1 => (1, 1, 1), 2 => (1, 2, 1), 3 => (2, 1, 1), 4 => (2, 2, 2)) - cl_h = potts_hamiltonian( + potts_h = potts_hamiltonian( ig, Dict{NTuple{3,Int},Int}(), spectrum = full_spectrum, cluster_assignment_rule = assignment_rule, ) - ig, cl_h + ig, potts_h end """ @@ -74,14 +74,14 @@ function create_larger_example_potts_hamiltonian_tree() 9 => (3, 3, 1), ) - cl_h = potts_hamiltonian( + potts_h = potts_hamiltonian( ig, Dict{NTuple{3,Int},Int}(), spectrum = full_spectrum, cluster_assignment_rule = assignment_rule, ) - ig, cl_h + ig, potts_h end """ @@ -125,31 +125,31 @@ function create_larger_example_potts_hamiltonian_tree_pathological() 8 => (2, 2), ) - cl_h = potts_hamiltonian( + potts_h = potts_hamiltonian( ig, Dict{NTuple{2,Int},Int}(), spectrum = full_spectrum, cluster_assignment_rule = assignment_rule, ) - ig, cl_h + ig, potts_h end @testset "Belief propagation" begin - for (ig, cl_h) ∈ [ + for (ig, potts_h) ∈ [ create_larger_example_potts_hamiltonian_tree_basic(), create_larger_example_potts_hamiltonian_tree(), create_larger_example_potts_hamiltonian_tree_pathological(), ] for beta ∈ [0.5, 1] iter = 16 - beliefs = belief_propagation(cl_h, beta; iter = iter) + beliefs = belief_propagation(potts_h, beta; iter = iter) exact_marginal = Dict() for k in keys(beliefs) push!( exact_marginal, k => [ - exact_cond_prob(cl_h, beta, Dict(k => a)) for + exact_cond_prob(potts_h, beta, Dict(k => a)) for a = 1:length(beliefs[k]) ], ) diff --git a/test/bp_2site.jl b/test/bp_2site.jl index 992cb75..d0111b1 100644 --- a/test/bp_2site.jl +++ b/test/bp_2site.jl @@ -49,21 +49,21 @@ function create_larger_example_potts_hamiltonian_tree_2site() 8 => (2, 2, 2), ) - cl_h1 = potts_hamiltonian( + potts_h1 = potts_hamiltonian( ig, Dict{NTuple{2,Int},Int}(), spectrum = full_spectrum, cluster_assignment_rule = assignment_rule1, ) - cl_h2 = potts_hamiltonian( + potts_h2 = potts_hamiltonian( ig, Dict{NTuple{3,Int},Int}(), spectrum = full_spectrum, cluster_assignment_rule = assignment_rule2, ) - ig, cl_h1, cl_h2 + ig, potts_h1, potts_h2 end """ @@ -129,27 +129,27 @@ function create_larger_example_potts_hamiltonian_tree_2site_pathological() 10 => (3, 2, 2), ) - cl_h1 = potts_hamiltonian( + potts_h1 = potts_hamiltonian( ig, Dict{NTuple{2,Int},Int}(), spectrum = full_spectrum, cluster_assignment_rule = assignment_rule1, ) - cl_h2 = potts_hamiltonian( + potts_h2 = potts_hamiltonian( ig, Dict{NTuple{3,Int},Int}(), spectrum = full_spectrum, cluster_assignment_rule = assignment_rule2, ) - ig, cl_h1, cl_h2 + ig, potts_h1, potts_h2 end @testset "Belief propagation 2site" begin - for (ig, cl_h1, cl_h2) ∈ [ + for (ig, potts_h1, potts_h2) ∈ [ create_larger_example_potts_hamiltonian_tree_2site(), create_larger_example_potts_hamiltonian_tree_2site_pathological(), ] @@ -158,16 +158,16 @@ end iter = 16 num_states = 10 - new_cl_h1 = potts_hamiltonian_2site(cl_h2, beta) + new_potts_h1 = potts_hamiltonian_2site(potts_h2, beta) - @test vertices(new_cl_h1) == vertices(cl_h1) - @test edges(new_cl_h1) == edges(cl_h1) - for e ∈ vertices(new_cl_h1) - @test get_prop(new_cl_h1, e, :spectrum).energies ≈ - get_prop(cl_h1, e, :spectrum).energies + @test vertices(new_potts_h1) == vertices(potts_h1) + @test edges(new_potts_h1) == edges(potts_h1) + for e ∈ vertices(new_potts_h1) + @test get_prop(new_potts_h1, e, :spectrum).energies ≈ + get_prop(potts_h1, e, :spectrum).energies end - for e ∈ edges(new_cl_h1) - E = get_prop(new_cl_h1, src(e), dst(e), :en) + for e ∈ edges(new_potts_h1) + E = get_prop(new_potts_h1, src(e), dst(e), :en) # @cast E[(l1, l2), (r1, r2)] := # E.e11[l1, r1] + E.e21[l2, r1] + E.e12[l1, r2] + E.e22[l2, r2] a11 = reshape(CuArray(E.e11), size(E.e11, 1), :, size(E.e11, 2)) @@ -176,30 +176,30 @@ end a22 = reshape(CuArray(E.e22), 1, size(E.e22, 1), 1, size(E.e22, 2)) E = @__dot__(a11 + a21 + a12 + a22) E = reshape(E, size(E, 1) * size(E, 2), size(E, 3) * size(E, 4)) - @test Array(E) == get_prop(cl_h1, src(e), dst(e), :en) + @test Array(E) == get_prop(potts_h1, src(e), dst(e), :en) end - for e ∈ edges(new_cl_h1) - il1 = get_prop(new_cl_h1, src(e), dst(e), :ipl) - il2 = get_prop(cl_h1, src(e), dst(e), :ipl) - ir1 = get_prop(new_cl_h1, src(e), dst(e), :ipr) - ir2 = get_prop(cl_h1, src(e), dst(e), :ipr) - - pl1 = get_projector!(get_prop(new_cl_h1, :pool_of_projectors), il1, :CPU) - pl2 = get_projector!(get_prop(cl_h1, :pool_of_projectors), il2, :CPU) - pr1 = get_projector!(get_prop(new_cl_h1, :pool_of_projectors), ir1, :CPU) - pr2 = get_projector!(get_prop(cl_h1, :pool_of_projectors), ir2, :CPU) + for e ∈ edges(new_potts_h1) + il1 = get_prop(new_potts_h1, src(e), dst(e), :ipl) + il2 = get_prop(potts_h1, src(e), dst(e), :ipl) + ir1 = get_prop(new_potts_h1, src(e), dst(e), :ipr) + ir2 = get_prop(potts_h1, src(e), dst(e), :ipr) + + pl1 = get_projector!(get_prop(new_potts_h1, :pool_of_projectors), il1, :CPU) + pl2 = get_projector!(get_prop(potts_h1, :pool_of_projectors), il2, :CPU) + pr1 = get_projector!(get_prop(new_potts_h1, :pool_of_projectors), ir1, :CPU) + pr2 = get_projector!(get_prop(potts_h1, :pool_of_projectors), ir2, :CPU) @test pl1 == pl2 @test pr1 == pr2 end - beliefs = belief_propagation(new_cl_h1, beta; iter = iter, tol = tol) + beliefs = belief_propagation(new_potts_h1, beta; iter = iter, tol = tol) exact_marginal = Dict() for k in keys(beliefs) temp = -1 / beta .* log.([ - exact_cond_prob(cl_h1, beta, Dict(k => a)) for + exact_cond_prob(potts_h1, beta, Dict(k => a)) for a = 1:length(beliefs[k]) ]) push!(exact_marginal, k => temp .- minimum(temp)) diff --git a/test/potts_hamiltonian.jl b/test/potts_hamiltonian.jl index fb522f4..db5531c 100644 --- a/test/potts_hamiltonian.jl +++ b/test/potts_hamiltonian.jl @@ -15,20 +15,20 @@ enum(vec) = Dict(v => i for (i, v) ∈ enumerate(vec)) for T ∈ [Float16, Float32, Float64] ig = ising_graph(T, instance) - cl_h = potts_hamiltonian( + potts_h = potts_hamiltonian( ig, 2, cluster_assignment_rule = super_square_lattice((m, n, 2 * t)), ) - @test collect(vertices(cl_h)) == [(i, j) for i ∈ 1:m for j ∈ 1:n] + @test collect(vertices(potts_h)) == [(i, j) for i ∈ 1:m for j ∈ 1:n] clv = [] cle = [] rank = rank_vec(ig) - for v ∈ vertices(cl_h) - cl = get_prop(cl_h, v, :cluster) + for v ∈ vertices(potts_h) + cl = get_prop(potts_h, v, :cluster) push!(clv, vertices(cl)) push!(cle, collect(edges(cl))) @@ -96,17 +96,17 @@ end ig = ising_graph(T, instance) @test eltype(ig) == T - cl_h = potts_hamiltonian( + potts_h = potts_hamiltonian( ig, spectrum = full_spectrum, cluster_assignment_rule = super_square_lattice((m, n, t)), ) - for (bd, e) in zip(bond_dimensions, edges(cl_h)) + for (bd, e) in zip(bond_dimensions, edges(potts_h)) ipl, en, ipr = - get_prop(cl_h, e, :ipl), get_prop(cl_h, e, :en), get_prop(cl_h, e, :ipr) - pl = get_projector!(get_prop(cl_h, :pool_of_projectors), ipl, :CPU) - pr = get_projector!(get_prop(cl_h, :pool_of_projectors), ipr, :CPU) + get_prop(potts_h, e, :ipl), get_prop(potts_h, e, :en), get_prop(potts_h, e, :ipr) + pl = get_projector!(get_prop(potts_h, :pool_of_projectors), ipl, :CPU) + pr = get_projector!(get_prop(potts_h, :pool_of_projectors), ipr, :CPU) @test minimum(size(en)) == bd @test maximum(pl) == size(en, 1) @@ -114,11 +114,11 @@ end end for ((i, j), cedge) ∈ cedges - ipl, en, ipr = get_prop(cl_h, i, j, :ipl), - get_prop(cl_h, i, j, :en), - get_prop(cl_h, i, j, :ipr) - pl = get_projector!(get_prop(cl_h, :pool_of_projectors), ipl, :CPU) - pr = get_projector!(get_prop(cl_h, :pool_of_projectors), ipr, :CPU) + ipl, en, ipr = get_prop(potts_h, i, j, :ipl), + get_prop(potts_h, i, j, :en), + get_prop(potts_h, i, j, :ipr) + pl = get_projector!(get_prop(potts_h, :pool_of_projectors), ipl, :CPU) + pr = get_projector!(get_prop(potts_h, :pool_of_projectors), ipr, :CPU) base_i = all_states(rank[i]) base_j = all_states(rank[j]) @@ -144,14 +144,14 @@ end @test energy ≈ en[pl, pr] end @testset "each cluster comprises expected cells" begin - for v ∈ vertices(cl_h) - cl = get_prop(cl_h, v, :cluster) + for v ∈ vertices(potts_h) + cl = get_prop(potts_h, v, :cluster) @test issetequal(vertices(cl), cells[v]) end end @testset "each edge comprises expected bunch of edges from source Ising graph" begin - for e ∈ edges(cl_h) - outer_edges = get_prop(cl_h, e, :outer_edges) + for e ∈ edges(potts_h) + outer_edges = get_prop(potts_h, e, :outer_edges) @test issetequal( cedges[(src(e), dst(e))], [(src(oe), dst(oe)) for oe ∈ outer_edges], @@ -177,16 +177,16 @@ function create_example_potts_hamiltonian(::Type{T}) where {T} ) end -cl_h_state_to_spin = +potts_h_state_to_spin = [([1, 1], [-1, -1]), ([1, 2], [-1, 1]), ([2, 1], [1, -1]), ([2, 2], [1, 1])] @testset "Decoding solution gives correct spin assignment" begin for T ∈ [Float16, Float32, Float64] - cl_h = create_example_potts_hamiltonian(T) - @test all(eltype(get_prop(cl_h, e, :en)) == T for e ∈ edges(cl_h)) - for (state, spin_values) ∈ cl_h_state_to_spin - d = decode_potts_hamiltonian_state(cl_h, state) + potts_h = create_example_potts_hamiltonian(T) + @test all(eltype(get_prop(potts_h, e, :en)) == T for e ∈ edges(potts_h)) + for (state, spin_values) ∈ potts_h_state_to_spin + d = decode_potts_hamiltonian_state(potts_h, state) states = collect(values(d))[collect(keys(d))] @test states == spin_values end @@ -242,34 +242,34 @@ function create_larger_example_potts_hamiltonian() 9 => (2, 2), ) - cl_h = potts_hamiltonian( + potts_h = potts_hamiltonian( ig, Dict{NTuple{2,Int},Int}(), spectrum = full_spectrum, cluster_assignment_rule = assignment_rule, ) - ig, cl_h + ig, potts_h end -function potts_hamiltonian_energy(cl_h, state) +function potts_hamiltonian_energy(potts_h, state) # This is highly inefficient, but simple, which makes it suitable for testing. # If such a function is needed elsewhere, we need to implement it properly. total_en = 0 # Collect local terms from each cluster - for (s, v) ∈ zip(state, vertices(cl_h)) - total_en += get_prop(cl_h, v, :spectrum).energies[s] + for (s, v) ∈ zip(state, vertices(potts_h)) + total_en += get_prop(potts_h, v, :spectrum).energies[s] end # Collect inter-cluster terms - for edge ∈ edges(cl_h) - i, j = cl_h.reverse_label_map[src(edge)], cl_h.reverse_label_map[dst(edge)] - ipl, en, ipr = get_prop(cl_h, edge, :ipl), - get_prop(cl_h, edge, :en), - get_prop(cl_h, edge, :ipr) - pl = get_projector!(get_prop(cl_h, :pool_of_projectors), ipl, :CPU) - pr = get_projector!(get_prop(cl_h, :pool_of_projectors), ipr, :CPU) + for edge ∈ edges(potts_h) + i, j = potts_h.reverse_label_map[src(edge)], potts_h.reverse_label_map[dst(edge)] + ipl, en, ipr = get_prop(potts_h, edge, :ipl), + get_prop(potts_h, edge, :en), + get_prop(potts_h, edge, :ipr) + pl = get_projector!(get_prop(potts_h, :pool_of_projectors), ipl, :CPU) + pr = get_projector!(get_prop(potts_h, :pool_of_projectors), ipr, :CPU) edge_energy = en[pl, pr] total_en += edge_energy[state[i], state[j]] end @@ -277,18 +277,18 @@ function potts_hamiltonian_energy(cl_h, state) end @testset "Decoding solution gives spins configuration with corresponding energies" begin - ig, cl_h = create_larger_example_potts_hamiltonian() + ig, potts_h = create_larger_example_potts_hamiltonian() # Corresponding bases sizes for each cluster are 16, 4, 4, 2. all_states = [[i, j, k, l] for i ∈ 1:16 for j ∈ 1:4 for k ∈ 1:4 for l ∈ 1:2] for state ∈ all_states - d = decode_potts_hamiltonian_state(cl_h, state) + d = decode_potts_hamiltonian_state(potts_h, state) spins = zeros(length(d)) for (k, v) ∈ d spins[k] = v end σ = [Int.(spins)] - @test potts_hamiltonian_energy(cl_h, state) ≈ energy(σ, ig)[] + @test potts_hamiltonian_energy(potts_h, state) ≈ energy(σ, ig)[] end end diff --git a/test/utils.jl b/test/utils.jl index 418fd56..e4167b1 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -11,16 +11,16 @@ instances = ["P2"] #, "P4", "P8", "P16"] max_cl_states = 2 ig = ising_graph(joinpath(instance_dir, instance)) - cl_h = potts_hamiltonian( + potts_h = potts_hamiltonian( ig, max_cl_states, spectrum = brute_force, cluster_assignment_rule = super_square_lattice((m, n, t)), ) - @test nv(cl_h) == s^2 + @test nv(potts_h) == s^2 if s > 1 - @test all(has_edge(cl_h, (l, k), (l + 1, k - 1)) for l ∈ 1:s-1, k ∈ 2:s) + @test all(has_edge(potts_h, (l, k), (l + 1, k - 1)) for l ∈ 1:s-1, k ∈ 2:s) end end end