Skip to content

Commit

Permalink
update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
ArrogantGao committed Nov 24, 2024
1 parent b7d009f commit 740cba8
Show file tree
Hide file tree
Showing 19 changed files with 665 additions and 26 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@
Manifest.toml
.vscode
.DS_Store
./Manifest.toml
./Manifest.toml

lib/OptimalBranchingMIS/docs/build/
lib/OptimalBranchingCore/docs/build/
6 changes: 3 additions & 3 deletions lib/OptimalBranchingCore/src/OptimalBranchingCore.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ using Reexport

export Clause, BranchingTable, SubCover, DNF, Branch
export SolverConfig
export AbstractBranchingStrategy, NoBranchingStrategy, OptBranchingStrategy
export AbstractBranchingStrategy, OptBranchingStrategy
export AbstractProblem, AbstractResult, AbstractMeasure, AbstractReducer, AbstractSelector, AbstractPruner, AbstractTableSolver, AbstractSetCoverSolver
export NoProblem, NoResult, NoMeasure, NoReducer, NoSelector, NoPruner, NoTableSolver, LPSolver, IPSolver
export NoProblem, NoResult, NoPruner, LPSolver, IPSolver

export apply, measure, problem_reduce, select, solve_table, prune
export complexity, cover, branch
export complexity, cover, branch, solve_branches, optimal_branching

include("bitbasis.jl")
include("subcover.jl")
Expand Down
9 changes: 9 additions & 0 deletions lib/OptimalBranchingCore/src/bitbasis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,18 @@ end
Base.show(io::IO, ::MIME"text/plain", t::BranchingTable) = show(io, t)
Base.copy(t::BranchingTable) = BranchingTable(t.bit_length, copy(t.table))

"""
DNF{INT}
A data structure representing a Disjunctive Normal Form (DNF) expression. A DNF is a logical formula that is a disjunction of one or more conjunctions of literals.
# Fields
- `clauses::Vector{Clause{INT}}`: A vector of `Clause` objects representing the individual clauses in the DNF.
"""
struct DNF{INT}
clauses::Vector{Clause{INT}}
end

DNF(c::Clause{INT}, cs::Clause{INT}...) where {INT} = DNF([c, cs...])
Base.:(==)(x::DNF, y::DNF) = x.clauses == y.clauses
Base.length(x::DNF) = length(x.clauses)
Expand Down
36 changes: 36 additions & 0 deletions lib/OptimalBranchingCore/src/branch.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
"""
Generate optimal branches from a given branching table.
# Arguments
- `tbl::BranchingTable{INT}`: The branching table containing subcovers.
- `vs::Vector{T}`: A vector of variables to be used in the branching.
- `problem::P`: The problem instance being solved.
- `measure::M`: The measure used for evaluating the branches.
- `solver::S`: The solver used for the set cover problem.
- `::Type{R}`: The type of the result expected.
- `verbose::Bool`: Optional; if true, enables verbose output (default is false).
# Returns
A vector of `Branch` objects representing the optimal branches derived from the subcovers.
"""
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)
Expand All @@ -6,6 +21,16 @@ function optimal_branching(tbl::BranchingTable{INT}, vs::Vector{T}, problem::P,
end


"""
Branch the given problem using the specified solver configuration.
# Arguments
- `p::P`: The problem instance to branch.
- `config::SolverConfig`: The configuration for the solver.
# Returns
The maximum result obtained from the branches.
"""
function branch(p::P, config::SolverConfig) where{P<:AbstractProblem}

(p isa NoProblem) && return zero(config.result_type)
Expand All @@ -16,6 +41,17 @@ function branch(p::P, config::SolverConfig) where{P<:AbstractProblem}
return maximum([(branch(b.problem, config) + b.result) for b in branches])
end

"""
Solve branches of the given problem using the specified branching strategy.
# Arguments
- `p::P`: The problem instance to solve branches for.
- `strategy::OptBranchingStrategy`: The strategy to use for branching.
- `result_type::Type{R}`: The type of the result expected.
# Returns
A vector of branches derived from the problem using the specified strategy.
"""
function solve_branches(p::P, strategy::OptBranchingStrategy, result_type::Type{R}) where{P<:AbstractProblem, R<:AbstractResult}

vs = select(p, strategy.measure, strategy.selector)
Expand Down
79 changes: 74 additions & 5 deletions lib/OptimalBranchingCore/src/setcovering.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
function complexity(sbranches::Vector{T}) where{T}
# solve x, where 1 = sum(x^(-i) for i in sbranches)
"""
complexity(sbranches::Vector{T}) where {T}
Calculates the complexity based on the provided branching structures.
# Arguments
- `sbranches::Vector{T}`: A vector of branching structures, where each element represents a branch.
# Returns
- `Float64`: The computed complexity value.
"""
function complexity(sbranches::Vector{T}) where {T}
f = x -> sum(x[1]^(-i) for i in sbranches) - 1.0
sol = nlsolve(f, [1.0])
return sol.zero[1]
Expand Down Expand Up @@ -31,24 +42,66 @@ function dn(p::P, m::M, subcover::SubCover{INT}, vs::Vector{T}) where{P<:Abstrac
return measure(p, m) - measure(apply(p, subcover.clause, vs), m)
end

"""
cover(sub_covers::AbstractVector{SubCover{INT}}, p::P, m::M, vs::Vector{T}, solver::Union{LPSolver, IPSolver}; verbose::Bool = false) where{INT, P<:AbstractProblem, M<:AbstractMeasure, T}
Calculates the optimal cover from the provided subcovers using a specified solver.
# Arguments
- `sub_covers::AbstractVector{SubCover{INT}}`: A vector of subcover structures.
- `p::P`: An instance of a problem that needs to be solved.
- `m::M`: An instance of a measure associated with the problem.
- `vs::Vector{T}`: A vector of values used in the calculation.
- `solver::Union{LPSolver, IPSolver}`: The solver to be used for optimization.
- `verbose::Bool`: A flag to enable verbose output (default is false).
# Returns
- A tuple containing:
- A vector of selected subcovers.
- The computed complexity value.
# Description
This function computes the difference in measure for each subcover and then calls another `cover` function to find the optimal cover based on the computed differences.
"""
function cover(sub_covers::AbstractVector{SubCover{INT}}, p::P, m::M, vs::Vector{T}, solver::Union{LPSolver, IPSolver}; verbose::Bool = false) where{INT, P<:AbstractProblem, M<:AbstractMeasure, T}
dns = [dn(p, m, subcover, vs) for subcover in sub_covers]
return cover(sub_covers, dns, solver; verbose)
end

"""
cover(sub_covers::AbstractVector{SubCover{INT}}, dns::Vector{TF}, solver::LPSolver; verbose::Bool = false) where{INT, TF}
Finds the optimal cover based on the provided differences in measure.
# Arguments
- `sub_covers::AbstractVector{SubCover{INT}}`: A vector of subcover structures.
- `dns::Vector{TF}`: A vector of differences in measure for each subcover.
- `solver::LPSolver`: The linear programming solver to be used.
- `verbose::Bool`: A flag to enable verbose output (default is false).
# Returns
- A tuple containing:
- A vector of selected subcovers.
- The computed complexity value.
# Description
This function iteratively solves the linear programming problem to find the optimal cover, updating the complexity value until convergence or the maximum number of iterations is reached.
"""
function cover(sub_covers::AbstractVector{SubCover{INT}}, dns::Vector{TF}, solver::LPSolver; verbose::Bool = false) where{INT, TF}
max_itr = solver.max_itr
cx, n = γ0(sub_covers, dns)
verbose && (@info "γ0 = $(cx)")
scs_new = copy(sub_covers)
cx_old = cx
for i =1:max_itr
for i = 1:max_itr
xs = LP_setcover(cx, scs_new, n, dns, verbose)
picked_scs = random_pick(xs, sub_covers, n)
cx = complexity(dns[picked_scs])
picked = sub_covers[picked_scs]
verbose && (@info "LP Solver, Iteration $i, complexity = $cx")
if (i == max_itr) || (cx cx_old)
if (i == max_itr) || (cx cx_old)
return picked, cx
else
cx_old = cx
Expand Down Expand Up @@ -109,13 +162,29 @@ function pick(xs::Vector{TF}, sub_covers::AbstractVector{SubCover{INT}}) where{I
return [sub_covers[i] for i in 1:length(xs) if xs[i] 1.0]
end

"""
cover(sub_covers::AbstractVector{SubCover{INT}}, dns::Vector{TF}, solver::IPSolver; verbose::Bool = false) where{INT, TF}
This function implements a cover selection algorithm using an iterative process. It utilizes an integer programming solver to optimize the selection of sub-covers based on their complexity.
# Arguments
- `sub_covers::AbstractVector{SubCover{INT}}`: A vector of sub-cover objects that represent the available covers.
- `dns::Vector{TF}`: A vector of decision variables or parameters that influence the complexity calculation.
- `solver::IPSolver`: An object that contains the settings for the integer programming solver, including the maximum number of iterations.
- `verbose::Bool`: A flag to control the verbosity of the output. If set to true, additional information will be logged.
# Returns
- A tuple containing:
- `picked`: A vector of selected sub-covers based on the optimization process.
- `cx`: The final complexity value after the optimization iterations.
"""
function cover(sub_covers::AbstractVector{SubCover{INT}}, dns::Vector{TF}, solver::IPSolver; verbose::Bool = false) where{INT, TF}
max_itr = solver.max_itr
cx, n = γ0(sub_covers, dns)
verbose && (@info "γ0 = $cx")
scs_new = copy(sub_covers)
cx_old = cx
for i =1:max_itr
for i = 1:max_itr
xs = IP_setcover(cx, scs_new, n, dns, verbose)
cx = complexity(dns[xs .≈ 1.0])
picked = pick(xs, sub_covers)
Expand Down
33 changes: 32 additions & 1 deletion lib/OptimalBranchingCore/src/subcover.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@ function subcovers_naive(tbl::BranchingTable{INT}) where{INT}
return subcovers_naive(tbl.bit_length, tbl.table)
end

"""
subcovers(n::Int, bss::AbstractVector{Vector{INT}}) where {INT}
Generates a set of subcovers from the given bit strings.
# Arguments
- `n::Int`: The length of the bit strings.
- `bss::AbstractVector{Vector{INT}}`: A collection of vectors containing bit strings.
# Returns
- `Vector{SubCover{INT}}`: A vector of `SubCover` objects representing the generated subcovers.
# Description
This function concatenates the input vectors of bit strings and iteratively generates clauses. It maintains a set of all unique clauses and uses a temporary list to explore new clauses formed by combining existing ones. The resulting subcovers are created based on the covered items for each clause.
"""
function subcovers(n::Int, bss::AbstractVector{Vector{INT}}) where {INT}
bs = vcat(bss...)
all_clauses = Set{Clause{INT}}()
Expand Down Expand Up @@ -57,6 +73,21 @@ function subcovers(n::Int, bss::AbstractVector{Vector{INT}}) where {INT}
return allcovers
end

function subcovers(tbl::BranchingTable{INT}) where{INT}
"""
subcovers(tbl::BranchingTable{INT}) where {INT}
Generates subcovers from a branching table.
# Arguments
- `tbl::BranchingTable{INT}`: The branching table containing bit strings.
# Returns
- `Vector{SubCover{INT}}`: A vector of `SubCover` objects generated from the branching table.
# Description
This function calls the `subcovers` function with the bit length and table from the provided branching table to generate the corresponding subcovers.
"""
function subcovers(tbl::BranchingTable{INT}) where {INT}
return subcovers(tbl.bit_length, tbl.table)
end
Loading

0 comments on commit 740cba8

Please sign in to comment.