Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## Unreleased and breaking
- Removed NamedTupleTools add node directly

## Unreleased
- Store all solutions

Expand Down
2 changes: 0 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ version = "0.1.1"

[deps]
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
NamedTupleTools = "d9ec5142-1e00-5aa0-9d6a-321866360f50"

[compat]
DataStructures = "0.18"
NamedTupleTools = "0.13, 0.14"
julia = "1.6"

[extras]
Expand Down
7 changes: 6 additions & 1 deletion src/Bonobo.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
module Bonobo

using DataStructures
using NamedTupleTools

"""
AbstractNode
Expand Down Expand Up @@ -37,6 +36,8 @@ mutable struct BnBNodeInfo
ub :: Float64
end

BnBNodeInfo() = BnBNodeInfo(-1, NaN, NaN)

"""
DefaultNode <: AbstractNode

Expand All @@ -47,6 +48,10 @@ mutable struct DefaultNode <: AbstractNode
std :: BnBNodeInfo
end

function (::Type{AN})(args...) where {AN <: AbstractNode}
AN(BnBNodeInfo(), args...)
end

"""
DefaultSolution{Node<:AbstractNode,Value} <: AbstractSolution{Node, Value}

Expand Down
25 changes: 12 additions & 13 deletions src/node.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,38 +25,37 @@ Bonobo.set_root!(tree, (
))
```
"""
function set_root!(tree::BnBTree, node_info::NamedTuple)
add_node!(tree, nothing, node_info)
function set_root!(tree::BnBTree, node::AbstractNode)
add_node!(tree, nothing, node)
end

"""
add_node!(tree::BnBTree{Node}, parent::Union{AbstractNode, Nothing}, node_info::NamedTuple)
add_node!(tree::BnBTree{Node}, parent::Union{Node, Nothing}, node::Node) where Node <: AbstractNode

Add a new node to the tree using the `node_info`. For information on that see [`set_root!`](@ref).
Add a new node to the tree using the `node`. For information on that see [`set_root!`](@ref).
"""
function add_node!(tree::BnBTree{Node}, parent::Union{AbstractNode, Nothing}, node_info::NamedTuple) where Node <: AbstractNode
function add_node!(tree::BnBTree{Node}, parent::Union{Node, Nothing}, node::Node) where Node <: AbstractNode
node_id = tree.num_nodes + 1
node = create_node(Node, node_id, parent, node_info)
node = create_node(Node, node_id, parent, node)
tree.nodes[node_id] = node
tree.node_queue[node_id] = (node.lb, node_id)
tree.num_nodes += 1
end

"""
create_node(Node, node_id::Int, parent::Union{AbstractNode, Nothing}, node_info::NamedTuple)
create_node(Node, node_id::Int, parent::Union{AbstractNode, Nothing}, node::AbstractNode)

Creates a node of type `Node` with id `node_id` and the named tuple `node_info`.
Creates a node of type `Node` with id `node_id` and the named tuple `node`.
For information on that see [`set_root!`](@ref).
"""
function create_node(Node, node_id::Int, parent::Union{AbstractNode, Nothing}, node_info::NamedTuple)
function create_node(Node, node_id::Int, parent::Union{AbstractNode, Nothing}, node::AbstractNode)
Comment on lines +48 to +51

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is strange here, we have a function create node that already takes as input the created node?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that's the reason why I don't like this approach same with the mutable but I wasn't able to come up with something better which is most likely the reason why I used the named tuple approach 🤣
I wanted to avoid a node and an inner node as the user should have access to both but I also don't want to pass both around all the time. I could make a parametric type which includes both info and then one can dispatch on the inner later but accessing the variables of the inner then is a a bit tedious. Or one would need to create a get property and set property function to make it simpler....
Did you have a completely different approach in mind?

lb = -Inf
if !isnothing(parent)
lb = parent.lb
end
bnb_node = structfromnt(BnBNodeInfo, (id = node_id, lb = lb, ub = Inf))
bnb_nt = (std = bnb_node,)
node_nt = merge(bnb_nt, node_info)
return structfromnt(Node, node_nt)
bnb_node = BnBNodeInfo(node_id, lb, Inf)
node.std = bnb_node

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the default here assumes the node is mutable?

return node
end

"""
Expand Down
7 changes: 2 additions & 5 deletions test/end2end/dummy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ function BB.get_relaxed_values(::BnBTree{BB.DefaultNode, DummyRoot}, node::BB.De
end

function BB.get_branching_nodes_info(tree::BnBTree{BB.DefaultNode, DummyRoot}, node::BB.DefaultNode, vidx::Int)
node_info = NamedTuple[]
push!(node_info, NamedTuple())
push!(node_info, NamedTuple())
return node_info
return [BB.DefaultNode(), BB.DefaultNode()]
end

function dummy_callback(tree, node; node_infeasible=false, worse_than_incumbent=false)
Expand All @@ -38,7 +35,7 @@ end
sense = :Min
)

BB.set_root!(bnb_model, NamedTuple())
BB.set_root!(bnb_model, BB.DefaultNode())

BB.optimize!(bnb_model; callback=dummy_callback)

Expand Down
36 changes: 18 additions & 18 deletions test/end2end/mip.jl
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ end

function BB.get_branching_nodes_info(tree::BnBTree{MIPNode, JuMP.Model}, node::MIPNode, vidx::Int)
m = tree.root
node_info = NamedTuple[]
branches = MIPNode[]

var = VariableRef(m, MOI.VariableIndex(vidx))

Expand All @@ -69,21 +69,21 @@ function BB.get_branching_nodes_info(tree::BnBTree{MIPNode, JuMP.Model}, node::M
# left child set upper bound
ubs[vidx] = floor(Int, val)

push!(node_info, (
lbs = copy(node.lbs),
ubs = ubs,
status = MOI.OPTIMIZE_NOT_CALLED,
push!(branches, MIPNode(
copy(node.lbs),
ubs,
MOI.OPTIMIZE_NOT_CALLED,
))

# right child set lower bound
lbs[vidx] = ceil(Int, val)

push!(node_info, (
lbs = lbs,
ubs = copy(node.ubs),
status = MOI.OPTIMIZE_NOT_CALLED,
push!(branches, MIPNode(
lbs,
copy(node.ubs),
MOI.OPTIMIZE_NOT_CALLED,
))
return node_info
return branches
end

@testset "MIP Problem with 3 variables" begin
Expand All @@ -101,10 +101,10 @@ end
root = m,
sense = objective_sense(m) == MOI.MAX_SENSE ? :Max : :Min
)
BB.set_root!(bnb_model, (
lbs = zeros(length(x)),
ubs = fill(Inf, length(x)),
status = MOI.OPTIMIZE_NOT_CALLED
BB.set_root!(bnb_model, MIPNode(
zeros(length(x)),
fill(Inf, length(x)),
MOI.OPTIMIZE_NOT_CALLED
))

BB.optimize!(bnb_model)
Expand All @@ -130,10 +130,10 @@ end
root = m,
sense = objective_sense(m) == MOI.MAX_SENSE ? :Max : :Min
)
BB.set_root!(bnb_model, (
lbs = zeros(length(x)),
ubs = fill(Inf, length(x)),
status = MOI.OPTIMIZE_NOT_CALLED
BB.set_root!(bnb_model, MIPNode(
zeros(length(x)),
fill(Inf, length(x)),
MOI.OPTIMIZE_NOT_CALLED
))

BB.optimize!(bnb_model)
Expand Down
4 changes: 2 additions & 2 deletions test/unit/add_node.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ struct TestRoot end
root = TestRoot(),
sense = :Min
)
BB.set_root!(bnb_model, NamedTuple())
BB.set_root!(bnb_model, BB.DefaultNode())
root = BB.get_next_node(bnb_model, BB.BFS())
lb, ub = BB.evaluate_node!(bnb_model, root)
BB.set_node_bound!(bnb_model.sense, root, lb, ub)

# adding a new node with the root as parent
BB.add_node!(bnb_model, root, NamedTuple())
BB.add_node!(bnb_model, root, BB.DefaultNode())
last_node_id = bnb_model.num_nodes
@test bnb_model.nodes[last_node_id].lb == 0.0
end