diff --git a/src/bruteforce.jl b/src/bruteforce.jl index e62ba11b..adcf597c 100644 --- a/src/bruteforce.jl +++ b/src/bruteforce.jl @@ -5,12 +5,12 @@ A brute force method to find the best configuration of a problem. """ struct BruteForce end -function findbest(problem::AbstractProblem, ::BruteForce) +function findbest(problem::AbstractProblem, ::BruteForce; atol=eps(Float64), rtol=eps(Float64)) best_size = Inf best_configs = Vector{Int}[] configs = Iterators.product([flavors(problem) for i in 1:num_variables(problem)]...) for (size, config) in energy_multi(problem, configs) - if size == best_size + if isapprox(size, best_size; atol, rtol) push!(best_configs, collect(config)) elseif size < best_size[1] best_size = Float64(size) @@ -19,4 +19,4 @@ function findbest(problem::AbstractProblem, ::BruteForce) end end return best_configs -end \ No newline at end of file +end diff --git a/src/topology.jl b/src/topology.jl index 610880ba..b744cc95 100644 --- a/src/topology.jl +++ b/src/topology.jl @@ -42,13 +42,12 @@ $TYPEDEF A unit disk graph is a graph in which the vertices are points in a plane and two vertices are connected by an edge if and only if the Euclidean distance between them is at most a given radius. ### Fields -- `n::Int`: the number of vertices - `locations::Vector{NTuple{D, T}}`: the locations of the vertices -- `radius::T`: the radius of the unit disk +- `radius::Float64`: the radius of the unit disk """ struct UnitDiskGraph{D, T} <: Graphs.AbstractGraph{Int} locations::Vector{NTuple{D, T}} - radius::T + radius::Float64 end Base.:(==)(a::UnitDiskGraph, b::UnitDiskGraph) = a.locations == b.locations && a.radius == b.radius Graphs.nv(g::UnitDiskGraph) = length(g.locations) @@ -71,9 +70,7 @@ end function all_edges(g::UnitDiskGraph) edges = Graphs.SimpleEdge{Int}[] for i in 1:nv(g), j in i+1:nv(g) - if sum(abs2, g.locations[i] .- g.locations[j]) ≤ g.radius^2 - push!(edges, Graphs.SimpleEdge(i, j)) - end + has_edge(g, i, j) && push!(edges, Graphs.SimpleEdge(i, j)) end return edges end @@ -95,7 +92,7 @@ Base.eltype(::Type{Graphs.SimpleGraphs.SimpleEdgeIter{UnitDiskGraph{D,T}}}) wher end # return the next edge if it exists - if sum(abs2, g.locations[i] .- g.locations[j]) ≤ g.radius^2 + if has_edge(g, i, j) e = Graphs.SimpleEdge(i, j) state = (i, j + 1) return e, state @@ -107,31 +104,26 @@ Base.eltype(::Type{Graphs.SimpleGraphs.SimpleEdgeIter{UnitDiskGraph{D,T}}}) wher return nothing end -""" -$TYPEDEF +function Graphs.induced_subgraph(g::UnitDiskGraph, vlist::AbstractVector{<:Integer}) + return UnitDiskGraph(g.locations[vlist], g.radius), vlist +end -A grid graph is a graph in which the vertices are arranged in a grid and two vertices are connected by an edge if and only if they are adjacent in the grid. +function Graphs.neighbors(g::UnitDiskGraph, i::Int) + [j for j in 1:nv(g) if i != j && has_edge(g, i, j)] +end -### Fields -- `grid::BitMatrix`: a matrix of booleans, where `true` indicates the presence of an edge. -- `radius::Float64`: the radius of the unit disk """ -struct GridGraph <: Graphs.AbstractGraph{Int} - grid::BitMatrix - radius::Float64 +GridGraph is a unit disk graph with integer coordinates. +""" +const GridGraph{D} = UnitDiskGraph{D, Int} +function GridGraph(matrix::AbstractMatrix{Bool}, radius) + return UnitDiskGraph(vec(getfield.(findall(matrix), :I)), Float64(radius)) end -Base.:(==)(a::GridGraph, b::GridGraph) = a.grid == b.grid && a.radius == b.radius -Graphs.nv(g::GridGraph) = sum(g.grid) -Graphs.vertices(g::GridGraph) = 1:nv(g) -Graphs.ne(g::GridGraph) = length(Graphs.edges(g)) -function Graphs.edges(g::GridGraph) - udg = UnitDiskGraph([Float64.(x.I) for x in findall(g.grid)], g.radius) - return Graphs.edges(udg) +function GridGraph(locations::AbstractVector{NTuple{D, Int}}, radius::Float64) where {D} + return UnitDiskGraph(locations, radius) end -# not implemented -# struct PlanarGraph <: Graphs.AbstractGraph{Int} -# end +# TODO: implement the planar graph ##### Extra interfaces ##### _vec(e::Graphs.SimpleEdge) = [src(e), dst(e)] @@ -161,4 +153,4 @@ function _add_edge_weight!(g::HyperGraph, c::HyperEdge{Int}, J, weight) end push!(g.edges, c) push!(J, weight) -end \ No newline at end of file +end diff --git a/test/rules/rules.jl b/test/rules/rules.jl index 3c4a5d1a..d56d119f 100644 --- a/test/rules/rules.jl +++ b/test/rules/rules.jl @@ -84,6 +84,7 @@ end # reduce and solve result = reduceto(target_type, source) target = target_problem(result) + @test target isa target_type best_target = findbest(target, BruteForce()) # extract the solution diff --git a/test/rules/spinglass_sat.jl b/test/rules/spinglass_sat.jl index 0f792dc5..3f6c068a 100644 --- a/test/rules/spinglass_sat.jl +++ b/test/rules/spinglass_sat.jl @@ -82,8 +82,8 @@ end d = x ∨ (c ∧ ¬z) end sg, vars = ProblemReductions.circuit2spinglass(circuit) - indexof(x) = findfirst(==(x), vars) - gadget = LogicGadget(sg, indexof.([:x, :y, :z]), [indexof(:d)]) + indexof1(x) = findfirst(==(x), vars) + gadget = LogicGadget(sg, indexof1.([:x, :y, :z]), [indexof1(:d)]) tb = truth_table(gadget; variables=vars) @test tb.values == vec([(x & y & (1-z)) | x for x in [0, 1], y in [0, 1], z in [0, 1]]) res = reduceto(SpinGlass{<:SimpleGraph}, CircuitSAT(circuit)) @@ -95,8 +95,8 @@ end end circuitsat = CircuitSAT(circuit) result = reduceto(SpinGlass{<:SimpleGraph}, circuitsat) - indexof(x) = findfirst(==(x), circuitsat.symbols[sortperm(result.variables)]) - gadget = LogicGadget(result.spinglass, indexof.([:x, :y, :z]), [indexof(:d)]) + indexof2(x) = findfirst(==(x), circuitsat.symbols[sortperm(result.variables)]) + gadget = LogicGadget(result.spinglass, indexof2.([:x, :y, :z]), [indexof2(:d)]) tb = truth_table(gadget; variables=circuitsat.symbols[result.variables]) @test tb.values == vec([((1 - (x & y)) & (1-z)) | x for x in [0, 1], y in [0, 1], z in [0, 1]]) -end \ No newline at end of file +end diff --git a/test/topology.jl b/test/topology.jl index 87858349..bff02d96 100644 --- a/test/topology.jl +++ b/test/topology.jl @@ -40,4 +40,19 @@ end @test SimpleEdge(2, 3) in edges(gg) @test collect(edges(gg)) == [SimpleEdge(1, 2), SimpleEdge(2, 3)] @test vertices(gg) == 1:3 -end \ No newline at end of file + + grid = GridGraph([(2, 3), (2, 4), (5, 5)], 1.2) + g = SimpleGraph(grid) + @test ne(g) == 1 + @test vertices(grid) == vertices(g) + @test neighbors(grid, 2) == neighbors(g, 2) + + grid = GridGraph([(2, 3), (2, 4), (5, 5)], 4.0) + g = SimpleGraph(grid) + @test ne(g) == 3 + @test vertices(grid) == vertices(g) + @test neighbors(grid, 2) == neighbors(g, 2) + + ig, _ = induced_subgraph(grid, [1, 2]) + @test ne(ig) == 1 +end