diff --git a/src/Algorithm/branching/branchinggroup.jl b/src/Algorithm/branching/branchinggroup.jl index 1754ee979..613a02a7e 100644 --- a/src/Algorithm/branching/branchinggroup.jl +++ b/src/Algorithm/branching/branchinggroup.jl @@ -37,7 +37,7 @@ mutable struct BranchingGroup candidate::AbstractBranchingCandidate # the left-hand side in general. local_id::Int64 lhs::Float64 - children::Vector{Node} + children::Vector{SbNode} isconquered::Bool score::Float64 end @@ -45,7 +45,7 @@ end function BranchingGroup( candidate::AbstractBranchingCandidate, local_id::Int64, lhs::Float64 ) - return BranchingGroup(candidate, local_id, lhs, Node[], false, typemin(Float64)) + return BranchingGroup(candidate, local_id, lhs, SbNode[], false, typemin(Float64)) end get_lhs_distance_to_integer(group::BranchingGroup) = @@ -61,9 +61,9 @@ end # TODO : it does not look like a regeneration but more like a new vector where we # reassign children function regenerate_children!(group::BranchingGroup, parent::Node) - new_children = Node[] + new_children = SbNode[] for child in group.children - push!(new_children, Node(parent, child)) + push!(new_children, SbNode(parent, child)) end group.children = new_children return diff --git a/src/Algorithm/branching/varbranching.jl b/src/Algorithm/branching/varbranching.jl index 8eff8434a..e2f7d30b0 100644 --- a/src/Algorithm/branching/varbranching.jl +++ b/src/Algorithm/branching/varbranching.jl @@ -46,7 +46,7 @@ function generate_children( ) end child1description = candidate.varname * ">=" * string(ceil(lhs)) - child1 = Node(master, parent, child1description, store_records!(reform)) + child1 = SbNode(master, parent, child1description, store_records!(reform)) # adding the second branching constraints restore_from_records!(units_to_restore, copy_records(parent.recordids)) @@ -61,7 +61,7 @@ function generate_children( ) end child2description = candidate.varname * "<=" * string(floor(lhs)) - child2 = Node(master, parent, child2description, store_records!(reform)) + child2 = SbNode(master, parent, child2description, store_records!(reform)) return [child1, child2] end diff --git a/src/Algorithm/conquer.jl b/src/Algorithm/conquer.jl index 442345d3b..7417a067d 100644 --- a/src/Algorithm/conquer.jl +++ b/src/Algorithm/conquer.jl @@ -65,6 +65,30 @@ function apply_conquer_alg_to_node!( return end +# This is only for strong branching +# returns the optimization part of the output of the conquer algorithm +function apply_conquer_alg_to_node!( + node::SbNode, algo::AbstractConquerAlgorithm, env::Env, reform::Reformulation, + units_to_restore::UnitsUsage, opt_rtol::Float64 = Coluna.DEF_OPTIMALITY_RTOL, + opt_atol::Float64 = Coluna.DEF_OPTIMALITY_ATOL +) + nodestate = getoptstate(node) + if isverbose(algo) + @logmsg LogLevel(-1) string("Node IP DB: ", get_ip_dual_bound(nodestate)) + @logmsg LogLevel(-1) string("Tree IP PB: ", get_ip_primal_bound(nodestate)) + end + if ip_gap_closed(nodestate, rtol = opt_rtol, atol = opt_atol) + @info "IP Gap is closed: $(ip_gap(nodestate)). Abort treatment." + else + isverbose(algo) && @logmsg LogLevel(-1) string("IP Gap is positive. Need to treat node.") + + run!(algo, env, reform, ConquerInput(Node(node), units_to_restore)) + store_records!(reform, node.recordids) + end + node.conquerwasrun = true + return +end + #################################################################### # ParameterisedHeuristic #################################################################### diff --git a/src/Algorithm/divide.jl b/src/Algorithm/divide.jl index 9c2a10ece..5e6ee56be 100644 --- a/src/Algorithm/divide.jl +++ b/src/Algorithm/divide.jl @@ -15,7 +15,7 @@ Output of a divide algorithm used by the tree search algorithm. Should contain the vector of generated nodes. """ struct DivideOutput <: AbstractOutput - children::Vector{Node} + children::Vector{SbNode} optstate::OptimizationState end diff --git a/src/Algorithm/node.jl b/src/Algorithm/node.jl index 3eb9230f5..32a95323e 100644 --- a/src/Algorithm/node.jl +++ b/src/Algorithm/node.jl @@ -35,15 +35,6 @@ function Node( ) end -# this function creates a child node by copying info from another child -# used in strong branching -function Node(parent::Node, child::Node) - depth = getdepth(parent) + 1 - return Node( - -1, false, depth, parent, getoptstate(child), - child.branchdescription, child.recordids, false - ) -end get_tree_order(n::Node) = n.tree_order set_tree_order!(n::Node, tree_order::Int) = n.tree_order = tree_order @@ -64,3 +55,65 @@ function to_be_pruned(node::Node) getterminationstatus(nodestate) == INFEASIBLE && return true return ip_gap_closed(nodestate) end + + +### WIP +### Node for the strong branching (Goal: decouple strong branching from tree search) + +mutable struct SbNode + tree_order::Int + istreated::Bool + depth::Int + parent::Union{Nothing, Node} + optstate::OptimizationState + #branch::Union{Nothing, Branch} # branch::ConstrId + branchdescription::String + recordids::RecordsVector + conquerwasrun::Bool +end + +# this function creates a child node by copying info from another child +# used in strong branching +function SbNode(parent::Node, child::SbNode) + depth = getdepth(parent) + 1 + return SbNode( + -1, false, depth, parent, getoptstate(child), + child.branchdescription, child.recordids, false + ) +end + +function SbNode( + form::AbstractFormulation, parent::Node, branchdescription::String, recordrecordids::RecordsVector +) + depth = getdepth(parent) + 1 + nodestate = OptimizationState(form, getoptstate(parent), false, false) + + return SbNode( + -1, false, depth, parent, nodestate, branchdescription, recordrecordids, false + ) +end + +function Node(node::SbNode) + return Node(node.tree_order, node.istreated, node.depth, node.parent, node.optstate, node.branchdescription, node.recordids, node.conquerwasrun) +end + + +get_tree_order(n::SbNode) = n.tree_order +set_tree_order!(n::SbNode, tree_order::Int) = n.tree_order = tree_order +getdepth(n::SbNode) = n.depth +getparent(n::SbNode) = n.parent +getchildren(n::SbNode) = n.children +getoptstate(n::SbNode) = n.optstate +addchild!(n::SbNode, child::SbNode) = push!(n.children, child) +settreated!(n::SbNode) = n.istreated = true +istreated(n::SbNode) = n.istreated +isrootnode(n::SbNode) = n.tree_order == 1 +getinfeasible(n::SbNode) = n.infesible +setinfeasible(n::SbNode, status::Bool) = n.infeasible = status + +# TODO remove +function to_be_pruned(node::SbNode) + nodestate = getoptstate(node) + getterminationstatus(nodestate) == INFEASIBLE && return true + return ip_gap_closed(nodestate) +end \ No newline at end of file diff --git a/src/Algorithm/treesearch.jl b/src/Algorithm/treesearch.jl index d316e4cf7..0c3eaf863 100644 --- a/src/Algorithm/treesearch.jl +++ b/src/Algorithm/treesearch.jl @@ -292,7 +292,7 @@ function run_divide_algorithm!( end print(" N° ", get_tree_order(child) ," ") end - push!(tsdata, child) + push!(tsdata, Node(child)) end !first_child_with_runconquer && println() return diff --git a/test/runtests.jl b/test/runtests.jl index 6bf090ef5..64b192b4f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -5,4 +5,4 @@ include("ColunaTests.jl") retest(Coluna, ColunaTests) # Run a specific test: -#retest(ColunaTests, "toy instance with objective constant") \ No newline at end of file +#retest(ColunaTests, "small instance") \ No newline at end of file