调用步骤入下:
参考代码:
using BranchAndBound
using JuMP
using GLPK
const BB = BranchAndBound
m = Model(GLPK.Optimizer)
M = 100000
c = [3 4 1]
A = [1 6 2;2 0 0]
b = [5;3]
@variable(m, 0<=x[1:3]<=M) # assume integrality
@objective(m, Min, sum(c*x))
@constraint(m, A*x .>=b);
tree = BB.initialize_tree(m);
best_solution = nothing
function BB.branch!(tree::BB.AbstractTree, node::BB.AbstractNode)
@info " Node id $(node.id), status $(node.solution_status), bound $(node.bound)"
if node.bound >= tree.best_incumbent
@info " Fathomed by bound"
elseif node.solution_status in [MOI.OPTIMAL, MOI.LOCALLY_SOLVED]
feasible_solution = true
for i in 1:length(x)
if !isinteger(node.solution[x[i]])
@info " Branch at x$i = $(node.solution[x[i]]), x$i >= $(ceil(node.solution[x[i]])), x$i <= $(floor(node.solution[x[i]]))"
child1 = BB.create_child_node_with_lb(node, x[i], ceil(node.solution[x[i]]))
child2 = BB.create_child_node_with_ub(node, x[i], floor(node.solution[x[i]]))
BB.push!(tree, child1)
BB.push!(tree, child2)
feasible_solution = false
break
end
end
if feasible_solution && node.bound < tree.best_incumbent
@info " New incumbent bound: $(node.bound)"
global best_solution = [node.solution[x[i]] for i in 1:length(x)]
tree.best_incumbent = node.bound
end
else
@info " Fathomed by solution status: $(node.solution_status)"
end
end
function BB.termination(tree::BB.AbstractTree)
@info "Tree nodes: processed $(length(tree.processed)), left $(length(tree.nodes)), total $(tree.node_counter), best bound $(tree.best_bound), best incumbent $(tree.best_incumbent)"
if BB.isempty(tree) || length(tree.processed) >= 20
@info "Completed the tree search"
return true
end
return false
end
BB.run(tree)
best_solution
linprog是应用在节点上的线性规划求解器。
integerPro是使用递归构造搜索树的函数。
using JuMP
using GLPK
function linprog(c, A, b)
m = Model(GLPK.Optimizer)
n = length(c)
@variable(m, 0<=x[1:n])
@objective(m, Max, sum(c*x))
@constraint(m, A*x .<=b);
optimize!(m)
if Int(primal_status(m)) == 1
return value.(x)
else
return nothing
end
end
search_time = 0
LB = -Inf
x_val = nothing
function integerPro(c, A, b, t = 1e-5, search_limit = 100)
global search_time += 1
if search_time >= search_limit
@info "reach limit"
return nothing
end
x = linprog(c,A,b)
if x==nothing
@info "node $search_time: Infeasible"
return nothing
end
inte = [(xi-floor(xi)LB
LB = obj;
global x_val = x
@info "node $search_time: LB = $obj \nx=$(round.(x,digits=2))"
else
@info "node $search_time: $(sum(c*x)) <= $LB \nx=$(round.(x,digits=2)) \nFathomed by LB"
end
return x
else
ind = findfirst(.!(inte))
x_b = x[ind]
@info "node $search_time: $obj \nx=$(round.(x,digits=2)) \nbranch on x$ind: x$ind<=$(floor(x_b)),x$ind>=$(ceil(x_b)) "
A1 = zeros(Int,length(c))';A1[ind] = 1
A2 = zeros(Int,length(c))';A2[ind] = -1
x1 = integerPro(c, [copy(A);A1], [copy(b);floor(x_b)])
x2 = integerPro(c, [copy(A);A2], [copy(b);-ceil(x_b)])
if x1==nothing;return x2
elseif x2==nothing;return x1
elseif sum(c*x1) > sum(c*x2);return x1
else;return x2
end
end
end
c = [1 1 2]
A = [7 2 3;5 4 7;2 3 5]
b = [26;42;28]
integerPro(c,A,b)
x_val