Julia系列13:使用B&B包求解MIP问题

1. 算法示例

调用步骤入下:

  1. 声明线性规划模型,比如Model(GLPK.Optimizer)
  2. 声明tree:tree = BB.initialize_tree(m);
  3. 实现branch函数:function BB.branch!(tree::BB.AbstractTree, node::BB.AbstractNode)。 这里用到node.bound,tree.best_incumbent,node.solution_status,node.solution等变量。
  4. 实现终止函数:function BB.termination(tree::BB.AbstractTree)

参考代码:

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

2. 不使用包的对照版

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

你可能感兴趣的:(Julia系列,julia,开发语言)