Skip to content

Commit 8057774

Browse files
authored
Merge branch 'main' into setppc-presolve
2 parents 7761da8 + a92fd23 commit 8057774

File tree

66 files changed

+8014
-1593
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+8014
-1593
lines changed

.coderabbit.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
1+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
22
# SPDX-License-Identifier: Apache-2.0
33

44
reviews:
55
profile: chill
6-
high_level_summary: true
6+
high_level_summary: false
77
poem: false
88
auto_review:
99
enabled: true

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ cpp/doxygen/xml
5252
token_cache.json
5353
version_cache.json
5454

55+
# Clang compilation database
56+
compile_commands.json
57+
5558
# Local Server Error Log
5659
error_log.txt
5760

benchmarks/linear_programming/cuopt/benchmark_helper.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
#pragma once
99

10-
#include <cuopt/linear_programming/optimization_problem.hpp>
10+
#include <cuopt/linear_programming/optimization_problem_interface.hpp>
1111
#include <cuopt/linear_programming/pdlp/pdlp_hyper_params.cuh>
1212
#include <cuopt/linear_programming/pdlp/solver_solution.hpp>
1313
#include <cuopt/linear_programming/solve.hpp>

benchmarks/linear_programming/cuopt/run_mip.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include <cstdio>
1111
#include <cuopt/linear_programming/mip/solver_settings.hpp>
1212
#include <cuopt/linear_programming/mip/solver_solution.hpp>
13-
#include <cuopt/linear_programming/optimization_problem.hpp>
13+
#include <cuopt/linear_programming/optimization_problem_interface.hpp>
1414
#include <cuopt/linear_programming/solve.hpp>
1515
#include <mps_parser/parser.hpp>
1616
#include <utilities/logger.hpp>

benchmarks/linear_programming/cuopt/run_pdlp.cu

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66
/* clang-format on */
77

8-
#include <cuopt/linear_programming/optimization_problem.hpp>
8+
#include <cuopt/linear_programming/optimization_problem_interface.hpp>
99
#include <cuopt/linear_programming/pdlp/solver_solution.hpp>
1010
#include <cuopt/linear_programming/solve.hpp>
1111
#include <cuopt/linear_programming/solver_settings.hpp>

ci/run_ctests.sh

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/bin/bash
2-
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
33
# SPDX-License-Identifier: Apache-2.0
44

55
set -euo pipefail
@@ -26,3 +26,11 @@ for gt in "${GTEST_DIR}"/*_TEST; do
2626
echo "Running gtest ${test_name}"
2727
"${gt}" "$@"
2828
done
29+
30+
# Run C_API_TEST with CPU memory for local solves (excluding time limit tests)
31+
if [ -x "${GTEST_DIR}/C_API_TEST" ]; then
32+
echo "Running gtest C_API_TEST with CUOPT_USE_CPU_MEM_FOR_LOCAL"
33+
CUOPT_USE_CPU_MEM_FOR_LOCAL=1 "${GTEST_DIR}/C_API_TEST" --gtest_filter=-c_api/TimeLimitTestFixture.* "$@"
34+
else
35+
echo "Skipping C_API_TEST with CUOPT_USE_CPU_MEM_FOR_LOCAL (binary not found)"
36+
fi

conda/recipes/cuopt/recipe.yaml

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,31 @@ build:
3434
- AWS_ACCESS_KEY_ID
3535
- AWS_SECRET_ACCESS_KEY
3636
- AWS_SESSION_TOKEN
37+
- SCCACHE_DIST_AUTH_TOKEN
3738
env:
3839
CMAKE_C_COMPILER_LAUNCHER: ${{ env.get("CMAKE_C_COMPILER_LAUNCHER") }}
3940
CMAKE_CUDA_COMPILER_LAUNCHER: ${{ env.get("CMAKE_CUDA_COMPILER_LAUNCHER") }}
4041
CMAKE_CXX_COMPILER_LAUNCHER: ${{ env.get("CMAKE_CXX_COMPILER_LAUNCHER") }}
4142
CMAKE_GENERATOR: ${{ env.get("CMAKE_GENERATOR") }}
42-
SCCACHE_BUCKET: ${{ env.get("SCCACHE_BUCKET") }}
43-
SCCACHE_IDLE_TIMEOUT: ${{ env.get("SCCACHE_IDLE_TIMEOUT") }}
44-
SCCACHE_REGION: ${{ env.get("SCCACHE_REGION") }}
45-
SCCACHE_S3_USE_SSL: ${{ env.get("SCCACHE_S3_USE_SSL") }}
46-
SCCACHE_S3_NO_CREDENTIALS: ${{ env.get("SCCACHE_S3_NO_CREDENTIALS") }}
43+
NVCC_APPEND_FLAGS: ${{ env.get("NVCC_APPEND_FLAGS", default="") }}
44+
PARALLEL_LEVEL: ${{ env.get("PARALLEL_LEVEL", default="8") }}
45+
SCCACHE_BUCKET: ${{ env.get("SCCACHE_BUCKET", default="") }}
46+
SCCACHE_DIST_AUTH_TYPE: ${{ env.get("SCCACHE_DIST_AUTH_TYPE", default="token") }}
47+
SCCACHE_DIST_FALLBACK_TO_LOCAL_COMPILE: ${{ env.get("SCCACHE_DIST_FALLBACK_TO_LOCAL_COMPILE", default="false") }}
48+
SCCACHE_DIST_MAX_RETRIES: ${{ env.get("SCCACHE_DIST_MAX_RETRIES", default="inf") }}
49+
SCCACHE_DIST_REQUEST_TIMEOUT: ${{ env.get("SCCACHE_DIST_REQUEST_TIMEOUT", default="7140") }}
50+
SCCACHE_DIST_SCHEDULER_URL: ${{ env.get("SCCACHE_DIST_SCHEDULER_URL", default="") }}
51+
SCCACHE_ERROR_LOG: ${{ env.get("SCCACHE_ERROR_LOG", default="/tmp/sccache.log") }}
52+
SCCACHE_IDLE_TIMEOUT: ${{ env.get("SCCACHE_IDLE_TIMEOUT", default="0") }}
53+
SCCACHE_NO_CACHE: ${{ env.get("SCCACHE_NO_CACHE", default="") }}
54+
SCCACHE_RECACHE: ${{ env.get("SCCACHE_RECACHE", default="") }}
55+
SCCACHE_REGION: ${{ env.get("SCCACHE_REGION", default="") }}
4756
SCCACHE_S3_KEY_PREFIX: cuopt/${{ env.get("RAPIDS_CONDA_ARCH") }}/cuda${{ cuda_major }}
57+
SCCACHE_S3_NO_CREDENTIALS: ${{ env.get("SCCACHE_S3_NO_CREDENTIALS", default="false") }}
58+
SCCACHE_S3_PREPROCESSOR_CACHE_KEY_PREFIX: cuopt/${{ env.get("RAPIDS_CONDA_ARCH") }}/cuda${{ cuda_major }}/conda/preprocessor-cache
59+
SCCACHE_S3_USE_PREPROCESSOR_CACHE_MODE: ${{ env.get("SCCACHE_S3_USE_PREPROCESSOR_CACHE_MODE", default="true") }}
60+
SCCACHE_S3_USE_SSL: ${{ env.get("SCCACHE_S3_USE_SSL", default="true") }}
61+
SCCACHE_SERVER_LOG: ${{ env.get("SCCACHE_SERVER_LOG", default="sccache=debug") }}
4862

4963
requirements:
5064
build:

conda/recipes/libcuopt/recipe.yaml

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,33 @@ cache:
3434
- AWS_ACCESS_KEY_ID
3535
- AWS_SECRET_ACCESS_KEY
3636
- AWS_SESSION_TOKEN
37+
- SCCACHE_DIST_AUTH_TOKEN
3738
env:
3839
# Enable assertions (-a flag) for PR builds, but not for nightly or release builds
3940
BUILD_EXTRA_FLAGS: '${{ "-a --host-lineinfo" if build_type == "pull-request" else "" }}'
4041
CMAKE_C_COMPILER_LAUNCHER: ${{ env.get("CMAKE_C_COMPILER_LAUNCHER") }}
4142
CMAKE_CUDA_COMPILER_LAUNCHER: ${{ env.get("CMAKE_CUDA_COMPILER_LAUNCHER") }}
4243
CMAKE_CXX_COMPILER_LAUNCHER: ${{ env.get("CMAKE_CXX_COMPILER_LAUNCHER") }}
4344
CMAKE_GENERATOR: ${{ env.get("CMAKE_GENERATOR") }}
44-
PARALLEL_LEVEL: ${{ env.get("PARALLEL_LEVEL") }}
45-
SCCACHE_BUCKET: ${{ env.get("SCCACHE_BUCKET") }}
46-
SCCACHE_IDLE_TIMEOUT: ${{ env.get("SCCACHE_IDLE_TIMEOUT") }}
47-
SCCACHE_REGION: ${{ env.get("SCCACHE_REGION") }}
48-
SCCACHE_S3_USE_SSL: ${{ env.get("SCCACHE_S3_USE_SSL") }}
49-
SCCACHE_S3_NO_CREDENTIALS: ${{ env.get("SCCACHE_S3_NO_CREDENTIALS") }}
45+
NVCC_APPEND_FLAGS: ${{ env.get("NVCC_APPEND_FLAGS", default="") }}
46+
PARALLEL_LEVEL: ${{ env.get("PARALLEL_LEVEL", default="8") }}
47+
SCCACHE_BUCKET: ${{ env.get("SCCACHE_BUCKET", default="") }}
48+
SCCACHE_DIST_AUTH_TYPE: ${{ env.get("SCCACHE_DIST_AUTH_TYPE", default="token") }}
49+
SCCACHE_DIST_FALLBACK_TO_LOCAL_COMPILE: ${{ env.get("SCCACHE_DIST_FALLBACK_TO_LOCAL_COMPILE", default="false") }}
50+
SCCACHE_DIST_MAX_RETRIES: ${{ env.get("SCCACHE_DIST_MAX_RETRIES", default="inf") }}
51+
SCCACHE_DIST_REQUEST_TIMEOUT: ${{ env.get("SCCACHE_DIST_REQUEST_TIMEOUT", default="7140") }}
52+
SCCACHE_DIST_SCHEDULER_URL: ${{ env.get("SCCACHE_DIST_SCHEDULER_URL", default="") }}
53+
SCCACHE_ERROR_LOG: ${{ env.get("SCCACHE_ERROR_LOG", default="/tmp/sccache.log") }}
54+
SCCACHE_IDLE_TIMEOUT: ${{ env.get("SCCACHE_IDLE_TIMEOUT", default="0") }}
55+
SCCACHE_NO_CACHE: ${{ env.get("SCCACHE_NO_CACHE", default="") }}
56+
SCCACHE_RECACHE: ${{ env.get("SCCACHE_RECACHE", default="") }}
57+
SCCACHE_REGION: ${{ env.get("SCCACHE_REGION", default="") }}
5058
SCCACHE_S3_KEY_PREFIX: libcuopt/${{ env.get("RAPIDS_CONDA_ARCH") }}/cuda${{ cuda_major }}
59+
SCCACHE_S3_NO_CREDENTIALS: ${{ env.get("SCCACHE_S3_NO_CREDENTIALS", default="false") }}
60+
SCCACHE_S3_PREPROCESSOR_CACHE_KEY_PREFIX: libcuopt/${{ env.get("RAPIDS_CONDA_ARCH") }}/cuda${{ cuda_major }}/conda/preprocessor-cache
61+
SCCACHE_S3_USE_PREPROCESSOR_CACHE_MODE: ${{ env.get("SCCACHE_S3_USE_PREPROCESSOR_CACHE_MODE", default="true") }}
62+
SCCACHE_S3_USE_SSL: ${{ env.get("SCCACHE_S3_USE_SSL", default="true") }}
63+
SCCACHE_SERVER_LOG: ${{ env.get("SCCACHE_SERVER_LOG", default="sccache=debug") }}
5164

5265
requirements:
5366
build:

cpp/CMakeLists.txt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ FetchContent_MakeAvailable(papilo)
235235
FetchContent_Declare(
236236
pslp
237237
GIT_REPOSITORY "https://github.com/dance858/PSLP.git"
238-
GIT_TAG "v0.0.4"
238+
GIT_TAG "v0.0.8"
239239
GIT_PROGRESS TRUE
240240
EXCLUDE_FROM_ALL
241241
SYSTEM
@@ -484,6 +484,15 @@ endif()
484484

485485

486486
if(NOT BUILD_LP_ONLY)
487+
rapids_cpm_find(
488+
argparse 3.2.0
489+
GLOBAL_TARGETS argparse::argparse
490+
CPM_ARGS
491+
GIT_REPOSITORY https://github.com/p-ranav/argparse.git
492+
GIT_TAG v3.2
493+
GIT_SHALLOW TRUE
494+
)
495+
487496
add_executable(cuopt_cli cuopt_cli.cpp)
488497

489498
set_target_properties(cuopt_cli
@@ -515,6 +524,7 @@ target_link_libraries(cuopt_cli
515524
${CUDSS_LIBRARIES}
516525
TBB::tbb
517526
PRIVATE
527+
argparse::argparse
518528
)
519529
# Use RUNPATH when building locally in order to allow LD_LIBRARY_PATH to override the conda env path
520530
if(NOT DEFINED INSTALL_TARGET OR "${INSTALL_TARGET}" STREQUAL "")

cpp/cuopt_cli.cpp

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
/* clang-format off */
22
/*
3-
* SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
* SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66
/* clang-format on */
77

8+
#include <cuopt/linear_programming/backend_selection.hpp>
9+
#include <cuopt/linear_programming/cpu_optimization_problem.hpp>
810
#include <cuopt/linear_programming/mip/solver_settings.hpp>
911
#include <cuopt/linear_programming/optimization_problem.hpp>
12+
#include <cuopt/linear_programming/optimization_problem_utils.hpp>
1013
#include <cuopt/linear_programming/solve.hpp>
1114
#include <mps_parser/parser.hpp>
1215
#include <utilities/logger.hpp>
@@ -89,7 +92,6 @@ int run_single_file(const std::string& file_path,
8992
bool solve_relaxation,
9093
const std::map<std::string, std::string>& settings_strings)
9194
{
92-
const raft::handle_t handle_{};
9395
cuopt::linear_programming::solver_settings_t<int, double> settings;
9496

9597
try {
@@ -122,13 +124,31 @@ int run_single_file(const std::string& file_path,
122124
return -1;
123125
}
124126

125-
auto op_problem =
126-
cuopt::linear_programming::mps_data_model_to_optimization_problem(&handle_, mps_data_model);
127+
// Determine memory backend and create problem using interface
128+
// Create handle only for GPU memory backend (avoid CUDA init on CPU-only hosts)
129+
auto memory_backend = cuopt::linear_programming::get_memory_backend_type();
130+
std::unique_ptr<raft::handle_t> handle_ptr;
131+
std::unique_ptr<cuopt::linear_programming::optimization_problem_interface_t<int, double>>
132+
problem_interface;
133+
134+
if (memory_backend == cuopt::linear_programming::memory_backend_t::GPU) {
135+
handle_ptr = std::make_unique<raft::handle_t>();
136+
problem_interface =
137+
std::make_unique<cuopt::linear_programming::optimization_problem_t<int, double>>(
138+
handle_ptr.get());
139+
} else {
140+
problem_interface =
141+
std::make_unique<cuopt::linear_programming::cpu_optimization_problem_t<int, double>>();
142+
}
143+
144+
// Populate the problem from MPS data model
145+
cuopt::linear_programming::populate_from_mps_data_model(problem_interface.get(), mps_data_model);
127146

128-
const bool is_mip =
129-
(op_problem.get_problem_category() == cuopt::linear_programming::problem_category_t::MIP ||
130-
op_problem.get_problem_category() == cuopt::linear_programming::problem_category_t::IP) &&
131-
!solve_relaxation;
147+
const bool is_mip = (problem_interface->get_problem_category() ==
148+
cuopt::linear_programming::problem_category_t::MIP ||
149+
problem_interface->get_problem_category() ==
150+
cuopt::linear_programming::problem_category_t::IP) &&
151+
!solve_relaxation;
132152

133153
try {
134154
auto initial_solution =
@@ -157,10 +177,10 @@ int run_single_file(const std::string& file_path,
157177
try {
158178
if (is_mip) {
159179
auto& mip_settings = settings.get_mip_settings();
160-
auto solution = cuopt::linear_programming::solve_mip(op_problem, mip_settings);
180+
auto solution = cuopt::linear_programming::solve_mip(problem_interface.get(), mip_settings);
161181
} else {
162182
auto& lp_settings = settings.get_pdlp_settings();
163-
auto solution = cuopt::linear_programming::solve_lp(op_problem, lp_settings);
183+
auto solution = cuopt::linear_programming::solve_lp(problem_interface.get(), lp_settings);
164184
}
165185
} catch (const std::exception& e) {
166186
CUOPT_LOG_ERROR("Error: %s", e.what());
@@ -334,19 +354,23 @@ int main(int argc, char* argv[])
334354
const auto initial_solution_file = program.get<std::string>("--initial-solution");
335355
const auto solve_relaxation = program.get<bool>("--relaxation");
336356

337-
// All arguments are parsed as string, default values are parsed as int if unused.
338-
const auto num_gpus = program.is_used("--num-gpus")
339-
? std::stoi(program.get<std::string>("--num-gpus"))
340-
: program.get<int>("--num-gpus");
341-
357+
// Only initialize CUDA resources if using GPU memory backend (not remote execution)
358+
auto memory_backend = cuopt::linear_programming::get_memory_backend_type();
342359
std::vector<std::shared_ptr<rmm::mr::device_memory_resource>> memory_resources;
343360

344-
for (int i = 0; i < std::min(raft::device_setter::get_device_count(), num_gpus); ++i) {
345-
cudaSetDevice(i);
346-
memory_resources.push_back(make_async());
347-
rmm::mr::set_per_device_resource(rmm::cuda_device_id{i}, memory_resources.back().get());
361+
if (memory_backend == cuopt::linear_programming::memory_backend_t::GPU) {
362+
// All arguments are parsed as string, default values are parsed as int if unused.
363+
const auto num_gpus = program.is_used("--num-gpus")
364+
? std::stoi(program.get<std::string>("--num-gpus"))
365+
: program.get<int>("--num-gpus");
366+
367+
for (int i = 0; i < std::min(raft::device_setter::get_device_count(), num_gpus); ++i) {
368+
RAFT_CUDA_TRY(cudaSetDevice(i));
369+
memory_resources.push_back(make_async());
370+
rmm::mr::set_per_device_resource(rmm::cuda_device_id{i}, memory_resources.back().get());
371+
}
372+
RAFT_CUDA_TRY(cudaSetDevice(0));
348373
}
349-
cudaSetDevice(0);
350374

351375
return run_single_file(file_name, initial_solution_file, solve_relaxation, settings_strings);
352376
}

0 commit comments

Comments
 (0)