Skip to content
Merged
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
42 changes: 26 additions & 16 deletions cpp/src/dual_simplex/branch_and_bound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -780,17 +780,15 @@ void branch_and_bound_t<i_t, f_t>::exploration_ramp_up(mip_node_t<i_t, f_t>* nod
// to repair the heuristic solution.
repair_heuristic_solutions();

f_t lower_bound = node->lower_bound;
f_t upper_bound = get_upper_bound();
f_t rel_gap = user_relative_gap(original_lp_, upper_bound, lower_bound);
f_t abs_gap = upper_bound - lower_bound;
i_t nodes_explored = (++exploration_stats_.nodes_explored);
i_t nodes_unexplored = (--exploration_stats_.nodes_unexplored);
exploration_stats_.nodes_since_last_log++;
f_t lower_bound = node->lower_bound;
f_t upper_bound = get_upper_bound();
f_t rel_gap = user_relative_gap(original_lp_, upper_bound, lower_bound);
f_t abs_gap = upper_bound - lower_bound;

if (lower_bound > upper_bound || rel_gap < settings_.relative_mip_gap_tol) {
search_tree->graphviz_node(settings_.log, node, "cutoff", node->lower_bound);
search_tree->update(node, node_status_t::FATHOMED);
--exploration_stats_.nodes_unexplored;
return;
}

Expand All @@ -802,15 +800,14 @@ void branch_and_bound_t<i_t, f_t>::exploration_ramp_up(mip_node_t<i_t, f_t>* nod
abs_gap < 10 * settings_.absolute_mip_gap_tol) &&
(time_since_last_log >= 1)) ||
(time_since_last_log > 30) || now > settings_.time_limit) {
// Check if no new node was explored until now. If this is the case,
// only the last thread should report the progress
if (exploration_stats_.nodes_explored.load() == nodes_explored) {
exploration_stats_.nodes_since_last_log = 0;
exploration_stats_.last_log = tic();
bool should_report = should_report_.exchange(false);
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to have member variable to decide if we should log? I think this is increasing the complexity of the code for little return.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since this piece of code is running by multiple threads, the atomic here prevent multiple reports from happening (potentially out-of-order). But I agree that it is an imperfect solution. I will probably change when the ramp-up phase is reworked or the report is moved to a separated thread.


if (should_report) {
f_t obj = compute_user_objective(original_lp_, upper_bound);
f_t user_lower = compute_user_objective(original_lp_, root_objective_);
std::string gap_user = user_mip_gap<f_t>(obj, user_lower);
i_t nodes_explored = exploration_stats_.nodes_explored;
i_t nodes_unexplored = exploration_stats_.nodes_unexplored;

settings_.log.printf(
" %10d %10lu %+13.6e %+10.6e %6d %7.1e %s %9.2f\n",
Expand All @@ -822,6 +819,10 @@ void branch_and_bound_t<i_t, f_t>::exploration_ramp_up(mip_node_t<i_t, f_t>* nod
nodes_explored > 0 ? exploration_stats_.total_lp_iters / nodes_explored : 0,
gap_user.c_str(),
now);

exploration_stats_.nodes_since_last_log = 0;
exploration_stats_.last_log = tic();
should_report_ = true;
}
}

Expand Down Expand Up @@ -853,6 +854,10 @@ void branch_and_bound_t<i_t, f_t>::exploration_ramp_up(mip_node_t<i_t, f_t>* nod
original_lp_.upper,
settings_.log);

++exploration_stats_.nodes_since_last_log;
++exploration_stats_.nodes_explored;
--exploration_stats_.nodes_unexplored;

if (status == node_solve_info_t::TIME_LIMIT) {
solver_status_ = mip_exploration_status_t::TIME_LIMIT;
return;
Expand Down Expand Up @@ -911,14 +916,11 @@ void branch_and_bound_t<i_t, f_t>::explore_subtree(i_t task_id,
// - The lower bound of the parent is lower or equal to its children
assert(task_id < local_lower_bounds_.size());
local_lower_bounds_[task_id] = lower_bound;
i_t nodes_explored = (++exploration_stats_.nodes_explored);
i_t nodes_unexplored = (--exploration_stats_.nodes_unexplored);
exploration_stats_.nodes_since_last_log++;

if (lower_bound > upper_bound || rel_gap < settings_.relative_mip_gap_tol) {
search_tree.graphviz_node(settings_.log, node_ptr, "cutoff", node_ptr->lower_bound);
search_tree.update(node_ptr, node_status_t::FATHOMED);
recompute_bounds_and_basis = true;
--exploration_stats_.nodes_unexplored;
continue;
}

Expand All @@ -935,6 +937,9 @@ void branch_and_bound_t<i_t, f_t>::explore_subtree(i_t task_id,
f_t obj = compute_user_objective(original_lp_, upper_bound);
f_t user_lower = compute_user_objective(original_lp_, get_lower_bound());
std::string gap_user = user_mip_gap<f_t>(obj, user_lower);
i_t nodes_explored = exploration_stats_.nodes_explored;
i_t nodes_unexplored = exploration_stats_.nodes_unexplored;

settings_.log.printf(
" %10d %10lu %+13.6e %+10.6e %6d %7.1e %s %9.2f\n",
nodes_explored,
Expand Down Expand Up @@ -974,6 +979,10 @@ void branch_and_bound_t<i_t, f_t>::explore_subtree(i_t task_id,

recompute_bounds_and_basis = !has_children(status);

++exploration_stats_.nodes_since_last_log;
++exploration_stats_.nodes_explored;
--exploration_stats_.nodes_unexplored;

if (status == node_solve_info_t::TIME_LIMIT) {
solver_status_ = mip_exploration_status_t::TIME_LIMIT;
return;
Expand Down Expand Up @@ -1356,6 +1365,7 @@ mip_status_t branch_and_bound_t<i_t, f_t>::solve(mip_solution_t<i_t, f_t>& solut
min_diving_queue_size_ = 4 * settings_.num_diving_threads;
solver_status_ = mip_exploration_status_t::RUNNING;
lower_bound_ceiling_ = inf;
should_report_ = true;

#pragma omp parallel num_threads(settings_.num_threads)
{
Expand Down
2 changes: 2 additions & 0 deletions cpp/src/dual_simplex/branch_and_bound.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ class branch_and_bound_t {
// Global status of the solver.
omp_atomic_t<mip_exploration_status_t> solver_status_;

omp_atomic_t<bool> should_report_;

// In case, a best-first thread encounters a numerical issue when solving a node,
// its blocks the progression of the lower bound.
omp_atomic_t<f_t> lower_bound_ceiling_;
Expand Down