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
20 changes: 18 additions & 2 deletions cpp/src/branch_and_bound/branch_and_bound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1124,7 +1124,7 @@ struct nondeterministic_policy_t : tree_update_policy_t<i_t, f_t> {
void on_numerical_issue(mip_node_t<i_t, f_t>* node) override
{
if (worker->search_strategy == search_strategy_t::BEST_FIRST) {
fetch_min(bnb.lower_bound_numerical_, node->lower_bound);
bnb.lower_bound_numerical_.fetch_min(node->lower_bound);
log.printf("LP returned numerical issue on node %d. Best bound set to %+10.6e.\n",
node->node_id,
compute_user_objective(bnb.original_lp_, bnb.lower_bound_numerical_.load()));
Expand Down Expand Up @@ -1722,6 +1722,7 @@ void branch_and_bound_t<i_t, f_t>::plunge_with(bfs_worker_t<i_t, f_t>* worker,
// relaxation
// - The lower bound of the parent is lower or equal to its children
worker->lower_bound = node_ptr->lower_bound;
exploration_stats_.max_node_depth.fetch_max(node_ptr->depth);

if (node_ptr->lower_bound > upper_bound_.load()) {
search_tree_.graphviz_node(settings_.log, node_ptr, "cutoff", node_ptr->lower_bound);
Expand Down Expand Up @@ -1772,6 +1773,19 @@ void branch_and_bound_t<i_t, f_t>::plunge_with(bfs_worker_t<i_t, f_t>* worker,
break;
}

i_t max_node_depth = exploration_stats_.max_node_depth;
i_t plunge_depth = node_ptr->depth - start_node->depth;

if (plunge_depth >= settings_.bnb_min_plunge_depth * max_node_depth) {
f_t max_bound = lower_bound + settings_.bnb_plunge_gap_factor * (upper_bound - lower_bound);
if (node_ptr->lower_bound >= max_bound ||
plunge_depth >= settings_.bnb_max_plunge_depth * max_node_depth) {
stack.push_front(node_ptr);
--exploration_stats_.nodes_being_solved;
break;
}
}

decompress_vstatus(
node_ptr->packed_vstatus, worker->leaf_problem.num_cols, worker->leaf_vstatus);
assert(worker->leaf_vstatus.size() == worker->leaf_problem.num_cols);
Expand Down Expand Up @@ -3457,6 +3471,7 @@ mip_status_t branch_and_bound_t<i_t, f_t>::solve(mip_solution_t<i_t, f_t>& solut
root_lp_current_lower_bound_ = -inf;
exploration_stats_.nodes_unexplored = 0;
exploration_stats_.nodes_explored = 0;
exploration_stats_.max_node_depth = 0;
original_lp_.A.to_compressed_row(Arow_);

settings_.log.debug("Reduced cost strengthening enabled: %d\n",
Expand Down Expand Up @@ -3887,6 +3902,7 @@ mip_status_t branch_and_bound_t<i_t, f_t>::solve(mip_solution_t<i_t, f_t>& solut

exploration_stats_.nodes_explored = 0;
exploration_stats_.nodes_unexplored = 2;
exploration_stats_.max_node_depth = 0;
exploration_stats_.nodes_since_last_log = 0;
exploration_stats_.last_log = tic();
min_node_queue_size_ = 20;
Expand Down Expand Up @@ -4803,7 +4819,7 @@ void branch_and_bound_t<i_t, f_t>::deterministic_sort_replay_events(
deterministic_merge_pseudo_cost_updates(*deterministic_workers_);

for (const auto& worker : *deterministic_workers_) {
fetch_min(lower_bound_numerical_, worker.local_lower_bound_ceiling);
lower_bound_numerical_.fetch_min(worker.local_lower_bound_ceiling);
}
}

Expand Down
1 change: 1 addition & 0 deletions cpp/src/branch_and_bound/worker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct branch_and_bound_stats_t {
omp_atomic_t<int64_t> nodes_unexplored = 0;
// Tracks the number of nodes being solved by the workers at a given time
omp_atomic_t<i_t> nodes_being_solved = 0;
omp_atomic_t<i_t> max_node_depth = 0;

omp_atomic_t<int64_t> total_simplex_iters = 0;
omp_atomic_t<i_t> nodes_since_last_log = 0;
Expand Down
6 changes: 6 additions & 0 deletions cpp/src/dual_simplex/simplex_solver_settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ struct simplex_solver_settings_t {
bnb_steal_chance(-1),
bnb_nodes_per_steal(-1),
bnb_max_steal_attempts(-1),
bnb_plunge_gap_factor(0.25),
bnb_min_plunge_depth(0.1),
bnb_max_plunge_depth(0.5),
reliability_branching(-1),
inside_mip(0),
inside_submip(0),
Expand Down Expand Up @@ -222,6 +225,9 @@ struct simplex_solver_settings_t {
f_t bnb_steal_chance;
i_t bnb_nodes_per_steal;
i_t bnb_max_steal_attempts;
f_t bnb_plunge_gap_factor;
f_t bnb_min_plunge_depth;
f_t bnb_max_plunge_depth;

// Settings for the reliability branching.
// - -1: automatic
Expand Down
45 changes: 19 additions & 26 deletions cpp/src/utilities/omp_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,38 +214,31 @@ class omp_atomic_t {
T& underlying() { return val; }
T underlying() const { return val; }

private:
T val;

friend double fetch_min(omp_atomic_t<double>& atomic_var, double other);
friend double fetch_max(omp_atomic_t<double>& atomic_var, double other);
};

// Free non-template functions are necessary because of a clang 20 bug
// when omp atomic compare is used within a templated context.
// see https://github.com/llvm/llvm-project/issues/127466
inline double fetch_min(omp_atomic_t<double>& atomic_var, double other)
{
double old;
#pragma omp atomic compare capture
T fetch_min(T other)
{
old = atomic_var.val;
if (other < atomic_var.val) { atomic_var.val = other; }
T old;
#pragma omp atomic compare capture
{
old = val;
if (other < val) { val = other; }
}
return old;
}
return old;
}

inline double fetch_max(omp_atomic_t<double>& atomic_var, double other)
{
double old;
#pragma omp atomic compare capture
T fetch_max(T other)
{
old = atomic_var.val;
if (other > atomic_var.val) { atomic_var.val = other; }
T old;
#pragma omp atomic compare capture
{
old = val;
if (other > val) { val = other; }
}
return old;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
return old;
}

private:
T val;
};
} // namespace cuopt

#endif