From 58868b7b88154201fb06dd45bc6d1197e9b2380c Mon Sep 17 00:00:00 2001 From: c-allergic Date: Mon, 22 Jul 2024 16:51:07 +0800 Subject: [PATCH 1/3] New: Reduction between simple kinds of SpinGlass and MaxCut problems --- src/models/MaxCut.jl | 24 ++++++------ src/rules/rules.jl | 3 +- src/rules/spinglass_maxcut.jl | 67 ++++++++++++++++++++++++++++++++++ test/rules/rules.jl | 9 ++++- test/rules/spinglass_maxcut.jl | 19 ++++++++++ 5 files changed, 107 insertions(+), 15 deletions(-) create mode 100644 src/rules/spinglass_maxcut.jl create mode 100644 test/rules/spinglass_maxcut.jl diff --git a/src/models/MaxCut.jl b/src/models/MaxCut.jl index eb89ede..287a7d0 100644 --- a/src/models/MaxCut.jl +++ b/src/models/MaxCut.jl @@ -8,17 +8,17 @@ weights of the edges that are cut. Positional arguments ------------------------------- * `graph` is the problem graph. -* `edge_weights` are associated with the edges of the `graph`. +* `weights` are associated with the edges of the `graph`. We have ensure that the `weights` are in the same order as the edges in `edges(graph)`. """ -struct MaxCut{WT1<:AbstractVector} <: AbstractProblem +struct MaxCut{WT<:AbstractVector} <: AbstractProblem graph::SimpleGraph{Int} - edge_weights::WT1 - function MaxCut(g::SimpleGraph,edge_weights::AbstractVector=UnitWeight(ne(g))) - @assert length(edge_weights) == ne(g) - new{typeof(edge_weights)}(g, edge_weights) + weights::WT + function MaxCut(g::SimpleGraph,weights::AbstractVector=UnitWeight(ne(g))) + @assert length(weights) == ne(g) + new{typeof(weights)}(g, weights) end end -Base.:(==)(a::MaxCut, b::MaxCut) = a.graph == b.graph && a.edge_weights == b.edge_weights +Base.:(==)(a::MaxCut, b::MaxCut) = a.graph == b.graph && a.weights == b.weights # varibles interface variables(gp::MaxCut) = [1:nv(gp.graph)...] @@ -26,7 +26,7 @@ num_variables(gp::MaxCut) = nv(gp.graph) flavors(::Type{<:MaxCut}) = [0, 1] #choose it or not # weights interface -parameters(c::MaxCut) = [[c.edge_weights[i] for i=1:ne(c.graph)]...] +parameters(c::MaxCut) = [[c.weights[i] for i=1:ne(c.graph)]...] set_parameters(c::MaxCut, weights) = MaxCut(c.graph, weights[1:ne(c.graph)]) @@ -38,12 +38,12 @@ sum of the weights of the edges that are cut. """ function evaluate(c::MaxCut, config) @assert length(config) == nv(c.graph) - -cut_size(vedges(c.graph), config; edge_weights=c.edge_weights) + -cut_size(vedges(c.graph), config; weights=c.weights) end -function cut_size(terms, config; edge_weights=UnitWeight(length(terms))) - size = zero(promote_type(eltype(edge_weights))) - for (i,j)in zip(terms, edge_weights) # we have ensure that the edge_weights are in the same order as the edges in terms, so we could use zip() +function cut_size(terms, config; weights=UnitWeight(length(terms))) + size = zero(promote_type(eltype(weights))) + for (i,j)in zip(terms, weights) size += (config[i[1]] != config[i[2]]) * j # terms are the edges,and terms[1],terms[2] are the two vertices of the edge. end return size diff --git a/src/rules/rules.jl b/src/rules/rules.jl index a29fbc6..e30e18d 100644 --- a/src/rules/rules.jl +++ b/src/rules/rules.jl @@ -46,4 +46,5 @@ Extract the solution `solution` of the target problem to the original problem. """ function extract_solution end -include("spinglass_sat.jl") \ No newline at end of file +include("spinglass_sat.jl") +include("spinglass_maxcut.jl") \ No newline at end of file diff --git a/src/rules/spinglass_maxcut.jl b/src/rules/spinglass_maxcut.jl new file mode 100644 index 0000000..43d6992 --- /dev/null +++ b/src/rules/spinglass_maxcut.jl @@ -0,0 +1,67 @@ +""" +$TYPEDEF + +The reduction result of a maxcut to a spin glass problem. + +### Fields +- `spinglass::SpinGlass{GT, T}`: the spin glass problem. + +We only consider a simple reduction from MaxCut to SpinGlass(the graph must be `SimpleGraph`). +""" +struct ReductionMaxCutToSpinGlass{GT, T} + spinglass::SpinGlass{GT, T} +end + +target_problem(res::ReductionMaxCutToSpinGlass) = res.spinglass + +function reduceto(::Type{<:SpinGlass}, maxcut::MaxCut) + sg = maxcut2spinglass(maxcut) + return ReductionMaxCutToSpinGlass(sg) +end + +function maxcut2spinglass(maxcut::MaxCut) + @assert maxcut.graph isa SimpleGraph "the graph must be `SimpleGraph`" + return SpinGlass(maxcut.graph, maxcut.weights) +end + +function extract_solution(res::ReductionMaxCutToSpinGlass, sol) + out = zeros(eltype(sol), num_variables(res.spinglass)) + for (k, v) in enumerate(variables(res.spinglass)) + out[v] = sol[k] + end + return out +end + +""" +$TYPEDEF + +The reduction result of a spin glass to a maxcut problem. + +### Fields +- `maxcut::MaxCut{WT}`: the MaxCut problem. + +We only consider a simple reduction from SpinGlass to MaxCut(the graph must be `SimpleGraph`). +""" +struct ReductionSpinGlassToMaxCut{WT} + maxcut::MaxCut{WT} +end + +target_problem(res::ReductionSpinGlassToMaxCut) = res.maxcut + +function reduceto(::Type{<:MaxCut}, sg::SpinGlass) + mc = spinglass2maxcut(sg) + return ReductionSpinGlassToMaxCut(mc) +end + +function spinglass2maxcut(sg::SpinGlass) + @assert sg.graph isa SimpleGraph "the graph must be `SimpleGraph`" + return MaxCut(sg.graph, sg.weights) +end + +function extract_solution(res::ReductionSpinGlassToMaxCut, sol) + out = zeros(eltype(sol), num_variables(res.maxcut)) + for (k, v) in enumerate(variables(res.maxcut)) + out[v] = sol[k] + end + return out +end diff --git a/test/rules/rules.jl b/test/rules/rules.jl index 398a4d9..c5dd0ad 100644 --- a/test/rules/rules.jl +++ b/test/rules/rules.jl @@ -1,4 +1,4 @@ -using Test +using Test, ProblemReductions, Graphs @testset "spinglass_sat" begin include("spinglass_sat.jl") @@ -10,10 +10,15 @@ end y = ¬c ∨ b z = x ∧ y ∧ a end) + graph = smallgraph(:petersen) + maxcut = MaxCut(graph) + spinglass = SpinGlass(graph, [1,2,1,2,1,2,1,2,1,2,1,2,1,2,1]) for (source, target_type) in [ # please add more tests here - circuit => SpinGlass + circuit => SpinGlass, + maxcut => SpinGlass, + spinglass => MaxCut, ] # directly solve best_source = findbest(source, BruteForce()) diff --git a/test/rules/spinglass_maxcut.jl b/test/rules/spinglass_maxcut.jl new file mode 100644 index 0000000..f70efc8 --- /dev/null +++ b/test/rules/spinglass_maxcut.jl @@ -0,0 +1,19 @@ +using Test, ProblemReductions, Graphs +using ProblemReductions: reduceto, maxcut2spinglass, extract_solution, ReductionMaxCutToSpinGlass + +# add a simple test to check the reduction process +@testset "spinglass_maxcut" begin + # construct a graph + g = SimpleGraph(4) + add_edge!(g, 1, 2) + add_edge!(g, 1, 3) + add_edge!(g, 3, 4) + add_edge!(g, 2, 3) + + mc = MaxCut(g, [1, 3, 1, 4]) + Base.:(==)(a::ReductionMaxCutToSpinGlass, b::ReductionMaxCutToSpinGlass) = a.spinglass == b.spinglass + @test reduceto(SpinGlass, mc) == ReductionMaxCutToSpinGlass(maxcut2spinglass(mc)) + @test maxcut2spinglass(mc) == SpinGlass(g, [1, 3, 1, 4]) + @test findbest(mc, BruteForce()) == [[0, 0, 1, 0], [0, 1, 1, 0], [1, 0, 0, 1], [1, 1, 0, 1]] # in lexicographic order + @test findbest(maxcut2spinglass(mc), BruteForce()) == [[0, 0, 1, 0], [0, 1, 1, 0], [1, 0, 0, 1], [1, 1, 0, 1]] # in lexicographic order +end \ No newline at end of file From 24b5479b670d58bdf4cd9a0df613829c63f42b89 Mon Sep 17 00:00:00 2001 From: c-allergic Date: Mon, 22 Jul 2024 17:52:27 +0800 Subject: [PATCH 2/3] update ProblemReductions.jl --- src/ProblemReductions.jl | 2 +- test/rules/spinglass_maxcut.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ProblemReductions.jl b/src/ProblemReductions.jl index 61d026a..0467a82 100644 --- a/src/ProblemReductions.jl +++ b/src/ProblemReductions.jl @@ -24,7 +24,7 @@ export MaxCut # rules export target_problem, AbstractProblem, AbstractReductionResult, reduceto, extract_solution, reduction_complexity export LogicGadget, truth_table -export spinglass_circuit, ReductionCircuitToSpinGlass +export ReductionCircuitToSpinGlass, ReductionMaxCutToSpinGlass, ReductionSpinGlassToMaxCut export findbest, BruteForce export CNF diff --git a/test/rules/spinglass_maxcut.jl b/test/rules/spinglass_maxcut.jl index f70efc8..d4039b7 100644 --- a/test/rules/spinglass_maxcut.jl +++ b/test/rules/spinglass_maxcut.jl @@ -1,5 +1,5 @@ using Test, ProblemReductions, Graphs -using ProblemReductions: reduceto, maxcut2spinglass, extract_solution, ReductionMaxCutToSpinGlass +using ProblemReductions: maxcut2spinglass # add a simple test to check the reduction process @testset "spinglass_maxcut" begin From be7032a7584647787338b3ccfb98f299d4eeaa0b Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Tue, 23 Jul 2024 10:36:28 +0800 Subject: [PATCH 3/3] fix tests --- test/rules/rules.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/rules/rules.jl b/test/rules/rules.jl index c5dd0ad..ca21194 100644 --- a/test/rules/rules.jl +++ b/test/rules/rules.jl @@ -4,6 +4,10 @@ using Test, ProblemReductions, Graphs include("spinglass_sat.jl") end +@testset "spinglass_sat" begin + include("spinglass_maxcut.jl") +end + @testset "rules" begin circuit = CircuitSAT(@circuit begin x = a ∨ ¬b @@ -34,4 +38,4 @@ end # check if the solutions are the same @test sort(best_source) == sort(best_source_extracted) end -end \ No newline at end of file +end