diff --git a/lib/OptimalBranchingMIS/src/OptimalBranchingMIS.jl b/lib/OptimalBranchingMIS/src/OptimalBranchingMIS.jl index 1d02820..fd1dae1 100644 --- a/lib/OptimalBranchingMIS/src/OptimalBranchingMIS.jl +++ b/lib/OptimalBranchingMIS/src/OptimalBranchingMIS.jl @@ -8,7 +8,7 @@ using GenericTensorNetworks export MISProblem export MISReducer, XiaoReducer -export MinBoundarySelector +export MinBoundarySelector, MinBoundaryHighDegreeSelector export TensorNetworkSolver export NumOfVertices, D3Measure diff --git a/lib/OptimalBranchingMIS/src/interfaces.jl b/lib/OptimalBranchingMIS/src/interfaces.jl index c96637d..de29ab0 100644 --- a/lib/OptimalBranchingMIS/src/interfaces.jl +++ b/lib/OptimalBranchingMIS/src/interfaces.jl @@ -1,36 +1,36 @@ """ - mis_size(g::AbstractGraph; bs::BranchingStrategy = BranchingStrategy(table_solver = TensorNetworkSolver(), selector = MinBoundarySelector(2), measure=D3Measure()), reducer::AbstractReducer = MISReducer()) + mis_size(g::AbstractGraph; bs::BranchingStrategy = BranchingStrategy(table_solver = TensorNetworkSolver(), selector = MinBoundaryHighDegreeSelector(2, 6, 0), measure=D3Measure()), reducer::AbstractReducer = MISReducer()) Calculate the size of the Maximum Independent Set (MIS) for a given graph. ### Arguments - `g::AbstractGraph`: The graph for which the MIS size is to be calculated. -- `bs::BranchingStrategy`: (optional) The branching strategy to be used. Defaults to a strategy using `table_solver=TensorNetworkSolver`, `selector=MinBoundarySelector(2)`, and `measure=D3Measure`. +- `bs::BranchingStrategy`: (optional) The branching strategy to be used. Defaults to a strategy using `table_solver=TensorNetworkSolver`, `selector=MinBoundaryHighDegreeSelector(2, 6, 0)`, and `measure=D3Measure`. - `reducer::AbstractReducer`: (optional) The reducer to be applied. Defaults to `MISReducer`. ### Returns - An integer representing the size of the Maximum Independent Set for the given graph. """ -function mis_size(g::AbstractGraph; bs::BranchingStrategy = BranchingStrategy(table_solver = TensorNetworkSolver(), selector = MinBoundarySelector(2), measure=D3Measure()), reducer=MISReducer()) +function mis_size(g::AbstractGraph; bs::BranchingStrategy = BranchingStrategy(table_solver = TensorNetworkSolver(), selector = MinBoundaryHighDegreeSelector(2, 6, 0), measure=D3Measure()), reducer=MISReducer()) p = MISProblem(g) res = branch_and_reduce(p, bs, reducer, MaxSize) return res.size end """ - mis_branch_count(g::AbstractGraph; bs::BranchingStrategy = BranchingStrategy(table_solver = TensorNetworkSolver(), selector = MinBoundarySelector(2), measure=D3Measure()), reducer=MISReducer()) + mis_branch_count(g::AbstractGraph; bs::BranchingStrategy = BranchingStrategy(table_solver = TensorNetworkSolver(), selector = MinBoundaryHighDegreeSelector(2, 6, 0), measure=D3Measure()), reducer=MISReducer()) Calculate the size and the number of branches of the Maximum Independent Set (MIS) for a given graph. ### Arguments - `g::AbstractGraph`: The graph for which the MIS size and the number of branches are to be calculated. -- `bs::BranchingStrategy`: (optional) The branching strategy to be used. Defaults to a strategy using `table_solver=TensorNetworkSolver`, `selector=MinBoundarySelector(2)`, and `measure=D3Measure`. +- `bs::BranchingStrategy`: (optional) The branching strategy to be used. Defaults to a strategy using `table_solver=TensorNetworkSolver`, `selector=MinBoundaryHighDegreeSelector(2, 6, 0)`, and `measure=D3Measure`. - `reducer::AbstractReducer`: (optional) The reducer to be applied. Defaults to `MISReducer`. ### Returns - A tuple `(size, count)` where `size` is the size of the Maximum Independent Set and `count` is the number of branches. """ -function mis_branch_count(g::AbstractGraph; branching_strategy::BranchingStrategy = BranchingStrategy(table_solver = TensorNetworkSolver(), selector = MinBoundarySelector(2), measure=D3Measure()), reducer=MISReducer()) +function mis_branch_count(g::AbstractGraph; branching_strategy::BranchingStrategy = BranchingStrategy(table_solver = TensorNetworkSolver(), selector = MinBoundaryHighDegreeSelector(2, 6, 0), measure=D3Measure()), reducer=MISReducer()) p = MISProblem(g) res = branch_and_reduce(p, branching_strategy, reducer, MaxSizeBranchCount) return (res.size, res.count) diff --git a/lib/OptimalBranchingMIS/src/selector.jl b/lib/OptimalBranchingMIS/src/selector.jl index 4ef91c5..543a809 100644 --- a/lib/OptimalBranchingMIS/src/selector.jl +++ b/lib/OptimalBranchingMIS/src/selector.jl @@ -16,22 +16,61 @@ function OptimalBranchingCore.select_variables(p::MISProblem, m::M, selector::Mi @assert nv(g) > 0 kneighbor = selector.k + local vs_min + + novs_min = nv(g) + for v in 1:nv(g) + vs, ovs = neighbor_cover(g, v, kneighbor) + if length(ovs) < novs_min + vs_min = vs + novs_min = length(ovs) + end + end + return vs_min +end + +""" + struct MinBoundaryHighDegreeSelector <: AbstractVertexSelector + +The `MinBoundaryHighDegreeSelector` struct represents a strategy: + - if exists a vertex with degree geq high_degree_threshold, then select it and its k-degree neighbors. + - otherwise, select a subgraph with the minimum number of open vertices by k-layers of neighbors. + +# Fields +- `kb::Int`: The number of layers of neighbors to consider when selecting the subgraph. +- `hd::Int`: The threshold of degree for a vertex to be selected. +- `kd::Int`: The number of layers of neighbors to consider when selecting the subgraph. + +""" +struct MinBoundaryHighDegreeSelector <: AbstractSelector + kb::Int # k-boundary + hd::Int # high-degree threshold + kd::Int # k-degree +end + +function OptimalBranchingCore.select_variables(p::MISProblem, m::M, selector::MinBoundaryHighDegreeSelector) where{M<:AbstractMeasure} + g = p.g + @assert nv(g) > 0 + boundary_neighbor = selector.kb + high_degree_threshold = selector.hd + high_degree_neighbor = selector.kd + local vs_min # if exists a vertex with degree geq 6, then select it and it 1st-order neighbors. for v in 1:nv(g) - if degree(g, v) ≥ 6 - vs_min = neighbor_cover(g, v, 1)[1] + if degree(g, v) ≥ high_degree_threshold + vs_min = neighbor_cover(g, v, high_degree_neighbor)[1] return vs_min end end novs_min = nv(g) for v in 1:nv(g) - vs, ovs = neighbor_cover(g, v, kneighbor) + vs, ovs = neighbor_cover(g, v, boundary_neighbor) if length(ovs) < novs_min vs_min = vs novs_min = length(ovs) end end return vs_min -end \ No newline at end of file +end diff --git a/lib/OptimalBranchingMIS/test/branch.jl b/lib/OptimalBranchingMIS/test/branch.jl index 6c1522d..0362eaa 100644 --- a/lib/OptimalBranchingMIS/test/branch.jl +++ b/lib/OptimalBranchingMIS/test/branch.jl @@ -11,8 +11,8 @@ using Test, Random mis_exact = mis2(EliminateGraph(g)) p = MISProblem(g) - for set_cover_solver in [IPSolver(10, false), LPSolver(10, false)], measure in [D3Measure(), NumOfVertices()], reducer in [NoReducer(), MISReducer(), XiaoReducer()], prune_by_env in [true, false] - branching_strategy = BranchingStrategy(; set_cover_solver, table_solver=TensorNetworkSolver(; prune_by_env), selector=MinBoundarySelector(2), measure) + for set_cover_solver in [IPSolver(10, false), LPSolver(10, false)], measure in [D3Measure(), NumOfVertices()], reducer in [NoReducer(), MISReducer(), XiaoReducer()], prune_by_env in [true, false], selector in [MinBoundarySelector(2), MinBoundaryHighDegreeSelector(2, 6, 0), MinBoundaryHighDegreeSelector(2, 6, 1)] + branching_strategy = BranchingStrategy(; set_cover_solver, table_solver=TensorNetworkSolver(; prune_by_env), selector=selector, measure) res = branch_and_reduce(p, branching_strategy, reducer, MaxSize) res_count = branch_and_reduce(p, branching_strategy, reducer, MaxSizeBranchCount)