diff --git a/src/dragondrop.jl b/src/dragondrop.jl index 8d9e2ec..66fd3bc 100644 --- a/src/dragondrop.jl +++ b/src/dragondrop.jl @@ -335,7 +335,7 @@ function post_process_grid(grid::Matrix{SimpleCell{T}}, h0, h1) where T return gg, pins end -struct QUBOResult{NT} +struct QUBOResult{NT} <: ProblemReductions.AbstractReductionResult grid_graph::GridGraph{NT} pins::Vector{Int} mis_overhead::Int @@ -353,13 +353,13 @@ function map_config_back(res::WMISResult, cfg) return cfg[res.pins] end -struct RestrictedQUBOResult{NT} +struct RestrictedQUBOResult{NT} <: ProblemReductions.AbstractReductionResult grid_graph::GridGraph{NT} end function map_config_back(res::RestrictedQUBOResult, cfg) end -struct SquareQUBOResult{NT} +struct SquareQUBOResult{NT} <: ProblemReductions.AbstractReductionResult grid_graph::GridGraph{NT} pins::Vector{Int} mis_overhead::Float64 diff --git a/src/reduceto.jl b/src/reduceto.jl index 115af33..5cd1079 100644 --- a/src/reduceto.jl +++ b/src/reduceto.jl @@ -3,14 +3,14 @@ struct IndependentSetToKSG{NT, VT} <: ProblemReductions.AbstractReductionResult weights::VT end function _to_gridgraph(g::UnitDiskMapping.GridGraph) - return ProblemReductions.GridGraph(g.size, getfield.(g.nodes, :loc), g.radius) + return ProblemReductions.GridGraph(getfield.(g.nodes, :loc), g.radius) end function _extract_weights(g::UnitDiskMapping.GridGraph{<:WeightedNode}) getfield.(g.nodes, :weight) end ###### unweighted reduction -function ProblemReductions.reduceto(::Type{ProblemReductions.IndependentSet{ProblemReductions.GridGraph, Int, ProblemReductions.UnitWeight}}, problem::ProblemReductions.IndependentSet{GT, Int, ProblemReductions.UnitWeight} where GT<:SimpleGraph) +function ProblemReductions.reduceto(::Type{ProblemReductions.IndependentSet{ProblemReductions.GridGraph{2}, Int, ProblemReductions.UnitWeight}}, problem::ProblemReductions.IndependentSet{GT, Int, ProblemReductions.UnitWeight} where GT<:SimpleGraph) return IndependentSetToKSG(map_graph(UnWeighted(), problem.graph), problem.weights) end @@ -23,7 +23,7 @@ end ###### Weighted reduction # TODO: rescale the weights to avoid errors -function ProblemReductions.reduceto(::Type{ProblemReductions.IndependentSet{ProblemReductions.GridGraph, T, Vector{T}}} where T, problem::ProblemReductions.IndependentSet{GT} where GT<:SimpleGraph) +function ProblemReductions.reduceto(::Type{ProblemReductions.IndependentSet{ProblemReductions.GridGraph{2}, T, Vector{T}}} where T, problem::ProblemReductions.IndependentSet{GT} where GT<:SimpleGraph) return IndependentSetToKSG(map_graph(Weighted(), problem.graph), problem.weights) end function ProblemReductions.target_problem(res::IndependentSetToKSG{<:WeightedNode}) @@ -35,12 +35,12 @@ end ###### Factoring ###### struct FactoringToIndependentSet{NT} <: ProblemReductions.AbstractReductionResult mapres::FactoringResult{NT} - raw_graph::ProblemReductions.GridGraph + raw_graph::ProblemReductions.GridGraph{2} raw_weight::Vector{Int} vmap::Vector{Int} - problem::ProblemReductions.IndependentSet{ProblemReductions.GridGraph, Int, Vector{Int}} + problem::ProblemReductions.IndependentSet{ProblemReductions.GridGraph{2}, Int, Vector{Int}} end -function ProblemReductions.reduceto(::Type{ProblemReductions.IndependentSet{ProblemReductions.GridGraph, T, Vector{T}}} where T, problem::ProblemReductions.Factoring) +function ProblemReductions.reduceto(::Type{ProblemReductions.IndependentSet{ProblemReductions.GridGraph{2}, T, Vector{T}}} where T, problem::ProblemReductions.Factoring) mres = map_factoring(problem.m, problem.n) g = _to_gridgraph(mres.grid_graph) ws = getfield.(mres.grid_graph.nodes, :weight) @@ -57,4 +57,50 @@ function ProblemReductions.extract_solution(res::FactoringToIndependentSet, sol) cfg[res.vmap] .= sol i1, i2 = map_config_back(res.mapres, cfg) return vcat([i1>>(k-1) & 1 for k=1:length(res.mapres.pins_input1)], [i2>>(k-1) & 1 for k=1:length(res.mapres.pins_input2)]) -end \ No newline at end of file +end + +###### Spinglass problem to MIS on KSG ###### +# NOTE: I am not sure about the correctness of this reduction. If you encounter a bug, please question this function! +function ProblemReductions.reduceto(::Type{ProblemReductions.IndependentSet{ProblemReductions.GridGraph{2}, T, Vector{T}}} where T, problem::ProblemReductions.SpinGlass{<:SimpleGraph}) + n = length(problem.h) + M = similar(problem.h, n, n) + for (e, j) in zip(edges(problem.graph), problem.J) + M[e.src, e.dst] = M[e.dst, e.src] = j + end + return map_qubo(M, -problem.h) +end + +function ProblemReductions.target_problem(res::QUBOResult) + grid = _to_gridgraph(res.grid_graph) + ws = getfield.(res.grid_graph.nodes, :weight) + return ProblemReductions.IndependentSet(grid, ws) +end + +function ProblemReductions.extract_solution(res::QUBOResult, sol) + res = map_config_back(res, sol) + return 1 .- 2 .* Int.(res) +end + +###### Spinglass problem on grid to MIS on KSG ###### +# NOTE: the restricted layout is not implemented, since it is not often used +function ProblemReductions.reduceto(::Type{ProblemReductions.IndependentSet{ProblemReductions.GridGraph{2}, T, Vector{T}}} where T, problem::ProblemReductions.SpinGlass{ProblemReductions.GridGraph{2}}) + g = problem.graph + @assert 1 <= g.radius < sqrt(2) "Only support nearest neighbor interaction" + coupling = [(g.locations[e.src]..., g.locations[e.dst]..., J) for (e, J) in zip(edges(g), problem.J)] + onsite = [(i, j, -h) for ((i, j), h) in zip(g.locations, problem.h)] + # a vector coupling of `(i, j, i', j', J)`, s.t. (i', j') == (i, j+1) or (i', j') = (i+1, j). + # a vector of onsite term `(i, j, h)`. + return map_qubo_square(coupling, onsite) +end + +function ProblemReductions.target_problem(res::SquareQUBOResult) + grid = _to_gridgraph(res.grid_graph) + ws = getfield.(res.grid_graph.nodes, :weight) + return ProblemReductions.IndependentSet(grid, ws) +end + +function ProblemReductions.extract_solution(res::SquareQUBOResult, sol) + res = map_config_back(res, sol) + return 1 .- 2 .* Int.(res) +end + \ No newline at end of file diff --git a/test/reduceto.jl b/test/reduceto.jl index 9ed393d..2f267be 100644 --- a/test/reduceto.jl +++ b/test/reduceto.jl @@ -6,11 +6,19 @@ import ProblemReductions fact = ProblemReductions.Factoring(2, 1, 2) is = ProblemReductions.IndependentSet(graph) wis = ProblemReductions.IndependentSet(graph, rand(nv(graph)) .* 0.2) + sg = ProblemReductions.SpinGlass(graph, [0.2, 0.4, -0.6], [0.1, 0.1, 0.1]) + sg2 = ProblemReductions.SpinGlass(graph, [0.1, 0.1, -0.1], [0.1, 0.1, 0.1]) + grid = ProblemReductions.GridGraph(ones(Bool, 2, 2), 1.2) + sg_square = ProblemReductions.SpinGlass(grid, [0.1, 0.3, -0.1, 0.4], [0.1, 0.1, 0.1, 0.2]) + sg_square2 = ProblemReductions.SpinGlass(grid, [0.1, -0.3, 0.1, 0.4], [0.1, 0.1, 0.1, 0.2]) for (source, target_type) in [ - # please add more tests here - is => ProblemReductions.IndependentSet{ProblemReductions.GridGraph, Int, ProblemReductions.UnitWeight}, - wis => ProblemReductions.IndependentSet{ProblemReductions.GridGraph, Float64, Vector{Float64}}, - fact => ProblemReductions.IndependentSet{ProblemReductions.GridGraph, Int, Vector{Int}}, + sg_square => ProblemReductions.IndependentSet{ProblemReductions.GridGraph{2}, Float64, Vector{Float64}}, + sg_square2 => ProblemReductions.IndependentSet{ProblemReductions.GridGraph{2}, Float64, Vector{Float64}}, + sg => ProblemReductions.IndependentSet{ProblemReductions.GridGraph{2}, Float64, Vector{Float64}}, + sg2 => ProblemReductions.IndependentSet{ProblemReductions.GridGraph{2}, Float64, Vector{Float64}}, + is => ProblemReductions.IndependentSet{ProblemReductions.GridGraph{2}, Int, ProblemReductions.UnitWeight}, + wis => ProblemReductions.IndependentSet{ProblemReductions.GridGraph{2}, Float64, Vector{Float64}}, + fact => ProblemReductions.IndependentSet{ProblemReductions.GridGraph{2}, Int, Vector{Int}}, ] @info "Testing reduction from $(typeof(source)) to $(target_type)" # directly solve