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
4 changes: 2 additions & 2 deletions cpp/src/dual_simplex/bounds_strengthening.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ bool bounds_strengthening_t<i_t, f_t>::bounds_strengthening(
bool is_infeasible =
check_infeasibility<i_t, f_t>(min_a, max_a, cnst_lb, cnst_ub, settings.primal_tol);
if (is_infeasible) {
settings.log.printf(
settings.log.debug(
"Iter:: %d, Infeasible constraint %d, cnst_lb %e, cnst_ub %e, min_a %e, max_a %e\n",
iter,
i,
Expand Down Expand Up @@ -211,7 +211,7 @@ bool bounds_strengthening_t<i_t, f_t>::bounds_strengthening(
new_ub = std::min(new_ub, upper_bounds[k]);

if (new_lb > new_ub + 1e-6) {
settings.log.printf(
settings.log.debug(
"Iter:: %d, Infeasible variable after update %d, %e > %e\n", iter, k, new_lb, new_ub);
return false;
}
Expand Down
204 changes: 90 additions & 114 deletions cpp/src/dual_simplex/branch_and_bound.cpp

Large diffs are not rendered by default.

71 changes: 37 additions & 34 deletions cpp/src/dual_simplex/branch_and_bound.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

#pragma once

#include <dual_simplex/diving_queue.hpp>
#include <dual_simplex/initial_basis.hpp>
#include <dual_simplex/mip_node.hpp>
#include <dual_simplex/node_queue.hpp>
#include <dual_simplex/phase2.hpp>
#include <dual_simplex/pseudo_costs.hpp>
#include <dual_simplex/simplex_solver_settings.hpp>
Expand All @@ -20,7 +20,6 @@
#include <utilities/omp_helpers.hpp>

#include <omp.h>
#include <queue>
#include <vector>

namespace cuopt::linear_programming::dual_simplex {
Expand Down Expand Up @@ -68,12 +67,22 @@ class bounds_strengthening_t;
template <typename i_t, typename f_t>
void upper_bound_callback(f_t upper_bound);

template <typename i_t, typename f_t>
struct bnb_stats_t {
f_t start_time = 0.0;
omp_atomic_t<f_t> total_lp_solve_time = 0.0;
omp_atomic_t<i_t> nodes_explored = 0;
omp_atomic_t<i_t> nodes_unexplored = 0;
omp_atomic_t<f_t> total_lp_iters = 0;

// This should only be used by the main thread
omp_atomic_t<f_t> last_log = 0.0;
omp_atomic_t<i_t> nodes_since_last_log = 0;
};

template <typename i_t, typename f_t>
class branch_and_bound_t {
public:
template <typename T>
using mip_node_heap_t = std::priority_queue<T, std::vector<T>, node_compare_t<i_t, f_t>>;

branch_and_bound_t(const user_problem_t<i_t, f_t>& user_problem,
const simplex_solver_settings_t<i_t, f_t>& solver_settings);

Expand Down Expand Up @@ -111,7 +120,6 @@ class branch_and_bound_t {

f_t get_upper_bound();
f_t get_lower_bound();
i_t get_heap_size();
bool enable_concurrent_lp_root_solve() const { return enable_concurrent_lp_root_solve_; }
std::atomic<int>* get_root_concurrent_halt() { return &root_concurrent_halt_; }
void set_root_concurrent_halt(int value) { root_concurrent_halt_ = value; }
Expand Down Expand Up @@ -145,17 +153,7 @@ class branch_and_bound_t {
mip_solution_t<i_t, f_t> incumbent_;

// Structure with the general info of the solver.
struct stats_t {
f_t start_time = 0.0;
omp_atomic_t<f_t> total_lp_solve_time = 0.0;
omp_atomic_t<i_t> nodes_explored = 0;
omp_atomic_t<i_t> nodes_unexplored = 0;
omp_atomic_t<f_t> total_lp_iters = 0;

// This should only be used by the main thread
omp_atomic_t<f_t> last_log = 0.0;
omp_atomic_t<i_t> nodes_since_last_log = 0;
} exploration_stats_;
bnb_stats_t<i_t, f_t> exploration_stats_;

// Mutex for repair
omp_mutex_t mutex_repair_;
Expand All @@ -175,21 +173,15 @@ class branch_and_bound_t {
// Pseudocosts
pseudo_costs_t<i_t, f_t> pc_;

// Heap storing the nodes to be explored.
omp_mutex_t mutex_heap_;
mip_node_heap_t<mip_node_t<i_t, f_t>*> heap_;
// Heap storing the nodes waiting to be explored.
node_queue_t<i_t, f_t> node_queue;

// Search tree
search_tree_t<i_t, f_t> search_tree_;

// Count the number of subtrees that are currently being explored.
omp_atomic_t<i_t> active_subtrees_;

// Queue for storing the promising node for performing dives.
omp_mutex_t mutex_dive_queue_;
diving_queue_t<i_t, f_t> diving_queue_;
i_t min_diving_queue_size_;

// Global status of the solver.
omp_atomic_t<mip_exploration_status_t> solver_status_;

Expand Down Expand Up @@ -219,22 +211,32 @@ class branch_and_bound_t {
const csr_matrix_t<i_t, f_t>& Arow,
i_t initial_heap_size);

// Explore the search tree using the best-first search with plunging strategy.
void explore_subtree(i_t task_id,
mip_node_t<i_t, f_t>* start_node,
search_tree_t<i_t, f_t>& search_tree,
lp_problem_t<i_t, f_t>& leaf_problem,
bounds_strengthening_t<i_t, f_t>& node_presolver,
basis_update_mpf_t<i_t, f_t>& basis_update,
std::vector<i_t>& basic_list,
std::vector<i_t>& nonbasic_list);
// Perform a plunge in the subtree determined by the `start_node`.
void plunge_from(i_t task_id,
mip_node_t<i_t, f_t>* start_node,
search_tree_t<i_t, f_t>& search_tree,
lp_problem_t<i_t, f_t>& leaf_problem,
bounds_strengthening_t<i_t, f_t>& node_presolver,
basis_update_mpf_t<i_t, f_t>& basis_update,
std::vector<i_t>& basic_list,
std::vector<i_t>& nonbasic_list);

// Each "main" thread pops a node from the global heap and then performs a plunge
// (i.e., a shallow dive) into the subtree determined by the node.
void best_first_thread(i_t task_id,
search_tree_t<i_t, f_t>& search_tree,
const csr_matrix_t<i_t, f_t>& Arow);

// Perform a deep dive in the subtree determined by the `start_node`.
void dive_from(mip_node_t<i_t, f_t>& start_node,
const std::vector<f_t>& start_lower,
const std::vector<f_t>& start_upper,
lp_problem_t<i_t, f_t>& leaf_problem,
bounds_strengthening_t<i_t, f_t>& node_presolver,
basis_update_mpf_t<i_t, f_t>& basis_update,
std::vector<i_t>& basic_list,
std::vector<i_t>& nonbasic_list,
thread_type_t diving_type);
// Each diving thread pops the first node from the dive queue and then performs
// a deep dive into the subtree determined by the node.
void diving_thread(const csr_matrix_t<i_t, f_t>& Arow);
Expand All @@ -251,6 +253,7 @@ class branch_and_bound_t {
bool recompute_basis_and_bounds,
const std::vector<f_t>& root_lower,
const std::vector<f_t>& root_upper,
bnb_stats_t<i_t, f_t>& stats,
logger_t& log);

// Sort the children based on the Martin's criteria.
Expand Down
73 changes: 0 additions & 73 deletions cpp/src/dual_simplex/diving_queue.hpp

This file was deleted.

33 changes: 11 additions & 22 deletions cpp/src/dual_simplex/mip_node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class mip_node_t {
branch_var_lower(-std::numeric_limits<f_t>::infinity()),
branch_var_upper(std::numeric_limits<f_t>::infinity()),
fractional_val(std::numeric_limits<f_t>::infinity()),
objective_estimate(std::numeric_limits<f_t>::infinity()),
vstatus(0)
{
children[0] = nullptr;
Expand All @@ -59,6 +60,7 @@ class mip_node_t {
node_id(0),
branch_var(-1),
branch_dir(rounding_direction_t::NONE),
objective_estimate(std::numeric_limits<f_t>::infinity()),
vstatus(basis)
{
children[0] = nullptr;
Expand All @@ -80,6 +82,7 @@ class mip_node_t {
branch_var(branch_variable),
branch_dir(branch_direction),
fractional_val(branch_var_value),
objective_estimate(parent_node->objective_estimate),
vstatus(basis)

{
Expand Down Expand Up @@ -227,17 +230,19 @@ class mip_node_t {
mip_node_t<i_t, f_t> detach_copy() const
{
mip_node_t<i_t, f_t> copy(lower_bound, vstatus);
copy.branch_var = branch_var;
copy.branch_dir = branch_dir;
copy.branch_var_lower = branch_var_lower;
copy.branch_var_upper = branch_var_upper;
copy.fractional_val = fractional_val;
copy.node_id = node_id;
copy.branch_var = branch_var;
copy.branch_dir = branch_dir;
copy.branch_var_lower = branch_var_lower;
copy.branch_var_upper = branch_var_upper;
copy.fractional_val = fractional_val;
copy.objective_estimate = objective_estimate;
copy.node_id = node_id;
return copy;
}

node_status_t status;
f_t lower_bound;
f_t objective_estimate;
i_t depth;
i_t node_id;
i_t branch_var;
Expand All @@ -262,22 +267,6 @@ void remove_fathomed_nodes(std::vector<mip_node_t<i_t, f_t>*>& stack)
}
}

template <typename i_t, typename f_t>
class node_compare_t {
public:
bool operator()(const mip_node_t<i_t, f_t>& a, const mip_node_t<i_t, f_t>& b) const
{
return a.lower_bound >
b.lower_bound; // True if a comes before b, elements that come before are output last
}

bool operator()(const mip_node_t<i_t, f_t>* a, const mip_node_t<i_t, f_t>* b) const
{
return a->lower_bound >
b->lower_bound; // True if a comes before b, elements that come before are output last
}
};

template <typename i_t, typename f_t>
class search_tree_t {
public:
Expand Down
Loading