From 943c81e1f3a624f9f970b002498821675d83780a Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Mon, 20 Jan 2025 00:34:46 +0800 Subject: [PATCH] allow setting initial gamma --- lib/OptimalBranchingCore/src/branch.jl | 8 +++---- lib/OptimalBranchingCore/src/setcovering.jl | 21 ++++++++-------- lib/OptimalBranchingCore/test/mockproblem.jl | 25 ++++++++++++++------ lib/OptimalBranchingMIS/src/interfaces.jl | 18 +++++++++----- 4 files changed, 45 insertions(+), 27 deletions(-) diff --git a/lib/OptimalBranchingCore/src/branch.jl b/lib/OptimalBranchingCore/src/branch.jl index 3af39d4..458802f 100644 --- a/lib/OptimalBranchingCore/src/branch.jl +++ b/lib/OptimalBranchingCore/src/branch.jl @@ -16,7 +16,7 @@ A [`OptimalBranchingResult`](@ref) object representing the optimal branching rul function optimal_branching_rule(table::BranchingTable, variables::Vector, problem::AbstractProblem, m::AbstractMeasure, solver::AbstractSetCoverSolver) candidates = candidate_clauses(table) size_reductions = [size_reduction(problem, m, candidate, variables) for candidate in candidates] - return minimize_γ(table, candidates, size_reductions, solver; γ0 = 2.0) + return minimize_γ(table, candidates, size_reductions, solver) end function size_reduction(p::AbstractProblem, m::AbstractMeasure, cl::Clause{INT}, variables::Vector) where {INT} @@ -72,7 +72,7 @@ function branch_and_reduce(problem::AbstractProblem, config::BranchingStrategy, has_zero_size(problem) && return zero(result_type) # reduce the problem rp, reducedvalue = reduce_problem(result_type, problem, reducer) - rp !== problem && return branch_and_reduce(rp, config, reducer, result_type; tag) * reducedvalue + rp !== problem && return branch_and_reduce(rp, config, reducer, result_type; tag, show_progress) * reducedvalue # branch the problem variables = select_variables(rp, config.measure, config.selector) # select a subset of variables @@ -92,9 +92,9 @@ function print_sequence(io::IO, sequence::Vector{Tuple{Int,Int}}) if i == n print(io, "■") elseif i == 1 - print(io, "□") + print(io, "⋅") else - print(io, "▦") + print(io, "□") end end end \ No newline at end of file diff --git a/lib/OptimalBranchingCore/src/setcovering.jl b/lib/OptimalBranchingCore/src/setcovering.jl index c54c2b6..bfade16 100644 --- a/lib/OptimalBranchingCore/src/setcovering.jl +++ b/lib/OptimalBranchingCore/src/setcovering.jl @@ -7,35 +7,39 @@ abstract type AbstractSetCoverSolver end """ LPSolver <: AbstractSetCoverSolver - LPSolver(; optimizer = HiGHS.Optimizer, max_itr::Int = 5, verbose::Bool = false) + LPSolver(; optimizer = HiGHS.Optimizer, max_itr::Int = 20, γ0::Float64 = 2.0, verbose::Bool = false) A linear programming solver for set covering problems. ### Fields - `optimizer`: The optimizer to be used. - `max_itr::Int`: The maximum number of iterations to be performed. +- `γ0::Float64`: The initial γ value. - `verbose::Bool`: Whether to print the solver's output. """ Base.@kwdef struct LPSolver <: AbstractSetCoverSolver optimizer = HiGHS.Optimizer - max_itr::Int = 5 + max_itr::Int = 20 + γ0::Float64 = 2.0 verbose::Bool = false end """ IPSolver <: AbstractSetCoverSolver - IPSolver(; optimizer = HiGHS.Optimizer, max_itr::Int = 5, verbose::Bool = false) + IPSolver(; optimizer = HiGHS.Optimizer, max_itr::Int = 20, γ0::Float64 = 2.0, verbose::Bool = false) An integer programming solver for set covering problems. ### Fields - `optimizer`: The optimizer to be used. - `max_itr::Int`: The maximum number of iterations to be performed. +- `γ0::Float64`: The initial γ value. - `verbose::Bool`: Whether to print the solver's output. """ Base.@kwdef struct IPSolver <: AbstractSetCoverSolver optimizer = HiGHS.Optimizer - max_itr::Int = 5 + max_itr::Int = 20 + γ0::Float64 = 2.0 verbose::Bool = false end @@ -127,15 +131,12 @@ It utilizes an integer programming solver to optimize the selection of sub-cover - `Δρ::Vector`: A vector of problem size reduction for each candidate clause. - `solver`: The solver to be used. It can be an instance of `LPSolver` or `IPSolver`. -### Keyword Arguments -- `γ0::Float64`: The initial γ value. - ### Returns A tuple of two elements: (indices of selected subsets, γ) """ -function minimize_γ(table::BranchingTable, candidates::Vector{Clause{INT}}, Δρ::Vector, solver::AbstractSetCoverSolver; γ0::Float64 = 2.0) where {INT} +function minimize_γ(table::BranchingTable, candidates::Vector{Clause{INT}}, Δρ::Vector, solver::AbstractSetCoverSolver) where {INT} subsets = [covered_items(table.table, c) for c in candidates] - @debug "solver = $(solver), subsets = $(subsets), γ0 = $γ0, Δρ = $(Δρ)" + @debug "solver = $(solver), subsets = $(subsets), γ0 = $(solver.γ0), Δρ = $(Δρ)" num_items = length(table.table) # Note: the following instance is captured for time saving, and also for it may cause IP solver to fail @@ -143,7 +144,7 @@ function minimize_γ(table::BranchingTable, candidates::Vector{Clause{INT}}, Δ (length(subset) == num_items) && return OptimalBranchingResult(DNF([candidates[k]]), [Δρ[k]], 1.0) end - cx_old = cx = γ0 + cx_old = cx = solver.γ0 local picked_scs for i = 1:solver.max_itr weights = 1 ./ cx_old .^ Δρ diff --git a/lib/OptimalBranchingCore/test/mockproblem.jl b/lib/OptimalBranchingCore/test/mockproblem.jl index b527517..ad192a0 100644 --- a/lib/OptimalBranchingCore/test/mockproblem.jl +++ b/lib/OptimalBranchingCore/test/mockproblem.jl @@ -25,20 +25,31 @@ end n = 100 nsample = 3 p = MockProblem(rand(Bool, n)) - config = BranchingStrategy(table_solver=MockTableSolver(nsample), measure=NumOfVariables(), selector=RandomSelector(16)) + config = BranchingStrategy(table_solver=MockTableSolver(nsample), measure=NumOfVariables(), selector=RandomSelector(16), set_cover_solver=NaiveBranch()) + res0 = branch_and_reduce(p, config, NoReducer(), MaxSizeBranchCount; show_progress=false) + @test res0.size == 100 + + config = BranchingStrategy(table_solver=MockTableSolver(nsample), measure=NumOfVariables(), selector=RandomSelector(16), set_cover_solver=IPSolver()) @test branch_and_reduce(p, config, NoReducer(), MaxSize).size == 100 res1 = branch_and_reduce(p, config, NoReducer(), MaxSizeBranchCount; show_progress=true) @test res1.size == 100 + @test res1.count < res0.count - config = BranchingStrategy(table_solver=MockTableSolver(nsample), measure=NumOfVariables(), selector=RandomSelector(16), set_cover_solver=NaiveBranch()) - res2 = branch_and_reduce(p, config, NoReducer(), MaxSizeBranchCount; show_progress=true) + config = BranchingStrategy(table_solver=MockTableSolver(nsample), measure=NumOfVariables(), selector=RandomSelector(16), set_cover_solver=LPSolver()) + res2 = branch_and_reduce(p, config, NoReducer(), MaxSizeBranchCount; show_progress=false) @test res2.size == 100 - @test res1.count < res2.count + @test res2.count < res0.count config = BranchingStrategy(table_solver=MockTableSolver(nsample), measure=NumOfVariables(), selector=RandomSelector(16), set_cover_solver=GreedyMerge()) - res3 = branch_and_reduce(p, config, NoReducer(), MaxSizeBranchCount; show_progress=true) + res3 = branch_and_reduce(p, config, NoReducer(), MaxSizeBranchCount; show_progress=false) @test res3.size == 100 - @test res2.count > res3.count + @test res3.count < res0.count + + # gamma informed, let γ0 be 1.05 + config = BranchingStrategy(table_solver=MockTableSolver(nsample), measure=NumOfVariables(), selector=RandomSelector(16), set_cover_solver=IPSolver(max_itr=1, γ0=1.05)) + res4 = branch_and_reduce(p, config, NoReducer(), MaxSizeBranchCount; show_progress=false) + @test res4.size == 100 + @test res4.count < res0.count - @show res1.count, res2.count, res3.count + @show res0.count, res1.count, res2.count, res3.count, res4.count end diff --git a/lib/OptimalBranchingMIS/src/interfaces.jl b/lib/OptimalBranchingMIS/src/interfaces.jl index 83e397a..14d3ae0 100644 --- a/lib/OptimalBranchingMIS/src/interfaces.jl +++ b/lib/OptimalBranchingMIS/src/interfaces.jl @@ -1,37 +1,43 @@ """ - mis_size(g::AbstractGraph; branching_strategy::BranchingStrategy = BranchingStrategy(table_solver = TensorNetworkSolver(), selector = MinBoundaryHighDegreeSelector(2, 6, 0), measure=D3Measure()), reducer::AbstractReducer = MISReducer()) + mis_size(g::AbstractGraph; branching_strategy::BranchingStrategy = BranchingStrategy(table_solver = TensorNetworkSolver(), selector = MinBoundaryHighDegreeSelector(2, 6, 0), measure=D3Measure()), reducer::AbstractReducer = MISReducer(), show_progress::Bool = false) 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. + +### Keyword Arguments - `branching_strategy::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`. +- `show_progress::Bool`: (optional) Whether to show the progress of the branching and reduction process. Defaults to `false`. ### Returns - An integer representing the size of the Maximum Independent Set for the given graph. """ -function mis_size(g::AbstractGraph; branching_strategy::BranchingStrategy = BranchingStrategy(table_solver = TensorNetworkSolver(), selector = MinBoundaryHighDegreeSelector(2, 6, 0), measure = D3Measure()), reducer = MISReducer()) +function mis_size(g::AbstractGraph; branching_strategy::BranchingStrategy = BranchingStrategy(table_solver = TensorNetworkSolver(), selector = MinBoundaryHighDegreeSelector(2, 6, 0), measure = D3Measure()), reducer = MISReducer(), show_progress::Bool = false) p = MISProblem(g) - res = branch_and_reduce(p, branching_strategy, reducer, MaxSize) + res = branch_and_reduce(p, branching_strategy, reducer, MaxSize; show_progress) return res.size end """ - mis_branch_count(g::AbstractGraph; branching_strategy::BranchingStrategy = BranchingStrategy(table_solver = TensorNetworkSolver(), selector = MinBoundaryHighDegreeSelector(2, 6, 0), measure=D3Measure()), reducer=MISReducer()) + mis_branch_count(g::AbstractGraph; branching_strategy::BranchingStrategy = BranchingStrategy(table_solver = TensorNetworkSolver(), selector = MinBoundaryHighDegreeSelector(2, 6, 0), measure=D3Measure()), reducer=MISReducer(), show_progress::Bool = false) 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. + +### Keyword Arguments - `branching_strategy::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`. +- `show_progress::Bool`: (optional) Whether to show the progress of the branching and reduction process. Defaults to `false`. ### 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 = MinBoundaryHighDegreeSelector(2, 6, 0), 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(), show_progress::Bool = false) p = MISProblem(g) - res = branch_and_reduce(p, branching_strategy, reducer, MaxSizeBranchCount) + res = branch_and_reduce(p, branching_strategy, reducer, MaxSizeBranchCount; show_progress) return (res.size, res.count) end