From 7f370cfef9c33d139dce9873c8fca0c163e390d0 Mon Sep 17 00:00:00 2001 From: Kibaek Kim Date: Fri, 14 Aug 2020 15:28:35 -0500 Subject: [PATCH 1/4] resolved #10 --- src/impl-JuMP.jl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/impl-JuMP.jl b/src/impl-JuMP.jl index 3ebb949..55d9c0e 100644 --- a/src/impl-JuMP.jl +++ b/src/impl-JuMP.jl @@ -50,6 +50,13 @@ create_child_node(current_node::JuMPNode{T}, variable::JuMP.VariableRef, lb::Rea create_child_node_with_lb(current_node::JuMPNode{T}, variable::JuMP.VariableRef, lb::Real) where T<:AbstractBranch = create_child_node(current_node, VariableBranch(Dict(variable=>lb), empty_variable_bound())) create_child_node_with_ub(current_node::JuMPNode{T}, variable::JuMP.VariableRef, ub::Real) where T<:AbstractBranch = create_child_node(current_node, VariableBranch(empty_variable_bound(), Dict(variable=>ub))) +function processed!(tree::AbstractTree, node::JuMPNode) + # Rollback the branch objects + adjust_branch!(node.auxiliary_data["bounds_changed"]) + + Base.push!(tree.processed, node) +end + # basic bounding function function bound!(node::JuMPNode) JuMP.optimize!(node.model) @@ -69,9 +76,6 @@ function bound!(node::JuMPNode) @warn "Unexpected node solution status: $(node.solution_status)" node.bound = -Inf end - - # Rollback the branch objects - adjust_branch!(node.auxiliary_data["bounds_changed"]) end function apply_changes!(node::JuMPNode) From a3104bc4ef8493cbae8e6d6c34f591d63e240ed3 Mon Sep 17 00:00:00 2001 From: Kibaek Kim Date: Fri, 14 Aug 2020 16:01:55 -0500 Subject: [PATCH 2/4] fixed type error --- src/tree.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tree.jl b/src/tree.jl index 426f58d..098eca8 100644 --- a/src/tree.jl +++ b/src/tree.jl @@ -36,7 +36,7 @@ function push!(tree::AbstractTree, node::AbstractNode) end # add a set of nodes to tree -function push!(tree::AbstractTree, nodes::Vector{AbstractNode}) +function push!(tree::AbstractTree, nodes::Vector{T}) where T<:AbstractNode for node in nodes push!(tree, node) end From 53c668dfe95ac670459a50e3944379d47f636938 Mon Sep 17 00:00:00 2001 From: Kibaek Kim Date: Fri, 14 Aug 2020 16:02:04 -0500 Subject: [PATCH 3/4] refactored --- src/node.jl | 19 ------------------- src/tree.jl | 4 ++-- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/src/node.jl b/src/node.jl index 71b9424..4cb62da 100644 --- a/src/node.jl +++ b/src/node.jl @@ -1,4 +1,3 @@ - abstract type AbstractNode end abstract type AbstractBranch end @@ -17,24 +16,6 @@ macro abstract_node_fields() end) end -# mutable struct AbstractNode{T<:AbstractBranch} -# @abstract_node_fields - -# function AbstractNode( -# id = -1, -# parent = nothing, -# depth = 0, -# branch = nothing, -# solution_status = MOI.OPTIMIZE_NOT_CALLED, -# bound = -Inf, -# solution = Dict{Any,Real}()) -# return new{T}(id, parent, depth, branch, solution_status, bound, solution) -# end -# end - -# return node solution -node_solution(node::AbstractNode) = node.solution - # empty branching function branch(node::AbstractNode)::Vector{AbstractNode} = [] diff --git a/src/tree.jl b/src/tree.jl index 098eca8..96d5dc1 100644 --- a/src/tree.jl +++ b/src/tree.jl @@ -3,8 +3,8 @@ mutable struct AbstractTree node_counter::Int nodes::Vector{AbstractNode} processed::Vector{AbstractNode} - best_bound::Real # e.g., lower bound in minimizing MILP - best_incumbent::Real # e.g., upper bound in minimizing MILP + best_bound::Real # e.g., lower bound for minimization + best_incumbent::Real # e.g., upper bound for minimization function AbstractTree(node_counter::Int = 0) return new(node_counter, [], [], -Inf, Inf) From b3266bb1753044b673810ca27eb0f0cbaff2a50e Mon Sep 17 00:00:00 2001 From: Kibaek Kim Date: Fri, 14 Aug 2020 16:02:11 -0500 Subject: [PATCH 4/4] improved test --- test/unittest.jl | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/test/unittest.jl b/test/unittest.jl index 2205560..98ec58a 100644 --- a/test/unittest.jl +++ b/test/unittest.jl @@ -6,6 +6,15 @@ using MathOptInterface const BB = BranchAndBound const MOI = MathOptInterface +@testset "Abstract Node" begin + struct MyNode <: BB.AbstractNode end + node = MyNode() + @test BB.branch(node) == [] + BB.bound!(node) + BB.heuristics!(node) + BB.apply_changes!(node) +end + model = Model(GLPK.Optimizer) @variable(model, 0 <= x <= 1) @objective(model, Min, x) @@ -59,18 +68,22 @@ end @testset "Marked root node as processed" begin BB.processed!(tree, current_node) - @test isempty(tree.nodes) + @test BB.termination(tree) @test length(tree.processed) == 1 @test tree.processed[1] == current_node end +@testset "Empty branching" begin + BB.branch!(tree, current_node) + @test tree.node_counter == 1 + @test length(tree.nodes) == 0 + @test length(tree.processed) == 1 +end + @testset "Branching at root" begin child1 = BB.create_child_node_with_lb(current_node, x, 0.5) child2 = BB.create_child_node_with_ub(current_node, x, 0.5) - - BB.push!(tree, child1) - BB.push!(tree, child2) - + BB.push!(tree, [child1,child2]) @test tree.node_counter == 3 @test length(tree.nodes) == 2 @test length(tree.processed) == 1