Skip to content

Commit

Permalink
update optimalbranchingmis
Browse files Browse the repository at this point in the history
  • Loading branch information
ArrogantGao committed Nov 23, 2024
1 parent cfa2431 commit 863884c
Show file tree
Hide file tree
Showing 17 changed files with 570 additions and 30 deletions.
4 changes: 2 additions & 2 deletions lib/OptimalBranchingCore/src/OptimalBranchingCore.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export AbstractBranchingStrategy, NoBranchingStrategy, OptimalBranching
export AbstractProblem, AbstractResult, AbstractMeasure, AbstractReducer, AbstractSelector, AbstractPruner, AbstractTableSolver, AbstractSetCoverSolver
export NoProblem, NoResult, NoMeasure, NoReducer, NoSelector, NoPruner, NoTableSolver, LPSolver, IPSolver

export apply, measure, reduce!, select, solve_table, prune
export complexity, cover
export apply, measure, reduce, select, solve_table, prune
export complexity, cover, branch

include("bitbasis.jl")
include("subcover.jl")
Expand Down
5 changes: 2 additions & 3 deletions lib/OptimalBranchingCore/src/bitbasis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,7 @@ struct BranchingTable{INT <: Integer}
bit_length::Int
table::Vector{Vector{INT}}
end
function BranchingTable(arr::AbstractArray{<:CountingTropical{<:Real, <:ConfigEnumerator{N}}}) where N
return BranchingTable(N, filter(!isempty, vec(map(collect_configs, arr))))
end

function BranchingTable(n::Int, arr::AbstractVector{<:AbstractVector})
return BranchingTable(n, [_vec2int.(LongLongUInt, x) for x in arr])
end
Expand All @@ -178,6 +176,7 @@ function Base.show(io::IO, t::BranchingTable{INT}) where INT
end
end
Base.show(io::IO, ::MIME"text/plain", t::BranchingTable) = show(io, t)
Base.copy(t::BranchingTable) = BranchingTable(t.bit_length, copy(t.table))

struct DNF{INT}
clauses::Vector{Clause{INT}}
Expand Down
20 changes: 13 additions & 7 deletions lib/OptimalBranchingCore/src/branch.jl
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
function optimal_branching(tbl::BranchingTable{INT}, vs::Vector{T}, problem::P, measure::M, solver::S, ::Type{R}; verbose::Bool = false) where{INT, T, P<:AbstractProblem, M<:AbstractMeasure, S<:AbstractSetCoverSolver, R<:AbstractResult}
sub_covers = subcovers(tbl)
cov, cx = cover(sub_covers, problem, measure, vs, solver; verbose)
branches = Branches([Branch(sub_cover.clause, vs, problem, R) for sub_cover in cov])
branches = [Branch(sub_cover.clause, vs, problem, R) for sub_cover in cov]
return branches
end


function solve(p::P, config::SolverConfig) where{P<:AbstractProblem}
reduce!(p, config.reducer)
branches = solve_branches(p, config.branching_strategy)
return sum([(b.problem isa NoProblem) ? b.result : (solve(b.problem, config) * b.result) for b in branches])
function branch(p::P, config::SolverConfig) where{P<:AbstractProblem}

(p isa NoProblem) && return zero(config.result_type)

reduced = reduce(p, config.reducer, config.result_type)
branches = !isnothing(reduced) ? [Branch(reduced[1], reduced[2])] : solve_branches(p, config.branching_strategy, config.result_type)

return maximum([(branch(b.problem, config) + b.result) for b in branches])
end

function solve_branches(p::P, strategy::OptimalBranching) where{P<:AbstractProblem}
function solve_branches(p::P, strategy::OptimalBranching, result_type::Type{R}) where{P<:AbstractProblem, R<:AbstractResult}

vs = select(p, strategy.measure, strategy.selector)
tbl = solve_table(p, strategy.table_solver, vs)
pruned_tbl = prune(tbl, strategy.pruner, strategy.measure, p, vs)
branches = optimal_branching(pruned_tbl, vs, p, strategy.measure, strategy.set_cover_solver, strategy.table_result)
branches = optimal_branching(pruned_tbl, vs, p, strategy.measure, strategy.set_cover_solver, result_type)

return branches
end
17 changes: 9 additions & 8 deletions lib/OptimalBranchingCore/src/types.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
abstract type AbstractProblem end
struct NoProblem end
apply(::NoProblem, ::Clause, ::Vector{T}) where{T} = NoProblem()

struct NoProblem <: AbstractProblem end
abstract type AbstractResult end
struct NoResult <: AbstractResult end

apply(::NoProblem, ::Clause, vs) = NoProblem()
result(::NoProblem, ::Clause, vs, ::Type{R}) where{R<:AbstractResult} = NoResult()

# abstract type AbstractBranching end

abstract type AbstractMeasure end
Expand All @@ -13,15 +14,15 @@ function measure(::P, ::NoMeasure) where{P<:AbstractProblem} return 0 end

abstract type AbstractReducer end
struct NoReducer <: AbstractReducer end
function reduce!(p::P, ::NoReducer) where{P<:AbstractProblem} return p end
function reduce(p::P, ::NoReducer, ::Type{R}) where{P<:AbstractProblem, R<:AbstractResult} return nothing end

abstract type AbstractSelector end
struct NoSelector <: AbstractSelector end
function select(::P, ::M, ::NoSelector) where{P<:AbstractProblem, M<:AbstractMeasure} return nothing end

abstract type AbstractPruner end
struct NoPruner <: AbstractPruner end
prune(bt::BranchingTable, ::NoPruner, ::M, ::P, vs) where{M<:AbstractMeasure, P<:AbstractProblem} = copy(bt)
prune(bt::BranchingTable, ::NoPruner, ::M, ::P, vs) where{M<:AbstractMeasure, P<:AbstractProblem} = bt

abstract type AbstractTableSolver end
struct NoTableSolver <: AbstractTableSolver end
Expand All @@ -41,7 +42,7 @@ A struct representing a branching strategy.
- `mis::Int`: An integer representing the maximum independent set (MIS) size of the branching strategy.
"""
struct Branch{P<:AbstractProblem, R<:AbstractResult}
struct Branch{P<:AbstractProblem, R}
problem::P
result::R
end
Expand All @@ -64,5 +65,5 @@ end
struct SolverConfig{R<:AbstractReducer, B<:AbstractBranchingStrategy, TR<:AbstractResult}
reducer::R
branching_strategy::B
table_result::Type{TR}
end
result_type::Type{TR}
end
10 changes: 3 additions & 7 deletions lib/OptimalBranchingMIS/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,13 @@ authors = ["Xuanzhao Gao <[email protected]> and contributors"]
version = "1.0.0-DEV"

[deps]
Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
EliminateGraphs = "b3ff564c-d3b6-11e9-0ef2-9b4ae9f9cbe1"
GenericTensorNetworks = "3521c873-ad32-4bb4-b63d-f4f178f42b49"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
OptimalBranchingAPI = "fc6b5187-3699-421e-a5a4-8833c3921c85"
OptimalBranchingCore = "c76e7b22-e1d2-40e8-b0f1-f659837787b8"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"

[compat]
Combinatorics = "1.0.2"
EliminateGraphs = "0.2.1"
GenericTensorNetworks = "2.2.0"
Graphs = "1.12.0"
Reexport = "1.2.2"
julia = "1.6.7"

[extras]
Expand Down
22 changes: 20 additions & 2 deletions lib/OptimalBranchingMIS/src/OptimalBranchingMIS.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
module OptimalBranchingMIS

using OptimalBranchingAPI
using EliminateGraphs, GenericTensorNetworks, GenericTensorNetworks.Graphs
using Reexport
@reexport using OptimalBranchingCore
using EliminateGraphs, EliminateGraphs.Graphs
using OptimalBranchingCore.GenericTensorNetworks

export MISProblem
export MISSize, MISCount
export MISReducer, MinBoundarySelector, EnvFilter, TensorNetworkSolver
export NumOfVertices, D3Measure

export counting_mis1, counting_mis2

include("types.jl")
include("graphs.jl")
include("algorithms/mis1.jl")
include("algorithms/mis2.jl")

include("reducer.jl")
include("selector.jl")
include("tablesolver.jl")
include("pruner.jl")
include("branch.jl")

end
11 changes: 11 additions & 0 deletions lib/OptimalBranchingMIS/src/algorithms/mis1.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function counting_mis1(eg::EliminateGraph)
N = nv(eg)
if N == 0
return MISCount(0)
else
vmin, dmin = mindegree_vertex(eg)
return 1 + neighborcover_mapreduce(y->eliminate(counting_mis1, eg, NeighborCover(y)), max, eg, vmin)
end
end

counting_mis1(g::SimpleGraph) = counting_mis1(EliminateGraph(g))
110 changes: 110 additions & 0 deletions lib/OptimalBranchingMIS/src/algorithms/mis2.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using EliminateGraphs: adjacent45

function counting_mis2(eg::EliminateGraph)
if nv(eg) == 0
#@show "0" # CHECKED
return MISCount(0)
elseif nv(eg) == 1
return MISCount(1)
elseif nv(eg) == 2
return MISCount(2 - (@inbounds isconnected(eg, eg.vertices[end-1], eg.vertices[end])))
elseif nv(eg) == 3
@inbounds a, b, c = eg.vertices[end-2:end]
nedge = isconnected(eg, a, b) + isconnected(eg, a, c) + isconnected(eg, b, c)
if nedge == 0
return MISCount(3)
elseif nedge == 3
return MISCount(1)
else
return MISCount(2)
end
else
#@show "1" # CHECKED
vmin, degmin = mindegree_vertex(eg)
if degmin == 0 # DONE
#@show "1.1(1)" # CHECKED
return 1 + eliminate(counting_mis2, eg, vmin)
elseif degmin == 1 # DONE
#@show "1.1(2)" # CHECKED
return 1 + eliminate(counting_mis2, eg, NeighborCover(vmin))
elseif degmin == 2
#@show "1.2" # CHECKED
a, b = neighbors(eg, vmin)
if isconnected(eg, a, b)
#@show "1.2.1" # CHECKED
return 1 + eliminate(counting_mis2, eg, NeighborCover(vmin))
else
#@show "1.2.2" # CHECKED
sn = neighbors2(eg, vmin)
# NOTE: there is no degree one vertex!
if length(sn) == 1
#@show "1.2.2.1" # CHECKED
w = sn[1]
#return max(2+eliminate(counting_mis2, eg, NeighborCover(w) ∪ Neighbors{CLOSED,2}(vmin)),
#2+eliminate(counting_mis2, eg, Neighbors{CLOSED,2}(vmin)),
# Note: it seems it must choose the latter. Gurantted if one removes one vertex, the MIS is non-increasing.
return 2+eliminate(counting_mis2, eg, (vmin, w, a, b)
)
else
#@show "1.2.2.2" # CHECKED
return max(1+eliminate(counting_mis2, eg, NeighborCover(vmin)),
eliminate(counting_mis2, eg, MirrorCover(vmin)))
end
end
elseif degmin == 3 # DONE
#@show "1.3" #CHECKED
a, b, c = neighbors(eg, vmin)
nedge = isconnected(eg, a, b) + isconnected(eg, a, c) + isconnected(eg, b, c)
if nedge == 0
#@show "1.3.1" #CHECKED
ms = mirrorcover(eg, vmin)
if length(ms) > 1
#@show "1.3.1.1" # CHECKED
return max(1+eliminate(counting_mis2, eg, NeighborCover(vmin)),
eliminate(counting_mis2, eg, ms))
else
#@show "1.3.1.2" # CHECKED
return max(1+eliminate(counting_mis2, eg, NeighborCover(vmin)),
2 + eliminate(counting_mis2, eg, NeighborCover(a) NeighborCover(b)),
2 + eliminate(counting_mis2, eg, NeighborCover(a) NeighborCover(c) Vertex(b)),
2 + eliminate(counting_mis2, eg, NeighborCover(b) NeighborCover(c) Vertex(a)),
)
end
elseif nedge == 3
#@show "1.3.2" # CHECKED
return 1 + eliminate(counting_mis2, eg, NeighborCover(vmin))
else
#@show "1.3.3" # CHECKED
return max(1 + eliminate(counting_mis2, eg, NeighborCover(vmin)),
eliminate(counting_mis2, eg, MirrorCover(vmin)))
end
else # DONE
#@show "1.4" # CHECKED
vmax, degmax = maxdegree_vertex(eg)
if degmax >= 6 # DONE
#@show "1.4.1"
return max(1+eliminate(counting_mis2, eg, NeighborCover(vmax)),
eliminate(counting_mis2, eg, vmax))
elseif !isconnected(eg) # DONE
#@show "1.4.2" # CHECKED
cluster = find_cluster(eg, vmax)
A = subgraph(eg, cluster)
B = subgraph(eg, setdiff(vertices(eg), cluster))
return counting_mis2(A) + counting_mis2(B)
elseif degmin == degmax # DONE
#@show "1.4.3" # CHECKED
return max(1+eliminate(counting_mis2, eg, NeighborCover(vmax)),
eliminate(counting_mis2, eg, MirrorCover(vmax)))
else
#@show "1.4.4" # CHECKED
v4, v5 = adjacent45(eg)
return max(1+eliminate(counting_mis2, eg, NeighborCover(v5)),
1+eliminate(counting_mis2, eg, MirrorCover(v5) NeighborCover(v4)),
eliminate(counting_mis2, eg, MirrorCover(v5) Vertex(v4))
)
end
end
end
end

counting_mis2(g::SimpleGraph) = counting_mis2(EliminateGraph(g))
9 changes: 9 additions & 0 deletions lib/OptimalBranchingMIS/src/branch.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function OptimalBranchingCore.apply(p::MISProblem, clause::Clause{INT}, vertices::Vector{T}) where {INT<:Integer, T<:Integer}
g = p.g
vertices_removed = removed_vertices(vertices, g, clause)
return MISProblem(remove_vertices(g, vertices_removed))
end

function OptimalBranchingCore.result(p::MISProblem, clause::Clause{INT}, vertices::Vector{T}, TR::Type{R}) where {INT<:Integer, R<:AbstractResult, T<:Integer}
return count_ones(clause.val)
end
Loading

0 comments on commit 863884c

Please sign in to comment.