Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
141 commits
Select commit Hold shift + click to select a range
c9081a6
implemented diving heuristics. sorted starting nodes for diving based…
nguidotti Dec 3, 2025
046a501
moved diving heuristics to a separated file
nguidotti Dec 3, 2025
6ea6d72
organized code. added toggle to disable each type of diving.
nguidotti Dec 3, 2025
5422b97
restrict calling RINS to the best-first threads
nguidotti Dec 4, 2025
73c1a63
fix invalid branch var in line search diving
nguidotti Dec 4, 2025
3a77cca
moved asserts
nguidotti Dec 9, 2025
0f7af4e
replace inf and max with STL calls
nguidotti Dec 9, 2025
79368c3
Fix incorrect infeasible list
chris-maes Dec 12, 2025
6334ad7
implemented diving heuristics. sorted starting nodes for diving based…
nguidotti Dec 3, 2025
2c94a7c
moved diving heuristics to a separated file
nguidotti Dec 3, 2025
0e815e1
organized code. added toggle to disable each type of diving.
nguidotti Dec 3, 2025
29a2a33
moved asserts
nguidotti Dec 9, 2025
5a3ef60
unified global node heap. fathom node in the diving node that was alr…
nguidotti Dec 4, 2025
c181ccf
refactoring code
nguidotti Dec 12, 2025
501c20d
fix style
nguidotti Dec 12, 2025
0ee757a
small fixes
nguidotti Dec 12, 2025
546b116
unified the best-first and diving heap into a single object. imposed …
nguidotti Dec 15, 2025
06d531a
adjusted column spacing in bnb logs. added opening mode for logger.
nguidotti Dec 15, 2025
ae742c2
revert fixes for dual simplex. changed RINS and SubMIP to use guided …
nguidotti Dec 15, 2025
b5f2c7e
moved bound propagation logs to debug mode
nguidotti Dec 15, 2025
eb5c695
addressing code rabbit suggestions
nguidotti Dec 15, 2025
5cf5ac0
added explicit conversion to float
nguidotti Dec 15, 2025
d7dfb0d
missing code revert in basis update
nguidotti Dec 15, 2025
55e64cc
fixed variable type
nguidotti Dec 15, 2025
a26a816
Merge remote-tracking branch 'origin/main' into node-queue
nguidotti Dec 15, 2025
17d3d7c
Merge remote-tracking branch 'origin/main' into diving-heuristics
nguidotti Dec 16, 2025
0b1e994
added comments
nguidotti Dec 16, 2025
9effdc8
added missing spacing
nguidotti Dec 16, 2025
6d43e03
updated logs
nguidotti Dec 16, 2025
98f670f
Merge branch 'main' into adjust-bnb-logs
nguidotti Dec 18, 2025
d54ecbd
Merge branch 'main' into node-queue
nguidotti Dec 18, 2025
0aa344e
Merge branch 'main' into diving-heuristics
nguidotti Dec 18, 2025
fbb9966
refactoring
nguidotti Dec 18, 2025
7a5284e
Merge branch 'adjust-bnb-logs' into diving-heuristics
nguidotti Dec 18, 2025
78f38a4
adjust header spacing
nguidotti Dec 19, 2025
668da14
Merge branch 'adjust-bnb-logs' into diving-heuristics
nguidotti Dec 19, 2025
dd8955f
fix compilation error
nguidotti Dec 19, 2025
9f07cbb
Merge branch 'main' into diving-heuristics
nguidotti Dec 19, 2025
cb1208f
Merge branch 'main' into diving-heuristics
nguidotti Jan 6, 2026
ed20d95
Merge branch 'main' into node-queue
nguidotti Jan 6, 2026
426b445
added cli option for disabling each diving heuristic
nguidotti Jan 6, 2026
319bd22
fix style
nguidotti Jan 6, 2026
3e52ffe
fix infeasible list (#694)
nguidotti Jan 6, 2026
1178493
Merge branch 'main' into diving-heuristics
nguidotti Jan 7, 2026
972b187
created a struct with all persistent data used by each worker
nguidotti Dec 15, 2025
d076da2
replace hashmap with a vector
nguidotti Dec 16, 2025
d8e3541
fix missing initialization
nguidotti Dec 16, 2025
4796733
added a setting for each type of task. changed how to set the number …
nguidotti Dec 17, 2025
308237e
first version of the new parallel b&b
nguidotti Dec 19, 2025
a0fa4e1
refactoring and fixing bugs
nguidotti Jan 7, 2026
25b0bed
several bug fixes
nguidotti Jan 7, 2026
25dac02
handle master suspension. added overdecomposition.
nguidotti Jan 7, 2026
85eab64
fix incorrect number of workers
nguidotti Jan 7, 2026
227d7f8
removed ramp-up phase
nguidotti Jan 7, 2026
5aecd63
added some comments
nguidotti Jan 7, 2026
8dd2d08
fix incorrect termination status
nguidotti Jan 8, 2026
1dcee03
replace upper bound lock with atomic
nguidotti Jan 8, 2026
9e2e5c7
improve idling master thread
nguidotti Jan 8, 2026
34f7eaa
added ramp-up-phase
nguidotti Jan 8, 2026
769a3d8
refactoring
nguidotti Jan 8, 2026
c54033c
updating code to match the new parallel bnb
nguidotti Jan 8, 2026
28c61b8
Merge branch 'main' into diving-heuristics
nguidotti Jan 8, 2026
4bcf801
removed command line options
nguidotti Jan 8, 2026
d91369d
fix style
nguidotti Jan 8, 2026
4ee57f9
fix compilation failure
nguidotti Jan 9, 2026
b99a9c7
separated objective estimate and variable selection
nguidotti Jan 9, 2026
43f8b31
separating objective estimate from variable selection
nguidotti Jan 9, 2026
a36bf03
added log
nguidotti Jan 9, 2026
d4c9d54
Merge branch 'node-queue' into diving-heuristics
nguidotti Jan 9, 2026
b9a14bf
Merge branch 'diving-heuristics' into parallel-bnb-v2
nguidotti Jan 9, 2026
7c5c996
small refactor
nguidotti Jan 9, 2026
5753de8
code cleanup
nguidotti Jan 9, 2026
421cbfd
fix reporting frequency
nguidotti Jan 9, 2026
6faeed0
fix style
nguidotti Jan 9, 2026
d7046e3
added missing stl headers. fix incorrect round-robin.
nguidotti Jan 9, 2026
14441d1
refactor to eliminate enum
nguidotti Jan 12, 2026
89cc6de
fix race condition in guided diving
nguidotti Jan 12, 2026
525f013
reliability branching from #599
nguidotti Jan 9, 2026
0fa76f1
modfiied reliability branching to reuse basis from node
nguidotti Jan 12, 2026
0926349
replaced mutex with a vector of mutexes
nguidotti Jan 12, 2026
2c069c0
restrict reliability branching to main thread
nguidotti Jan 12, 2026
f043ac9
fixed unintialized pseudocost. added adaptive rule for the number of …
nguidotti Jan 13, 2026
24a3838
re-enable reliability branching
nguidotti Jan 13, 2026
ccca7fe
setting reliable_threshold to 1
nguidotti Jan 13, 2026
5f58f6d
parallelized the trial branching
nguidotti Jan 20, 2026
fbc17c9
added debug log
nguidotti Jan 20, 2026
a1eb6b8
solved early termination in CMS750_4. fixed hard coded number of thre…
nguidotti Jan 20, 2026
8116fea
Merge branch 'main' into fix-bugs
nguidotti Jan 20, 2026
115a0b1
silenced logs from the concurrent mode when running inside MIP. ignor…
nguidotti Jan 21, 2026
d50c064
Merge branch 'main' into fix-bugs
nguidotti Jan 21, 2026
27d0d39
Merge branch 'fix-bugs' into reliability-branching
nguidotti Jan 21, 2026
c47adda
fixed merge errors
nguidotti Jan 21, 2026
c0422ed
fixed crash
nguidotti Jan 21, 2026
a0a1d93
better num thread initialization
nguidotti Jan 21, 2026
9f0fe29
fix compilation
nguidotti Jan 21, 2026
0dcb5ff
Merge branch 'fix-bugs' into reliability-branching
nguidotti Jan 21, 2026
298c68c
moved parameters to simplex_settings. added command line option
nguidotti Jan 21, 2026
8a890fd
handle cli arguments
nguidotti Jan 21, 2026
2c2c515
set additional openmp flags
nguidotti Jan 21, 2026
e593d36
set the number of tasks for strong branching.
nguidotti Jan 21, 2026
aa15d8e
added additional information in the logs when solving the root relaxa…
nguidotti Jan 22, 2026
ce0586c
Merge branch 'fix-bugs' into reliability-branching
nguidotti Jan 22, 2026
d604cb6
renamed macro
nguidotti Jan 22, 2026
781dd36
Merge branch 'fix-bugs' into reliability-branching
nguidotti Jan 22, 2026
628c22b
changed the number of threads in probing cache
nguidotti Jan 22, 2026
6956bbc
fix type
nguidotti Jan 22, 2026
6bdd587
changed the logs for the root relaxation
nguidotti Jan 23, 2026
6d7007c
Merge branch 'fix-bugs' into reliability-branching
nguidotti Jan 23, 2026
fc1c60a
limited the number of candidates for strong branching. refactoring to…
nguidotti Jan 23, 2026
444b95b
removed try_lock
nguidotti Jan 23, 2026
90dcdc9
removed unused settings
nguidotti Jan 23, 2026
5260b51
adjusted number of workers for rb
nguidotti Jan 23, 2026
87098e3
adjusting number of workers for rb
nguidotti Jan 24, 2026
b66ebae
fix incorrect max tasks
nguidotti Jan 24, 2026
84d0567
removed ramp-up phase
nguidotti Jan 25, 2026
1fdd13e
fix root relaxation message when the solution is not optimal
nguidotti Jan 26, 2026
6b1bee8
Merge branch 'fix-bugs' into reliability-branching
nguidotti Jan 26, 2026
66f6cfd
increase max_lookahead
nguidotti Jan 26, 2026
e46eba6
Merge branch 'release/26.02' into reliability-branching
nguidotti Jan 26, 2026
31b5285
set the reliable threshold dynamically
nguidotti Jan 26, 2026
7bac62d
fixed incorrect threshold formula. fixed time limit violation.
nguidotti Jan 27, 2026
a6e055c
simplified parallel loop
nguidotti Jan 27, 2026
de4389b
added single-threaded mode for rins and submip
nguidotti Jan 27, 2026
eb51080
added missing mutexes
nguidotti Jan 27, 2026
f3567cb
fixed empty vector in shuffle
nguidotti Jan 27, 2026
233933f
reverted some code changes
nguidotti Jan 27, 2026
527754c
replaced with lock_guards
nguidotti Jan 27, 2026
2251b87
fixed crash
nguidotti Jan 27, 2026
7919288
fixed number of threads set to 0
nguidotti Jan 28, 2026
cec6f38
enable reliablity branching by default
nguidotti Jan 28, 2026
2fdbe27
changed solver to use a single parallel section for the entire duration.
nguidotti Jan 28, 2026
87e4be2
converted RINS to use openmp task
nguidotti Jan 28, 2026
eee6848
migrated CPU FJ to OpenMP
nguidotti Jan 28, 2026
3699fd6
fix compilation
nguidotti Jan 29, 2026
ee0d49f
fix incorrect execution for single thread
nguidotti Jan 29, 2026
e8b5109
fixed missing barrier at the end of the scheduler
nguidotti Feb 2, 2026
e8f8148
replaced locks with atomics
nguidotti Feb 2, 2026
c9a27a7
replaced std::thread with openmp task for the concurrent root solve
nguidotti Feb 2, 2026
9731c76
fixed incorrectly declaring the root relaxation to be optimal after t…
nguidotti Feb 3, 2026
62f604f
small fixes
nguidotti Feb 3, 2026
a8fd737
fix pseudocost update
nguidotti Feb 3, 2026
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
25 changes: 19 additions & 6 deletions benchmarks/linear_programming/cuopt/run_mip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ int run_single_file(std::string file_path,
int num_cpu_threads,
bool write_log_file,
bool log_to_console,
bool reliability_branching,
double time_limit)
{
const raft::handle_t handle_{};
Expand Down Expand Up @@ -197,13 +198,16 @@ int run_single_file(std::string file_path,
}
}

CUOPT_LOG_INFO("Reliability branching: %d\n", reliability_branching);

settings.time_limit = time_limit;
settings.heuristics_only = heuristics_only;
settings.num_cpu_threads = num_cpu_threads;
settings.log_to_console = log_to_console;
settings.tolerances.relative_tolerance = 1e-12;
settings.tolerances.absolute_tolerance = 1e-6;
settings.presolve = true;
settings.reliability_branching = reliability_branching;
cuopt::linear_programming::benchmark_info_t benchmark_info;
settings.benchmark_info_ptr = &benchmark_info;
auto start_run_solver = std::chrono::high_resolution_clock::now();
Expand Down Expand Up @@ -256,6 +260,7 @@ void run_single_file_mp(std::string file_path,
int num_cpu_threads,
bool write_log_file,
bool log_to_console,
bool reliability_branching,
double time_limit)
{
std::cout << "running file " << file_path << " on gpu : " << device << std::endl;
Expand All @@ -271,6 +276,7 @@ void run_single_file_mp(std::string file_path,
num_cpu_threads,
write_log_file,
log_to_console,
reliability_branching,
time_limit);
// this is a bad design to communicate the result but better than adding complexity of IPC or
// pipes
Expand Down Expand Up @@ -354,6 +360,10 @@ int main(int argc, char* argv[])
.help("track allocations (t/f)")
.default_value(std::string("f"));

program.add_argument("--reliability-branching")
.help("enable reliability branching (t/f)")
.default_value(std::string("t"));

// Parse arguments
try {
program.parse_args(argc, argv);
Expand All @@ -376,12 +386,13 @@ int main(int argc, char* argv[])
std::string result_file;
int batch_num = -1;

bool heuristics_only = program.get<std::string>("--heuristics-only")[0] == 't';
int num_cpu_threads = program.get<int>("--num-cpu-threads");
bool write_log_file = program.get<std::string>("--write-log-file")[0] == 't';
bool log_to_console = program.get<std::string>("--log-to-console")[0] == 't';
double memory_limit = program.get<double>("--memory-limit");
bool track_allocations = program.get<std::string>("--track-allocations")[0] == 't';
bool heuristics_only = program.get<std::string>("--heuristics-only")[0] == 't';
int num_cpu_threads = program.get<int>("--num-cpu-threads");
bool write_log_file = program.get<std::string>("--write-log-file")[0] == 't';
bool log_to_console = program.get<std::string>("--log-to-console")[0] == 't';
double memory_limit = program.get<double>("--memory-limit");
bool track_allocations = program.get<std::string>("--track-allocations")[0] == 't';
bool reliability_branching = program.get<std::string>("--reliability-branching")[0] == 't';

if (num_cpu_threads < 0) { num_cpu_threads = omp_get_max_threads() / n_gpus; }

Expand Down Expand Up @@ -469,6 +480,7 @@ int main(int argc, char* argv[])
num_cpu_threads,
write_log_file,
log_to_console,
reliability_branching,
time_limit);
} else if (sys_pid < 0) {
std::cerr << "Fork failed!" << std::endl;
Expand Down Expand Up @@ -509,6 +521,7 @@ int main(int argc, char* argv[])
num_cpu_threads,
write_log_file,
log_to_console,
reliability_branching,
time_limit);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* clang-format off */
/*
* SPDX-FileCopyrightText: Copyright (c) 2023-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2023-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
/* clang-format on */
Expand Down Expand Up @@ -83,6 +83,9 @@ class mip_solver_settings_t {
i_t num_cpu_threads = -1; // -1 means use default number of threads in branch and bound
i_t num_gpus = 1;
bool log_to_console = true;

bool reliability_branching = true;

std::string log_file;
std::string sol_file;
std::string user_problem_file;
Expand Down
1 change: 0 additions & 1 deletion cpp/src/dual_simplex/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ set(DUAL_SIMPLEX_SRC_FILES
${CMAKE_CURRENT_SOURCE_DIR}/crossover.cpp
${CMAKE_CURRENT_SOURCE_DIR}/folding.cpp
${CMAKE_CURRENT_SOURCE_DIR}/initial_basis.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mip_node.cpp
${CMAKE_CURRENT_SOURCE_DIR}/phase1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/phase2.cpp
${CMAKE_CURRENT_SOURCE_DIR}/presolve.cpp
Expand Down
3 changes: 3 additions & 0 deletions cpp/src/dual_simplex/basis_updates.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ class basis_update_mpf_t {
reset_stats();
}

basis_update_mpf_t(const basis_update_mpf_t& other) = default;
basis_update_mpf_t& operator=(const basis_update_mpf_t& other) = default;

void print_stats() const
{
i_t total_L_transpose_calls = total_sparse_L_transpose_ + total_dense_L_transpose_;
Expand Down
274 changes: 274 additions & 0 deletions cpp/src/dual_simplex/bnb_worker.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
/* clang-format off */
/*
* SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
/* clang-format on */

#pragma once

#include <dual_simplex/basis_updates.hpp>
#include <dual_simplex/bounds_strengthening.hpp>
#include <dual_simplex/mip_node.hpp>
#include <dual_simplex/phase2.hpp>

#include <utilities/pcg.hpp>

#include <array>
#include <deque>
#include <mutex>
#include <vector>

namespace cuopt::linear_programming::dual_simplex {

constexpr int bnb_num_worker_types = 5;

// Indicate the search and variable selection algorithms used by each thread
// in B&B (See [1]).
//
// [1] T. Achterberg, “Constraint Integer Programming,” PhD, Technischen Universität Berlin,
// Berlin, 2007. doi: 10.14279/depositonce-1634.
enum bnb_worker_type_t : int {
BEST_FIRST = 0, // Best-First + Plunging.
PSEUDOCOST_DIVING = 1, // Pseudocost diving (9.2.5)
LINE_SEARCH_DIVING = 2, // Line search diving (9.2.4)
GUIDED_DIVING = 3, // Guided diving (9.2.3).
COEFFICIENT_DIVING = 4 // Coefficient diving (9.2.1)
};

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<int64_t> nodes_explored = 0;
omp_atomic_t<int64_t> nodes_unexplored = 0;
omp_atomic_t<int64_t> total_lp_iters = 0;
omp_atomic_t<i_t> nodes_since_last_log = 0;
omp_atomic_t<f_t> last_log = 0.0;
};

template <typename i_t, typename f_t>
class bnb_worker_data_t {
public:
const i_t worker_id;
omp_atomic_t<bnb_worker_type_t> worker_type;
omp_atomic_t<bool> is_active;
omp_atomic_t<f_t> lower_bound;

lp_problem_t<i_t, f_t> leaf_problem;
lp_solution_t<i_t, f_t> leaf_solution;
std::vector<f_t> leaf_edge_norms;

basis_update_mpf_t<i_t, f_t> basis_factors;
std::vector<i_t> basic_list;
std::vector<i_t> nonbasic_list;

bounds_strengthening_t<i_t, f_t> node_presolver;
std::vector<bool> bounds_changed;

std::vector<f_t> start_lower;
std::vector<f_t> start_upper;
mip_node_t<i_t, f_t>* start_node;

PCG rng;

bool recompute_basis = true;
bool recompute_bounds = true;

bnb_worker_data_t(i_t worker_id,
const lp_problem_t<i_t, f_t>& original_lp,
const csr_matrix_t<i_t, f_t>& Arow,
const std::vector<variable_type_t>& var_type,
const simplex_solver_settings_t<i_t, f_t>& settings)
: worker_id(worker_id),
worker_type(BEST_FIRST),
is_active(false),
lower_bound(-std::numeric_limits<f_t>::infinity()),
leaf_problem(original_lp),
leaf_solution(original_lp.num_rows, original_lp.num_cols),
basis_factors(original_lp.num_rows, settings.refactor_frequency),
basic_list(original_lp.num_rows),
nonbasic_list(),
node_presolver(leaf_problem, Arow, {}, var_type),
bounds_changed(original_lp.num_cols, false),
rng(PCG::default_seed ^ worker_id, PCG::default_stream + worker_id)
{
}

// Set the `start_node` for best-first search.
void init_best_first(mip_node_t<i_t, f_t>* node, const lp_problem_t<i_t, f_t>& original_lp)
{
start_node = node;
start_lower = original_lp.lower;
start_upper = original_lp.upper;
worker_type = BEST_FIRST;
lower_bound = node->lower_bound;
is_active = true;
}

// Initialize the worker for diving, setting the `start_node`, `start_lower` and
// `start_upper`. Returns `true` if the starting node is feasible via
// bounds propagation.
bool init_diving(mip_node_t<i_t, f_t>* node,
bnb_worker_type_t type,
const lp_problem_t<i_t, f_t>& original_lp,
const simplex_solver_settings_t<i_t, f_t>& settings)
{
internal_node = node->detach_copy();
start_node = &internal_node;

start_lower = original_lp.lower;
start_upper = original_lp.upper;
worker_type = type;
lower_bound = node->lower_bound;
is_active = true;

std::fill(bounds_changed.begin(), bounds_changed.end(), false);
node->get_variable_bounds(start_lower, start_upper, bounds_changed);

return node_presolver.bounds_strengthening(start_lower, start_upper, bounds_changed, settings);
}

// Set the variables bounds for the LP relaxation of the current node.
bool set_lp_variable_bounds_for(mip_node_t<i_t, f_t>* node_ptr,
const simplex_solver_settings_t<i_t, f_t>& settings)
{
// Reset the bound_changed markers
std::fill(bounds_changed.begin(), bounds_changed.end(), false);

// Set the correct bounds for the leaf problem
if (recompute_bounds) {
leaf_problem.lower = start_lower;
leaf_problem.upper = start_upper;
node_ptr->get_variable_bounds(leaf_problem.lower, leaf_problem.upper, bounds_changed);

} else {
node_ptr->update_branched_variable_bounds(
leaf_problem.lower, leaf_problem.upper, bounds_changed);
}

return node_presolver.bounds_strengthening(
leaf_problem.lower, leaf_problem.upper, bounds_changed, settings);
}

private:
// For diving, we need to store the full node instead of
// of just a pointer, since it is not store in the tree anymore.
// To keep the same interface across all worker types,
// this will be used as a temporary storage and
// will be pointed by `start_node`.
// For exploration, this will not be used.
mip_node_t<i_t, f_t> internal_node;
};

template <typename i_t, typename f_t>
class bnb_worker_pool_t {
public:
void init(i_t num_workers,
const lp_problem_t<i_t, f_t>& original_lp,
const csr_matrix_t<i_t, f_t>& Arow,
const std::vector<variable_type_t>& var_type,
const simplex_solver_settings_t<i_t, f_t>& settings)
{
workers_.resize(num_workers);
num_idle_workers_ = num_workers;
for (i_t i = 0; i < num_workers; ++i) {
workers_[i] =
std::make_unique<bnb_worker_data_t<i_t, f_t>>(i, original_lp, Arow, var_type, settings);
idle_workers_.push_front(i);
}
}

// Here, we are assuming that the master is the only
// thread that can retrieve/pop an idle worker.
bnb_worker_data_t<i_t, f_t>* get_idle_worker()
{
std::lock_guard<omp_mutex_t> lock(mutex_);
if (idle_workers_.empty()) {
return nullptr;
} else {
i_t idx = idle_workers_.front();
return workers_[idx].get();
}
}

// Here, we are assuming that the master is the only
// thread that can retrieve/pop an idle worker.
void pop_idle_worker()
{
std::lock_guard<omp_mutex_t> lock(mutex_);
if (!idle_workers_.empty()) {
idle_workers_.pop_front();
num_idle_workers_--;
}
}

void return_worker_to_pool(bnb_worker_data_t<i_t, f_t>* worker)
{
worker->is_active = false;
std::lock_guard<omp_mutex_t> lock(mutex_);
idle_workers_.push_back(worker->worker_id);
num_idle_workers_++;
}

f_t get_lower_bounds()
{
f_t lower_bound = std::numeric_limits<f_t>::infinity();

for (i_t i = 0; i < workers_.size(); ++i) {
if (workers_[i]->worker_type == BEST_FIRST && workers_[i]->is_active) {
lower_bound = std::min(workers_[i]->lower_bound.load(), lower_bound);
}
}

return lower_bound;
}

i_t num_idle_workers() { return num_idle_workers_; }

private:
// Worker pool
std::vector<std::unique_ptr<bnb_worker_data_t<i_t, f_t>>> workers_;

omp_mutex_t mutex_;
std::deque<i_t> idle_workers_;
omp_atomic_t<i_t> num_idle_workers_;
};

template <typename f_t, typename i_t>
std::vector<bnb_worker_type_t> bnb_get_worker_types(diving_heuristics_settings_t<i_t, f_t> settings)
{
std::vector<bnb_worker_type_t> types;
types.reserve(bnb_num_worker_types);
types.push_back(BEST_FIRST);
if (settings.pseudocost_diving != 0) { types.push_back(PSEUDOCOST_DIVING); }
if (settings.line_search_diving != 0) { types.push_back(LINE_SEARCH_DIVING); }
if (settings.guided_diving != 0) { types.push_back(GUIDED_DIVING); }
if (settings.coefficient_diving != 0) { types.push_back(COEFFICIENT_DIVING); }
return types;
}

template <typename i_t>
std::array<i_t, bnb_num_worker_types> bnb_get_max_workers(
i_t num_workers, std::vector<bnb_worker_type_t> worker_types)
{
std::array<i_t, bnb_num_worker_types> max_num_workers;
max_num_workers.fill(0);

i_t bfs_workers = std::max(worker_types.size() == 1 ? num_workers : num_workers / 4, 1);
max_num_workers[BEST_FIRST] = bfs_workers;

i_t diving_workers = (num_workers - bfs_workers);
i_t m = worker_types.size() - 1;

for (size_t i = 1, k = 0; i < worker_types.size(); ++i) {
i_t start = (double)k * diving_workers / m;
i_t end = (double)(k + 1) * diving_workers / m;
max_num_workers[worker_types[i]] = end - start;
++k;
}

return max_num_workers;
}

} // namespace cuopt::linear_programming::dual_simplex
Loading