Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
0fe2abb
Add a binary/int8 fast path to the CPU feasibility jump
aliceb-nv Aug 6, 2026
ac9d47e
Take the tabu test out of the binary fast path's global argmax
aliceb-nv Aug 6, 2026
4f4bcb1
perf(cpufj-bin): drop the per-iteration bitmap clear and hoist apply_…
aliceb-nv Aug 6, 2026
f334465
perf(cpufj-bin): vectorize apply_move's row walk
aliceb-nv Aug 6, 2026
dd1501d
docs: record the Highway third-party licence
aliceb-nv Aug 7, 2026
57e2ef7
bit of cleanup
aliceb-nv Aug 7, 2026
febac7b
cleanup
aliceb-nv Aug 7, 2026
2dc1f79
perf: fold the patch width choice into the Highway target
aliceb-nv Aug 7, 2026
eb4ce75
perf: normalize every row to a'x <= b and drop the per-row sign
aliceb-nv Aug 7, 2026
b0c1924
refactor: replace the row record with a plain weight array
aliceb-nv Aug 7, 2026
2f63ab8
fix: derive the argmax tile from the L1 data cache size
aliceb-nv Aug 7, 2026
9bcb1b7
debug: add CUOPT_NO_BINFJ to force the general path
aliceb-nv Aug 7, 2026
bd9c383
fix: widen the packed staged score to int64
aliceb-nv Aug 7, 2026
c308ce4
add row integralize
aliceb-nv Aug 18, 2026
2f7cf86
fix solve_CPUFJ link
aliceb-nv Aug 19, 2026
5805269
latency tweaks
aliceb-nv Aug 19, 2026
10ddf0e
more logs
aliceb-nv Aug 19, 2026
69ac5a2
ai review
aliceb-nv Aug 19, 2026
64abba9
fix build
aliceb-nv Aug 19, 2026
0c771a3
some optimizing
aliceb-nv Aug 20, 2026
9d46a9f
some bug fixes regarding lift moves
aliceb-nv Aug 20, 2026
996c832
hiverge inspired improvements
aliceb-nv Aug 20, 2026
075ded0
ddfw improvements
aliceb-nv Aug 20, 2026
cdc805b
changes for the hiverge harness
aliceb-nv Aug 20, 2026
25e4479
replace operator overloaded arithmetic with explicit highway function…
aliceb-nv Aug 20, 2026
71d07a6
save user_callbacks in run_mip
aliceb-nv Aug 20, 2026
27bae2f
let B&B publih solutions via the user callbacks as well to reduce lat…
aliceb-nv Aug 20, 2026
8b26bcd
publish cpufj scratch solutions early as well
aliceb-nv Aug 20, 2026
abdad3e
absorb cuda driver startup in run_mip.cpp
aliceb-nv Aug 20, 2026
04a25fa
fix multigpu runs
aliceb-nv Aug 21, 2026
a977cf9
lhs refresh period stretch, lazy mtm cache invalidate, magnitude awar…
aliceb-nv Aug 21, 2026
b4ed104
objective weight tweaks
aliceb-nv Aug 21, 2026
64b5bfd
perf optimization
aliceb-nv Aug 21, 2026
9c94889
more optimization
aliceb-nv Aug 21, 2026
08a858a
weight_escalation_delta
aliceb-nv Aug 21, 2026
ff86b74
infeasible region kicks
aliceb-nv Aug 21, 2026
4ff4650
2opt lift move thing
aliceb-nv Aug 21, 2026
01b44ae
portfolio lane seeding
aliceb-nv Aug 21, 2026
af02f91
early cpu portfolio
aliceb-nv Aug 21, 2026
5293291
lift move handle fractionals
aliceb-nv Aug 22, 2026
a8bb991
vectorized argmax for binary path in feasible region
aliceb-nv Aug 22, 2026
868142c
kahan sum the objective; audit validity in the harness
aliceb-nv Aug 22, 2026
a2ccbc9
Binary perturb re-anchors to the incumbent
aliceb-nv Aug 22, 2026
e02bd00
apply_exact_k_seed
aliceb-nv Aug 22, 2026
0e4453f
more seeds
aliceb-nv Aug 22, 2026
6c8e2ce
bipartite seeding
aliceb-nv Aug 22, 2026
32b6b52
share incumbent in portfolio
aliceb-nv Aug 22, 2026
428575a
perturbation gated on objective stall
aliceb-nv Aug 22, 2026
21f2b89
infeasible pair repair
aliceb-nv Aug 23, 2026
dd70c32
dualsimplex LP seed, 2s
aliceb-nv Aug 23, 2026
e885c11
some optimization work
aliceb-nv Aug 23, 2026
0795c61
some optimization efforts
aliceb-nv Aug 24, 2026
d32d935
bounds prop in CPUFJ
aliceb-nv Aug 24, 2026
98130fc
ddfw scheme
aliceb-nv Aug 24, 2026
e4caa19
encode small domain integers as binary to enable the FJ binary fastpath
aliceb-nv Aug 24, 2026
555848a
feaspump in early cpufj
aliceb-nv Aug 24, 2026
b6f4f43
cpufj batching
aliceb-nv Aug 24, 2026
c28f2ab
fix Werror=unused flags
aliceb-nv Aug 24, 2026
72d7335
match main post rebase
aliceb-nv Aug 25, 2026
67ccc35
run cpufj portfolio before root LP solve
aliceb-nv Aug 25, 2026
7eda27d
many lanes during early heuristics
aliceb-nv Aug 25, 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
444 changes: 444 additions & 0 deletions benchmarks/linear_programming/cuopt/run_cpufj.cu

Large diffs are not rendered by default.

58 changes: 58 additions & 0 deletions benchmarks/linear_programming/cuopt/run_mip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <cuopt/mathematical_optimization/mip/solver_solution.hpp>
#include <cuopt/mathematical_optimization/optimization_problem_interface.hpp>
#include <cuopt/mathematical_optimization/solve.hpp>
#include <cuopt/mathematical_optimization/utilities/internals.hpp>
#include <utilities/logger.hpp>

#include <raft/core/handle.hpp>
Expand Down Expand Up @@ -136,6 +137,52 @@ std::vector<std::vector<double>> read_solution_from_dir(const std::string file_p
return initial_solutions;
}

struct incumbent_record_t {
double objective;
double work_timestamp;
double wall_time;
};

class incumbent_tracker_t : public cuopt::internals::get_solution_callback_t {
public:
explicit incumbent_tracker_t(std::chrono::high_resolution_clock::time_point start_time)
: start_time_(start_time)
{
}

void get_solution(void* /*data*/,
void* cost,
void* /*solution_bound*/,
void* /*user_data*/) override
{
const auto now = std::chrono::high_resolution_clock::now();
records_.push_back({*static_cast<double*>(cost),
0.0,
std::chrono::duration<double>(now - start_time_).count()});
}

void write_csv(const std::string& path) const
{
std::ofstream file(path);
if (!file.is_open()) {
std::cerr << "Error opening incumbent file " << path << std::endl;
return;
}
file << "index,objective,work_timestamp,wall_time_s\n";
for (size_t i = 0; i < records_.size(); ++i) {
file << i << "," << std::setprecision(15) << records_[i].objective << ","
<< records_[i].work_timestamp << "," << std::setprecision(6) << records_[i].wall_time
<< "\n";
}
}

size_t size() const { return records_.size(); }

private:
std::chrono::high_resolution_clock::time_point start_time_;
std::vector<incumbent_record_t> records_;
};

int run_single_file(std::string file_path,
int device,
int batch_id,
Expand All @@ -151,6 +198,8 @@ int run_single_file(std::string file_path,
double work_limit,
bool deterministic)
{
(void)cudaFree(0);

const raft::handle_t handle_{};
cuopt::mathematical_optimization::mip_solver_settings_t<int, double> settings;
std::string base_filename = file_path.substr(file_path.find_last_of("/\\") + 1);
Expand Down Expand Up @@ -218,6 +267,8 @@ int run_single_file(std::string file_path,
cuopt::mathematical_optimization::benchmark_info_t benchmark_info;
settings.benchmark_info_ptr = &benchmark_info;
auto start_run_solver = std::chrono::high_resolution_clock::now();
incumbent_tracker_t incumbent_tracker(start_run_solver);
settings.set_mip_callback(&incumbent_tracker);
auto solution = cuopt::mathematical_optimization::solve_mip(&handle_, mps_data_model, settings);
CUOPT_LOG_INFO(
"first obj: %f last improvement of best feasible: %f last improvement after recombination: %f",
Expand Down Expand Up @@ -291,6 +342,13 @@ int run_single_file(std::string file_path,
<< "\n";
write_to_output_file(out_dir, base_filename, device, n_gpus, batch_id, ss.str());
CUOPT_LOG_INFO("Results written to the file %s", base_filename.c_str());
if (out_dir != "") {
std::string csv_path =
out_dir + "/" + base_filename.substr(0, base_filename.find(".mps")) + "_incumbents.csv";
incumbent_tracker.write_csv(csv_path);
CUOPT_LOG_INFO(
"Incumbent trace (%zu entries) written to %s", incumbent_tracker.size(), csv_path.c_str());
}
return sol_found;
}

Expand Down
60 changes: 59 additions & 1 deletion cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ rapids_cmake_build_type(Release)
option(CMAKE_CUDA_LINEINFO "Enable the -lineinfo option for nvcc useful for cuda-memcheck / profiler" ON)
option(BUILD_TESTS "Configure CMake to build tests" ON)
option(BUILD_LP_ONLY "Build only linear programming components, exclude routing and MIP-specific files" OFF)
option(BUILD_MIP_BENCHMARKS "Build MIP benchmarks" OFF)
option(SKIP_C_PYTHON_ADAPTERS "Skip building C and Python adapter files (cython_solve.cu and cuopt_c.cpp)" OFF)
option(SKIP_ROUTING_BUILD "Skip building routing components" OFF)
option(SKIP_GRPC_BUILD "Skip building gRPC and protobuf components" OFF)
Expand Down Expand Up @@ -307,6 +308,25 @@ set(BUILD_SHARED_LIBS OFF)
FetchContent_MakeAvailable(pslp)
set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_SAVED})

FetchContent_Declare(
highway
GIT_REPOSITORY "https://github.com/google/highway.git"
GIT_TAG "1.4.0"
GIT_PROGRESS TRUE
EXCLUDE_FROM_ALL
SYSTEM
)

set(HWY_ENABLE_CONTRIB OFF CACHE BOOL "" FORCE)
set(HWY_ENABLE_EXAMPLES OFF CACHE BOOL "" FORCE)
set(HWY_ENABLE_TESTS OFF CACHE BOOL "" FORCE)
set(HWY_ENABLE_INSTALL OFF CACHE BOOL "" FORCE)

set(BUILD_SHARED_LIBS_SAVED ${BUILD_SHARED_LIBS})
set(BUILD_SHARED_LIBS OFF)
FetchContent_MakeAvailable(highway)
set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_SAVED})


# dejavu - header-only graph automorphism library for MIP symmetry detection
# https://github.com/markusa4/dejavu (header-only, skip its CMakeLists.txt)
Expand Down Expand Up @@ -666,6 +686,7 @@ target_include_directories(cuopt_objs PRIVATE
target_include_directories(cuopt_objs SYSTEM PRIVATE
"${pslp_SOURCE_DIR}/include"
"${dejavu_SOURCE_DIR}"
"${highway_SOURCE_DIR}"
)

target_include_directories(cuopt_objs
Expand All @@ -691,6 +712,9 @@ target_include_directories(cuopt_objs
target_link_libraries(cuopt_objs PRIVATE $<TARGET_FILE:PSLP>)
add_dependencies(cuopt_objs PSLP)

target_link_libraries(cuopt_objs PRIVATE $<TARGET_FILE:hwy>)
add_dependencies(cuopt_objs hwy)

# Link KaMinPar by file to avoid export dependency tracking (mirrors PSLP above).
# KaMinPar is a from-source static library fully embedded into libcuopt.so; it is never
# installed (INSTALL_KAMINPAR OFF) and consumers of cuopt::cuopt never use it, so it must
Expand Down Expand Up @@ -777,6 +801,9 @@ target_link_libraries(cuopt_objs
# - generate tests --------------------------------------------------------------------------------
if (BUILD_TESTS)
include(CTest)
endif ()

if (BUILD_TESTS OR (BUILD_MIP_BENCHMARKS AND NOT BUILD_LP_ONLY))
add_library(cuopt_static STATIC $<TARGET_OBJECTS:cuopt_objs>)
target_link_libraries(cuopt_static
PUBLIC
Expand Down Expand Up @@ -813,10 +840,15 @@ if (BUILD_TESTS)
)
target_link_libraries(cuopt_static PRIVATE $<TARGET_FILE:PSLP>)
add_dependencies(cuopt_static PSLP)
target_link_libraries(cuopt_static PRIVATE $<TARGET_FILE:hwy>)
add_dependencies(cuopt_static hwy)
target_link_libraries(cuopt_static PRIVATE $<TARGET_FILE:KaMinPar::KaMinPar>)
if (TARGET KaMinPar)
add_dependencies(cuopt_static KaMinPar)
endif ()
endif ()

if (BUILD_TESTS)
add_subdirectory(tests)
endif (BUILD_TESTS)

Expand Down Expand Up @@ -857,6 +889,8 @@ target_link_libraries(cuopt
)
target_link_libraries(cuopt PRIVATE $<TARGET_FILE:PSLP>)
add_dependencies(cuopt PSLP)
target_link_libraries(cuopt PRIVATE $<TARGET_FILE:hwy>)
add_dependencies(cuopt hwy)
target_link_libraries(cuopt PRIVATE $<TARGET_FILE:KaMinPar::KaMinPar>)
if (TARGET KaMinPar)
add_dependencies(cuopt KaMinPar)
Expand Down Expand Up @@ -1031,7 +1065,6 @@ if (NOT BUILD_LP_ONLY)
endif ()


option(BUILD_MIP_BENCHMARKS "Build MIP benchmarks" OFF)
if (BUILD_MIP_BENCHMARKS AND NOT BUILD_LP_ONLY)
add_executable(solve_MIP ../benchmarks/linear_programming/cuopt/run_mip.cpp)
target_include_directories(solve_MIP
Expand Down Expand Up @@ -1065,6 +1098,31 @@ if (BUILD_MIP_BENCHMARKS AND NOT BUILD_LP_ONLY)
"${CMAKE_CURRENT_SOURCE_DIR}/src"
)

# CPU FJ standalone portfolio benchmark
add_executable(solve_CPUFJ ../benchmarks/linear_programming/cuopt/run_cpufj.cu)
set_target_properties(solve_CPUFJ PROPERTIES CXX_SCAN_FOR_MODULES OFF)
target_compile_options(solve_CPUFJ
PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:${CUOPT_CXX_FLAGS}>"
"$<$<COMPILE_LANGUAGE:CUDA>:${CUOPT_CUDA_FLAGS}>"
"$<$<COMPILE_LANGUAGE:CUDA>:-fopenmp>"
)
target_link_libraries(solve_CPUFJ
PUBLIC
cuopt_static
OpenMP::OpenMP_CXX
OpenMP::OpenMP_CUDA
)
target_include_directories(solve_CPUFJ
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/src"
"${papilo_SOURCE_DIR}/src"
"${papilo_BINARY_DIR}"
)
target_include_directories(solve_CPUFJ SYSTEM PRIVATE
"${pslp_SOURCE_DIR}/include"
"${dejavu_SOURCE_DIR}"
)

endif ()

option(BUILD_LP_BENCHMARKS "Build LP benchmarks" OFF)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ class cpu_optimization_problem_t : public optimization_problem_interface_t<i_t,
std::string get_objective_name() const override;
std::string get_problem_name() const override;
problem_category_t get_problem_category() const override;
/**
* @brief Whether any variable type is SEMI_CONTINUOUS.
*
* Cached in set_variable_types() / adopt_from_mps_data_model().
*/
bool has_semi_continuous_variables() const noexcept;
const std::vector<std::string>& get_variable_names() const override;
const std::vector<std::string>& get_row_names() const override;
const std::vector<i_t>& get_quadratic_objective_offsets() const override;
Expand Down Expand Up @@ -208,6 +214,7 @@ class cpu_optimization_problem_t : public optimization_problem_interface_t<i_t,

private:
problem_category_t problem_category_ = problem_category_t::LP;
bool has_semi_continuous_variables_{false};
bool maximize_{false};
i_t n_vars_{0};
i_t n_constraints_{0};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,12 @@ class optimization_problem_t : public optimization_problem_interface_t<i_t, f_t>
std::string get_objective_name() const override;
std::string get_problem_name() const override;
problem_category_t get_problem_category() const override;
/**
* @brief Whether any variable type is SEMI_CONTINUOUS.
*
* Cached in set_variable_types(); used to skip SC reformulation host probes.
*/
bool has_semi_continuous_variables() const noexcept;
const std::vector<std::string>& get_variable_names() const override;
const std::vector<std::string>& get_row_names() const override;
const std::vector<i_t>& get_quadratic_objective_offsets() const override;
Expand Down Expand Up @@ -391,6 +397,7 @@ class optimization_problem_t : public optimization_problem_interface_t<i_t, f_t>
rmm::cuda_stream_view stream_view_;

problem_category_t problem_category_ = problem_category_t::LP;
bool has_semi_continuous_variables_{false};
bool maximize_{false};
i_t n_vars_{0};
i_t n_constraints_{0};
Expand Down
50 changes: 46 additions & 4 deletions cpp/src/branch_and_bound/branch_and_bound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2430,6 +2430,7 @@ void branch_and_bound_t<i_t, f_t>::solve_submip(diving_worker_t<i_t, f_t>* worke
f_t work_limit = 1.0;
submip_fj_cpu_worker.create_worker(submip_bnb.original_lp_,
submip_bnb.var_types_,
submip_bnb.original_problem_.num_cols,
initial_guess,
submip_bnb.settings_,
std::format("{} [CPU FJ]", log_prefix),
Expand Down Expand Up @@ -2891,6 +2892,7 @@ void branch_and_bound_t<i_t, f_t>::recursive_submip(diving_worker_t<i_t, f_t>* w
f_t work_limit = 1.0;
submip_fj_cpu_worker.create_worker(worker->leaf_problem,
var_types,
original_problem_.num_cols,
worker->leaf_solution.x,
settings_,
std::format("{} [CPU FJ]", log_prefix),
Expand Down Expand Up @@ -2963,12 +2965,31 @@ void branch_and_bound_t<i_t, f_t>::launch_root_heuristics(
f_t work_limit = std::numeric_limits<f_t>::infinity();
f_t time_limit = settings_.time_limit - toc(exploration_stats_.start_time);

// Odd passes start from the incumbent, even ones from the relaxation. The size guard covers a
// concurrent pass having grown the LP past the crush the incumbent was last taken through.
std::vector<f_t> fj_seed;
if (cut_pass % 2 == 1) {
mutex_upper_.lock();
if (incumbent_.has_incumbent && incumbent_.x.size() == (size_t)lp.num_cols) {
fj_seed = incumbent_.x;
}
mutex_upper_.unlock();
}
if (fj_seed.empty()) { fj_seed = sol; }

current_heuristic->fj_cpu_worker_.improvement_callback =
[this](f_t obj, const std::vector<f_t>& assignment, double work_units) {
set_solution_from_cpu_fj(obj, assignment, work_units);
};
current_heuristic->fj_cpu_worker_.create_worker(
lp, var_types_, sol, settings_, "[RootCut CPUFJ] ");
current_heuristic->fj_cpu_worker_.create_worker(lp,
var_types_,
original_problem_.num_cols,
fj_seed,
settings_,
"[RootCut CPUFJ " + std::to_string(cut_pass) +
"] ",
/*seed=*/-1,
/*lane=*/cut_pass);
++(*worker_count);

#pragma omp task priority(CUOPT_DEFAULT_TASK_PRIORITY) \
Expand Down Expand Up @@ -3525,6 +3546,29 @@ mip_status_t branch_and_bound_t<i_t, f_t>::solve(mip_solution_t<i_t, f_t>& solut
lp_status_t root_status = lp_status_t::UNSET;
solving_root_relaxation_ = true;

// Started here so the lanes run through the root LP and every cut pass. No relaxation exists
// yet, so they seed from the anchor.
root_heuristics_t<i_t, f_t> root_heuristics(settings_.num_threads - 1);
const i_t n_root_fj_lanes =
std::clamp(settings_.num_threads / 4, 0, CUOPT_MIP_ROOT_CPUFJ_MAX_LANES);
const f_t root_fj_time_limit = settings_.time_limit - toc(exploration_stats_.start_time);
if (!settings_.deterministic && n_root_fj_lanes > 0 && root_fj_time_limit > 0) {
root_heuristics.start_persistent_lanes(
original_lp_,
var_types_,
original_problem_.num_cols,
{},
settings_,
n_root_fj_lanes,
root_fj_time_limit,
(int64_t)settings_.random_seed,
[this](f_t obj, const std::vector<f_t>& assignment, double work_units) {
cuopt_assert(assignment.size() == (size_t)original_problem_.num_cols,
"root CPU FJ lanes must report a slack-free assignment");
set_solution_from_cpu_fj(obj, assignment, work_units);
});
}

f_t root_relax_start_time = tic();

if (!enable_concurrent_lp_root_solve()) {
Expand Down Expand Up @@ -3682,8 +3726,6 @@ mip_status_t branch_and_bound_t<i_t, f_t>::solve(mip_solution_t<i_t, f_t>& solut
compute_user_objective(original_lp_, root_relax_objective);
}

root_heuristics_t<i_t, f_t> root_heuristics(settings_.num_threads - 1);

f_t cut_generation_start_time = tic();
i_t cut_pool_size = 0;
for (i_t cut_pass = 0; cut_pass < settings_.max_cut_passes; cut_pass++) {
Expand Down
2 changes: 2 additions & 0 deletions cpp/src/mip_heuristics/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ set(MIP_NON_LP_FILES
${CMAKE_CURRENT_SOURCE_DIR}/feasibility_jump/feasibility_jump.cu
${CMAKE_CURRENT_SOURCE_DIR}/feasibility_jump/feasibility_jump_kernels.cu
${CMAKE_CURRENT_SOURCE_DIR}/feasibility_jump/fj_cpu.cu
${CMAKE_CURRENT_SOURCE_DIR}/feasibility_jump/fj_cpu_binary.cu
${CMAKE_CURRENT_SOURCE_DIR}/feasibility_jump/fj_cpu_binary_kernels.cpp
${CMAKE_CURRENT_SOURCE_DIR}/feasibility_jump/early_cpufj.cu
${CMAKE_CURRENT_SOURCE_DIR}/feasibility_jump/early_gpufj.cu)

Expand Down
11 changes: 11 additions & 0 deletions cpp/src/mip_heuristics/diversity/diversity_manager.cu
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "cuda_profiler_api.h"
#include "diversity_manager.cuh"

#include <mip_heuristics/feasibility_jump/early_cpufj.cuh>
#include <mip_heuristics/mip_constants.hpp>
#include <mip_heuristics/presolve/third_party_presolve.hpp>

Expand All @@ -22,6 +23,9 @@
#include <utilities/copy_helpers.hpp>
#include <utilities/scope_guard.hpp>

#include <omp.h>

#include <algorithm>
#include <chrono>
#include <cmath>
#include <limits>
Expand Down Expand Up @@ -314,6 +318,13 @@ bool diversity_manager_t<i_t, f_t>::run_presolve(f_t time_limit, timer_t global_

if (run_probing_cache && !global_timer.check_time_limit() && !presolve_timer.check_time_limit()) {
log_presolve_budget("PROBING", probing_features, probing_budget);
// The early CPUFJ lanes hold their threads for the whole of presolve, and probing's default
// task count assumes the whole team. Its pools are sized per task, so this bounds host memory
// as well as concurrency.
const i_t held_by_cpufj =
context.early_cpufj_ptr != nullptr ? (i_t)context.early_cpufj_ptr->lane_count() : 0;
ls.constraint_prop.bounds_update.settings.num_tasks =
std::max(1, omp_get_num_threads() - 1 - held_by_cpufj);
f_t time_for_probing_cache = std::min(time_limit, (f_t)global_timer.remaining_time());
timer_t probing_timer{time_for_probing_cache};
[[maybe_unused]] const auto probing_t0 = std::chrono::steady_clock::now();
Expand Down
Loading