From 5b13f785e907b3d99601112d5ca46792ffb4050d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Fri, 2 Oct 2026 08:37:34 +0200 Subject: [PATCH 01/19] Build against latest cuOpt nightly wheels from RAPIDS nightly index --- .github/workflows/main-arm64.yml | 4 ++-- .github/workflows/main-x86_64.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main-arm64.yml b/.github/workflows/main-arm64.yml index c6ac4d8..1fcbdc3 100644 --- a/.github/workflows/main-arm64.yml +++ b/.github/workflows/main-arm64.yml @@ -28,9 +28,9 @@ jobs: run: | mkdir -p venvs uv venv venvs/cu12 - uv pip install --python venvs/cu12 --extra-index-url=https://pypi.nvidia.com 'cuopt-cu12==26.8.*' -qq + uv pip install --python venvs/cu12 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'cuopt-cu12>=26.10.0a0' -qq uv venv venvs/cu13 - uv pip install --python venvs/cu13 --extra-index-url=https://pypi.nvidia.com 'cuopt-cu13==26.8.*' -qq + uv pip install --python venvs/cu13 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'cuopt-cu13>=26.10.0a0' -qq # Get GAMS (ARM64 version) - name: Download and extract latest GAMS distribution diff --git a/.github/workflows/main-x86_64.yml b/.github/workflows/main-x86_64.yml index 535d4bd..7896ebc 100644 --- a/.github/workflows/main-x86_64.yml +++ b/.github/workflows/main-x86_64.yml @@ -28,9 +28,9 @@ jobs: run: | mkdir -p venvs uv venv venvs/cu12 - uv pip install --python venvs/cu12 --extra-index-url=https://pypi.nvidia.com 'cuopt-cu12==26.8.*' -qq + uv pip install --python venvs/cu12 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'cuopt-cu12>=26.10.0a0' -qq uv venv venvs/cu13 - uv pip install --python venvs/cu13 --extra-index-url=https://pypi.nvidia.com 'cuopt-cu13==26.8.*' -qq + uv pip install --python venvs/cu13 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'cuopt-cu13>=26.10.0a0' -qq # Get GAMS - name: Download and extract latest GAMS distribution From 9f2afcb6f1dbd781c270d522c614fb740273c52b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Fri, 2 Oct 2026 08:37:34 +0200 Subject: [PATCH 02/19] Support multi-GPU PDLP via num_gpus -1/>1 and add multigpu_pdlp_partitioner option --- assets/optcuopt.def | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/assets/optcuopt.def b/assets/optcuopt.def index 2184850..0c4aa3d 100644 --- a/assets/optcuopt.def +++ b/assets/optcuopt.def @@ -3,7 +3,11 @@ * * name type usermap default low high visible group num_cpu_threads integer 0 -1 -1 maxint 1 1 Controls the number of CPU threads used in the LP and MIP solvers (default GAMS Threads) -num_gpus integer 0 1 1 2 1 2 Controls the number of GPUs to use for the solve. This setting is only relevant for LP problems that uses concurrent mode and supports up to 2 GPUs at the moment. Using this mode will run PDLP and barrier in parallel on different GPUs to avoid sharing single GPU resources. +num_gpus integer 0 1 -1 72 1 2 Controls the number of GPUs to use for the solve. In concurrent mode for LP problems up to 2 GPUs are used, running PDLP and barrier in parallel on different GPUs to avoid sharing single GPU resources. With method pdlp, a value of -1 (all visible GPUs) or greater than 1 runs multi-GPU PDLP, which shards the LP across GPUs (the problem must currently fit into the memory of a single GPU). +multigpu_pdlp_partitioner enumint 0 0 1 2 Controls how multi-GPU PDLP partitions the problem across GPUs + 0 1 auto (default) RoundRobin on 1 GPU, KaMinPar otherwise + 1 1 KaMinPar multi-threaded graph partitioner, better balanced shards at the cost of extra partitioning time + 2 1 RoundRobin no partitioning graph built presolve enumint 0 -1 1 1 Controls which presolver (if any) to use for presolve reductions. -1 1 default (Papilo for MIP, PSLP for LP) 0 1 off (disable presolve) From 56556f99166778a257899c46e2eda456218ea097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Fri, 2 Oct 2026 08:47:26 +0200 Subject: [PATCH 03/19] Adapt link and bundles to split cuOpt nightly libraries (libcuopt_mathopt/client, new cuDSS mtlayer) --- .github/workflows/main-arm64.yml | 22 ++++++++++++---------- .github/workflows/main-x86_64.yml | 22 ++++++++++++---------- build-link.sh | 11 ++++++----- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/.github/workflows/main-arm64.yml b/.github/workflows/main-arm64.yml index 1fcbdc3..c457b12 100644 --- a/.github/workflows/main-arm64.yml +++ b/.github/workflows/main-arm64.yml @@ -51,7 +51,7 @@ jobs: gcc -Wall gmscuopt.c -o gmscuopt-cu12.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I $GAMSCAPI $GAMSCAPI/gmomcc.c $GAMSCAPI/optcc.c $GAMSCAPI/gevmcc.c \ - -I $CUOPT/include $JITLINK/libnvJitLink.so.12 -L $CUOPT/lib64 -lcuopt + -I $CUOPT/include $JITLINK/libnvJitLink.so.12 -L $CUOPT/lib64 -lcuopt_mathopt patchelf --set-rpath \$ORIGIN gmscuopt-cu12.out export CUOPT="venvs/cu13/lib/python3.13/site-packages/libcuopt" export JITLINK="venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib" @@ -60,7 +60,7 @@ jobs: gcc -Wall gmscuopt.c -o gmscuopt-cu13.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I $GAMSCAPI $GAMSCAPI/gmomcc.c $GAMSCAPI/optcc.c $GAMSCAPI/gevmcc.c \ - -I $CUOPT/include $JITLINK/libnvJitLink.so.13 -L $CUOPT/lib64 -lcuopt + -I $CUOPT/include $JITLINK/libnvJitLink.so.13 -L $CUOPT/lib64 -lcuopt_mathopt patchelf --set-rpath \$ORIGIN gmscuopt-cu13.out # Collect dependencies for link and runtime convenience archive @@ -69,17 +69,18 @@ jobs: mkdir release-cu12 cp gmscuopt-cu12.out release-cu12/gmscuopt.out cp assets/* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libraft_cu12.libs/libgomp-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_mathopt.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_client.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libgomp-*.so* release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libtbb-*.so* release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libtbbmalloc-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libomp-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcudss_mtlayer_cuopt.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libcudart-*.so* release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/rapids_logger/lib64/librapids_logger.so release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/librmm/lib64/librmm.so release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/nccl/lib/libnccl.so* release-cu12/ mkdir runtime-cu12 cp venvs/cu12/lib/python3.13/site-packages/nvidia/cu12/lib/libcudss.so* runtime-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/nvidia/cu12/lib/libcudss_mtlayer_gomp.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/cusolver/lib/libcusolver.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/cublas/lib/libcublas.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/cublas/lib/libcublasLt.so* runtime-cu12/ @@ -90,17 +91,18 @@ jobs: mkdir release-cu13 cp gmscuopt-cu13.out release-cu13/gmscuopt.out cp assets/* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libraft_cu13.libs/libgomp-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_mathopt.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_client.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libgomp-*.so* release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libtbb-*.so* release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libtbbmalloc-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libomp-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcudss_mtlayer_cuopt.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libcudart-*.so* release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/rapids_logger/lib64/librapids_logger.so release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/librmm/lib64/librmm.so release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/nccl/lib/libnccl.so* release-cu13/ mkdir runtime-cu13 cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcudss.so* runtime-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcudss_mtlayer_gomp.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libnvJitLink.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcublas.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcublasLt.so* runtime-cu13/ diff --git a/.github/workflows/main-x86_64.yml b/.github/workflows/main-x86_64.yml index 7896ebc..66485ed 100644 --- a/.github/workflows/main-x86_64.yml +++ b/.github/workflows/main-x86_64.yml @@ -51,7 +51,7 @@ jobs: gcc -Wall gmscuopt.c -o gmscuopt-cu12.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I $GAMSCAPI $GAMSCAPI/gmomcc.c $GAMSCAPI/optcc.c $GAMSCAPI/gevmcc.c \ - -I $CUOPT/include $JITLINK/libnvJitLink.so.12 -L $CUOPT/lib64 -lcuopt + -I $CUOPT/include $JITLINK/libnvJitLink.so.12 -L $CUOPT/lib64 -lcuopt_mathopt patchelf --set-rpath \$ORIGIN gmscuopt-cu12.out export CUOPT="venvs/cu13/lib/python3.13/site-packages/libcuopt" export JITLINK="venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib" @@ -60,7 +60,7 @@ jobs: gcc -Wall gmscuopt.c -o gmscuopt-cu13.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I $GAMSCAPI $GAMSCAPI/gmomcc.c $GAMSCAPI/optcc.c $GAMSCAPI/gevmcc.c \ - -I $CUOPT/include $JITLINK/libnvJitLink.so.13 -L $CUOPT/lib64 -lcuopt + -I $CUOPT/include $JITLINK/libnvJitLink.so.13 -L $CUOPT/lib64 -lcuopt_mathopt patchelf --set-rpath \$ORIGIN gmscuopt-cu13.out # Collect dependencies for link and runtime convenience archive @@ -69,17 +69,18 @@ jobs: mkdir release-cu12 cp gmscuopt-cu12.out release-cu12/gmscuopt.out cp assets/* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libraft_cu12.libs/libgomp-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_mathopt.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_client.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libgomp-*.so* release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libtbb-*.so* release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libtbbmalloc-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libomp-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcudss_mtlayer_cuopt.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libcudart-*.so* release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/rapids_logger/lib64/librapids_logger.so release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/librmm/lib64/librmm.so release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/nccl/lib/libnccl.so* release-cu12/ mkdir runtime-cu12 cp venvs/cu12/lib/python3.13/site-packages/nvidia/cu12/lib/libcudss.so* runtime-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/nvidia/cu12/lib/libcudss_mtlayer_gomp.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/cusolver/lib/libcusolver.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/cublas/lib/libcublas.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/cublas/lib/libcublasLt.so* runtime-cu12/ @@ -90,17 +91,18 @@ jobs: mkdir release-cu13 cp gmscuopt-cu13.out release-cu13/gmscuopt.out cp assets/* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libraft_cu13.libs/libgomp-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_mathopt.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_client.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libgomp-*.so* release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libtbb-*.so* release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libtbbmalloc-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libomp-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcudss_mtlayer_cuopt.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libcudart-*.so* release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/rapids_logger/lib64/librapids_logger.so release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/librmm/lib64/librmm.so release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/nccl/lib/libnccl.so* release-cu13/ mkdir runtime-cu13 cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcudss.so* runtime-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcudss_mtlayer_gomp.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libnvJitLink.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcublas.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcublasLt.so* runtime-cu13/ diff --git a/build-link.sh b/build-link.sh index 07f1ed3..bbdc987 100755 --- a/build-link.sh +++ b/build-link.sh @@ -40,7 +40,7 @@ gcc -g3 -O0 -Wall gmscuopt.c -o gmscuopt-cu13.out \ -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I "$GAMSCAPI" "$GAMSCAPI/gmomcc.c" "$GAMSCAPI/optcc.c" "$GAMSCAPI/gevmcc.c" \ -I "$CUOPT/include" "$JITLINK/libnvJitLink.so.13" \ - -L "$CUOPT/lib64" -lcuopt + -L "$CUOPT/lib64" -lcuopt_mathopt # 5. Patch RPATH patchelf --set-rpath \$ORIGIN gmscuopt-cu13.out @@ -53,15 +53,16 @@ mkdir -p "$GAMSDIST" mv gmscuopt-cu13.out "$GAMSDIST/gmscuopt.out" -cp "$CUOPT/lib64/libcuopt.so" "$GAMSDIST/" -cp "$SITE_PACKAGES"/libraft_cu13.libs/libgomp-*.so* "$GAMSDIST/" +cp "$CUOPT/lib64/libcuopt_mathopt.so" "$GAMSDIST/" +cp "$CUOPT/lib64/libcuopt_client.so" "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libgomp-*.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libtbb-*.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libtbbmalloc-*.so* "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libomp-*.so* "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt/lib64/libcudss_mtlayer_cuopt.so "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libcudart-*.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/rapids_logger/lib64/librapids_logger.so "$GAMSDIST/" cp "$SITE_PACKAGES"/librmm/lib64/librmm.so "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcudss.so* "$GAMSDIST/" -cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcudss_mtlayer_gomp.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/cu13/lib/libnvJitLink.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcublas.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcublasLt.so* "$GAMSDIST/" From b7b2871d1dbd8e759dcc943e62086b6d4b7cbc7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Fri, 2 Oct 2026 08:50:13 +0200 Subject: [PATCH 04/19] Drop PDLP reduced-cost workaround, fixed upstream in cuOpt 26.10 (NVIDIA/cuopt#1797) --- gmscuopt.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/gmscuopt.c b/gmscuopt.c index ef626bf..abff129 100644 --- a/gmscuopt.c +++ b/gmscuopt.c @@ -1035,18 +1035,7 @@ int main(int argc, char *argv[]) final_duals[i] = gams2cuopt_row ? raw_duals[gams2cuopt_row[i]] : raw_duals[i]; cuopt_float_t *reduced_costs = malloc(num_variables * sizeof(cuopt_float_t)); - if (obj_qnz == 0) - { - // cuOpt 26.08's PDLP returns all-zero reduced costs, so compute them for LPs from the - // duals as d = c - A^T y (exact for dual simplex and barrier as well). GMO's own - // computation (gmoSetSolution2) ignores c when the objective variable is eliminated. - status = gmoGetObjVector(gmo, reduced_costs, NULL); - for (int r = 0; r < num_constraints && !status; r++) - for (int k = constraint_matrix_row_offsets[r]; k < constraint_matrix_row_offsets[r + 1]; k++) - reduced_costs[constraint_matrix_column_indices[k]] -= constraint_matrix_coefficent_values[k] * raw_duals[r]; - } - else - status = cuOptGetReducedCosts(solution, reduced_costs); + status = cuOptGetReducedCosts(solution, reduced_costs); if (status) { printOut(gev, "Error getting reduced costs: %d\n", status); From ba7bdeec20e843b110596d91a765467a0189e6c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Fri, 2 Oct 2026 09:00:01 +0200 Subject: [PATCH 05/19] Document multi-GPU PDLP usage in README --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index bc3cf0d..fe8078d 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,23 @@ gamslib trnsport gams trnsport lp cuopt ``` +## Multi-GPU PDLP + +With cuOpt 26.10 or newer, LPs can be solved with PDLP on several GPUs at once. This requires both `method 1` (PDLP) and `num_gpus -1` (all visible GPUs) or `num_gpus` greater than 1 in the option file: +``` +* cuopt.opt +method 1 +num_gpus -1 +``` +``` +gams mymodel lp=cuopt optfile=1 +``` + +- Without `method 1`, i.e. in the default concurrent mode, `num_gpus 2` instead runs PDLP and barrier in parallel on two GPUs. +- `multigpu_pdlp_partitioner` selects how the problem is split across the GPUs: `0` auto (default), `1` KaMinPar (better balanced, extra partitioning time), `2` round robin. +- The GPUs used can be restricted with `CUDA_VISIBLE_DEVICES`, e.g. `CUDA_VISIBLE_DEVICES=0,1 gams mymodel lp=cuopt optfile=1`. +- Only LPs are supported, and the whole problem currently has to fit into the memory of a single GPU. + ## Examples ### Notebooks From e5bfb6d8598ecc389eca17511a736391e5f1b26f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Fri, 2 Oct 2026 09:30:32 +0200 Subject: [PATCH 06/19] Remove options dropped in cuOpt 26.10 from optcuopt.def --- assets/optcuopt.def | 4 ---- 1 file changed, 4 deletions(-) diff --git a/assets/optcuopt.def b/assets/optcuopt.def index 0c4aa3d..9b21f4f 100644 --- a/assets/optcuopt.def +++ b/assets/optcuopt.def @@ -128,8 +128,6 @@ mip_reliability_branching integer 0 -1 -1 maxint 1 3 Controls the reliablity bra mip_strong_branching_simplex_iteration_limit integer 0 -1 -1 maxint 1 3 Controls the strong branching simplex iteration limit mip_hyper_heuristic_population_size integer 0 32 1 maxint 1 3 Controls maximum number of solutions in pool mip_hyper_heuristic_num_cpufj_threads integer 0 8 0 maxint 1 3 Controls parallel CPU FJ climbers -mip_hyper_heuristic_presolve_time_ratio double 0 0.1 0 1 1 3 Controls fraction of total time for presolve -mip_hyper_heuristic_presolve_max_time double 0 60 0 maxdouble 1 3 Controls the hard cap on presolve seconds mip_hyper_heuristic_root_lp_time_ratio double 0 0.1 0 1 1 3 Controls fraction of total time for root LP mip_hyper_heuristic_root_lp_max_time double 0 15 0 maxdouble 1 3 Controls the hard cap on root LP seconds mip_hyper_heuristic_rins_time_limit double 0 3 0 maxdouble 1 3 Controls per-call RINS sub-MIP time @@ -149,7 +147,6 @@ mip_hyper_diving_guided integer 0 -1 -1 1 1 3 Controls diving heuristic guided d mip_hyper_diving_coefficient integer 0 -1 -1 1 1 3 Controls diving heuristic coefficient (-1 automatic, 0 disabled, 1 enabled) mip_hyper_diving_farkas integer 0 -1 -1 1 1 3 Controls diving heuristic farkas (-1 automatic, 0 disabled, 1 enabled) mip_hyper_diving_vector_length integer 0 -1 -1 1 1 3 Controls diving heuristic vector-length (-1 automatic, 0 disabled, 1 enabled) -mip_hyper_diving_min_node_depth integer 0 10 0 maxint 1 3 Controls minimum depth at which to start diving mip_hyper_diving_node_limit integer 0 500 0 maxint 1 3 Controls nodes explored per dive mip_hyper_diving_iteration_limit_factor double 0 0.05 0 1 1 3 Fraction of best-first iterations allowed per dive mip_hyper_diving_backtrack_limit integer 0 5 0 32767 1 3 Controls maximum backtracking allowed per dive @@ -157,7 +154,6 @@ mip_hyper_submip_base_target_fixrate double 0 0.6 0 1 1 3 Controls base target f mip_hyper_submip_min_fixrate double 0 0.25 0 1 1 3 Controls minimum fix rate for accepting the RINS neighbourhood mip_hyper_submip_min_fixrate_cap double 0 0.1 0 1 1 3 Controls hard cap on the minimum fix rate for solving a sub-MIP mip_hyper_submip_target_mip_gap double 0 0.01 0 1 1 3 Controls MIP gap target for the sub-MIP -mip_hyper_submip_node_limit_base integer 0 200 0 maxint 1 3 Controls base node limit for the sub-MIP mip_hyper_submip_max_level integer 0 10 0 maxint 1 3 Controls maximum sub-MIP recursion level mip_hyper_submip_iteration_limit_ratio double 0 0.8 0 1 1 3 Controls sub-MIP simplex iteration limit as a factor of the parent branch-and-bound iterations mip_hyper_submip_enable_cpufj boolean 0 1 1 3 Controls whether CPU feasibility jump runs over the sub-MIP From 990bd1f4e2c096e308c3df333eea73f3609fa0f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Fri, 2 Oct 2026 09:30:32 +0200 Subject: [PATCH 07/19] Make multi-GPU PDLP work: create ranged problem and skip initial solutions for multi-GPU PDLP --- gmscuopt.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/gmscuopt.c b/gmscuopt.c index abff129..94360d7 100644 --- a/gmscuopt.c +++ b/gmscuopt.c @@ -161,6 +161,8 @@ int main(int argc, char *argv[]) cuopt_float_t* constraint_matrix_coefficent_values=NULL; cuopt_float_t* objective_coefficients=NULL; cuopt_float_t* rhs=NULL; + cuopt_float_t* constraint_lower_bounds=NULL; + cuopt_float_t* constraint_upper_bounds=NULL; cuopt_float_t* lower_bounds=NULL; cuopt_float_t* upper_bounds=NULL; char* constraint_sense=NULL; @@ -315,8 +317,19 @@ int main(int argc, char *argv[]) printOut(gev, "Error querying method option.\n"); goto DONE; } + cuopt_int_t num_gpus; + status = cuOptGetIntegerParameter(settings, CUOPT_NUM_GPUS, &num_gpus); + if (status != CUOPT_SUCCESS) + { + printOut(gev, "Error querying num_gpus option.\n"); + goto DONE; + } + // multi-GPU PDLP rejects initial solutions + int multigpu_pdlp = chosen_method == CUOPT_METHOD_PDLP && (num_gpus == -1 || num_gpus > 1); + if (multigpu_pdlp && gmoHaveBasis(gmo)) + printOut(gev, "Multi-GPU PDLP does not support initial solutions, ignoring the levels and marginals.\n"); // only when some PDLP is used and we have basis - if ((chosen_method == CUOPT_METHOD_PDLP || chosen_method == CUOPT_METHOD_CONCURRENT) && gmoHaveBasis(gmo)) + else if ((chosen_method == CUOPT_METHOD_PDLP || chosen_method == CUOPT_METHOD_CONCURRENT) && gmoHaveBasis(gmo)) { int nvars = gmoN(gmo), nconstraints = gmoM(gmo); double *lvls = (double *)malloc(sizeof(double) * nvars); @@ -432,6 +445,8 @@ int main(int argc, char *argv[]) constraint_matrix_coefficent_values = malloc(nnz * sizeof(cuopt_float_t)); objective_coefficients = malloc((num_variables) * sizeof(cuopt_float_t)); rhs = malloc((num_linear_constraints) * sizeof(cuopt_float_t)); + constraint_lower_bounds = malloc((num_linear_constraints) * sizeof(cuopt_float_t)); + constraint_upper_bounds = malloc((num_linear_constraints) * sizeof(cuopt_float_t)); lower_bounds = malloc((num_variables) * sizeof(cuopt_float_t)); upper_bounds = malloc((num_variables) * sizeof(cuopt_float_t)); constraint_sense = malloc((num_linear_constraints) * sizeof(char)); @@ -442,6 +457,8 @@ int main(int argc, char *argv[]) (constraint_matrix_coefficent_values == NULL) || (objective_coefficients == NULL) || (rhs == NULL) || + (constraint_lower_bounds == NULL) || + (constraint_upper_bounds == NULL) || (lower_bounds == NULL) || (upper_bounds == NULL) || (constraint_sense == NULL) || @@ -580,6 +597,8 @@ int main(int argc, char *argv[]) constraint_sense[lin_row] = orig_sense[i]; rhs[lin_row] = orig_rhs[i]; + constraint_lower_bounds[lin_row] = (orig_sense[i] == CUOPT_LESS_THAN) ? -CUOPT_INFINITY : orig_rhs[i]; + constraint_upper_bounds[lin_row] = (orig_sense[i] == CUOPT_GREATER_THAN) ? CUOPT_INFINITY : orig_rhs[i]; nnz += rnz; lin_row++; @@ -593,7 +612,9 @@ int main(int argc, char *argv[]) goto DONE; } - status = cuOptCreateProblem( + // Ranged form, since cuOpt's multi-GPU PDLP (without presolve) ignores the row types + RHS + // form of cuOptCreateProblem and sees no constraints + status = cuOptCreateRangedProblem( num_linear_constraints, // Use mapped linear size num_variables, (gmoSense(gmo) == gmoObj_Min) ? CUOPT_MINIMIZE : CUOPT_MAXIMIZE, @@ -602,8 +623,8 @@ int main(int argc, char *argv[]) constraint_matrix_row_offsets, constraint_matrix_column_indices, constraint_matrix_coefficent_values, - constraint_sense, - rhs, + constraint_lower_bounds, + constraint_upper_bounds, lower_bounds, upper_bounds, variable_types, @@ -1105,6 +1126,8 @@ int main(int argc, char *argv[]) free(constraint_matrix_coefficent_values); free(objective_coefficients); free(rhs); + free(constraint_lower_bounds); + free(constraint_upper_bounds); free(lower_bounds); free(upper_bounds); free(constraint_sense); From 235e7ccc26df74b7f26ac8258e966f053832ca10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Fri, 2 Oct 2026 09:33:30 +0200 Subject: [PATCH 08/19] Document multi-GPU PDLP limitations (no starting values, different convergence) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index fe8078d..c086500 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,8 @@ gams mymodel lp=cuopt optfile=1 - `multigpu_pdlp_partitioner` selects how the problem is split across the GPUs: `0` auto (default), `1` KaMinPar (better balanced, extra partitioning time), `2` round robin. - The GPUs used can be restricted with `CUDA_VISIBLE_DEVICES`, e.g. `CUDA_VISIBLE_DEVICES=0,1 gams mymodel lp=cuopt optfile=1`. - Only LPs are supported, and the whole problem currently has to fit into the memory of a single GPU. +- Starting values (levels and marginals) from GAMS are not passed to multi-GPU PDLP. +- Convergence can differ from single-GPU PDLP, so some models need noticeably more iterations. ## Examples From c7a771211031d336f7143d928659c7d8ede2282b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Fri, 2 Oct 2026 12:11:56 +0200 Subject: [PATCH 09/19] Add primal simplex method and SeDuMi barrier initial point, fix changed default in optcuopt.def --- assets/optcuopt.def | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/assets/optcuopt.def b/assets/optcuopt.def index 9b21f4f..dc089d3 100644 --- a/assets/optcuopt.def +++ b/assets/optcuopt.def @@ -34,6 +34,7 @@ method enumint 0 0 1 2 Controls the method to solve the linear programming probl 1 1 pdlp Use the PDLP method. 2 1 dual_simplex Use the dual simplex method. 3 1 method_barrier Use the barrier (interior-point) method. + 4 1 primal_simplex Use the primal simplex method. pdlp_precision enumint 0 -1 1 2 PDLP precision mode constants -1 1 default By default, PDLP operates in the native precision of the problem type (FP64 for double-precision problems). 0 1 single Run PDLP internally in FP32, with automatic conversion of inputs and outputs. FP32 uses half the memory and allows PDHG iterations to be on average twice as fast, but may require more iterations to converge. Compatible with crossover (solution is converted back to FP64 before crossover) and concurrent mode (PDLP runs in FP32 while other solvers run in FP64). @@ -68,6 +69,7 @@ barrier_dual_initial_point enumint 0 -1 1 4 Controls the method used to compute -1 1 automatic (default) cuOpt selects the best method 0 1 use an initial point from a heuristic approach based on the paper "On Implementing Mehrotra’s Predictor–Corrector Interior-Point Method for Linear Programming" (SIAM J. Optimization, 1992) by Lustig, Martsten, Shanno. 1 1 use an initial point from solving a least squares problem that minimizes the norms of the dual variables and reduced costs while statisfying the dual equality constraints. + 2 1 use a Sturm/SeDuMi-style mu-based primal and dual initial point. barrier_iterative_refinement boolean 0 1 1 4 Controls whether iterative refinement is applied after each barrier iteration to improve solution accuracy. qcqp_hyper_ruiz_equilibration integer 0 -1 -1 1 1 4 Controls Ruiz equilibration for QCQP (barrier) scaling (-1 automatic, 0 off, 1 on) barrier_step_scale double 0 0.9 0.5 0.9999 1 4 Controls the scaling factor applied to the step size in the barrier method. @@ -140,7 +142,7 @@ mip_hyper_heuristic_n_of_minimums_for_exit integer 0 7000 1 maxint 1 3 Controls mip_hyper_heuristic_enabled_recombiners integer 0 15 0 15 1 3 Controls bitmask: 1=BP 2=FP 4=LS 8=SubMIP mip_hyper_heuristic_cycle_detection_length integer 0 30 1 maxint 1 3 Controls FP assignment cycle ring buffer mip_hyper_heuristic_relaxed_lp_time_limit double 0 1 1e-09 maxdouble 1 3 Controls base relaxed LP time cap in heuristics -mip_hyper_heuristic_related_vars_time_limit double 0 30 1e-09 maxdouble 1 3 Controls time for related-variable structure build +mip_hyper_heuristic_related_vars_time_limit double 0 2 1e-09 maxdouble 1 3 Controls time for related-variable structure build mip_hyper_diving_line_search integer 0 -1 -1 1 1 3 Controls diving heuristic line search (-1 automatic, 0 disabled, 1 enabled) mip_hyper_diving_pseudocost integer 0 -1 -1 1 1 3 Controls diving heuristic pseudocost (-1 automatic, 0 disabled, 1 enabled) mip_hyper_diving_guided integer 0 -1 -1 1 1 3 Controls diving heuristic guided diving (-1 automatic, 0 disabled, 1 enabled) From 9a14f86dcc2bd8ac1d6e74245a0089fdb9919bb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Fri, 2 Oct 2026 12:14:17 +0200 Subject: [PATCH 10/19] Add options introduced in cuOpt 26.10 to optcuopt.def --- assets/optcuopt.def | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/assets/optcuopt.def b/assets/optcuopt.def index dc089d3..2cd40cb 100644 --- a/assets/optcuopt.def +++ b/assets/optcuopt.def @@ -44,6 +44,13 @@ iteration_limit integer 0 maxint 0 maxint 1 2 Controls the iteration limit after infeasibility_detection boolean 0 0 1 2 Controls whether PDLP should detect infeasibility strict_infeasibility boolean 0 0 1 2 Controls the strict infeasibility mode in PDLP crossover boolean 0 0 1 2 Controls whether PDLP should crossover to a basic solution after an optimal solution is found +concurrent_nnz_cutoff integer 0 50000000 -1 maxint 1 2 Controls the reduced number of nonzeros at or above which barrier and dual simplex are skipped in concurrent mode (-1 disables the cutoff) +primal_simplex_pricing enumint 0 1 1 2 Controls the pricing rule of the primal simplex method + 0 1 Dantzig pricing + 1 1 Devex pricing (default) +dual_simplex_initial_perturbation integer 0 -1 -1 1 1 2 Controls whether the simplex method perturbs the problem initially (-1 automatic, 0 off, 1 on) +dual_simplex_remove_perturbation integer 0 -1 -1 1 1 2 Controls whether the simplex method removes the perturbation (-1 automatic, 0 off, 1 on) +pdlp_hyper_enable_curtis_reid_scaling boolean 0 1 1 2 Controls whether Curtis-Reid prescaling runs before Ruiz/Pock-Chambolle scaling in PDLP save_best_primal_so_far boolean 0 0 1 2 Controls whether PDLP should save the best primal solution so far first_primal_feasible boolean 0 0 1 2 Controls whether PDLP should stop when the first primal feasible solution is found per_constraint_residual boolean 0 0 1 2 Controls whether PDLP should compute the primal & dual residual per constraint instead of globally @@ -72,6 +79,12 @@ barrier_dual_initial_point enumint 0 -1 1 4 Controls the method used to compute 2 1 use a Sturm/SeDuMi-style mu-based primal and dual initial point. barrier_iterative_refinement boolean 0 1 1 4 Controls whether iterative refinement is applied after each barrier iteration to improve solution accuracy. qcqp_hyper_ruiz_equilibration integer 0 -1 -1 1 1 4 Controls Ruiz equilibration for QCQP (barrier) scaling (-1 automatic, 0 off, 1 on) +barrier_adaptive_regularization integer 0 -1 -1 1 1 4 Controls adaptive regularization in the barrier method (-1 automatic, 0 off, 1 on) +barrier_primal_regularization double 0 -1 -1 maxdouble 1 4 Controls the initial primal regularization for the augmented system (-1 automatic) +barrier_dual_regularization double 0 -1 -1 maxdouble 1 4 Controls the initial dual regularization for the augmented system (-1 automatic) +barrier_initial_point_safeguard double 0 10 0 maxdouble 1 4 Controls the margin pushing the barrier initial iterate into the interior of the nonnegative orthant / second-order cone +barrier_presolve_bound_free_variables integer 0 -1 -1 1 1 4 Controls whether free variables are bounded during barrier presolve (-1 automatic, 0 off, 1 on) +barrier_hyper_gpu_ruiz_nnz_threshold integer 0 500000 0 maxint 1 4 Controls the number of nonzeros (of A and Q) at or above which barrier Ruiz equilibration runs on the GPU instead of the CPU barrier_step_scale double 0 0.9 0.5 0.9999 1 4 Controls the scaling factor applied to the step size in the barrier method. absolute_primal_tolerance double 0 0.0001 0 0.1 1 2 Controls the absolute primal tolerance used in PDLP's primal feasibility check relative_primal_tolerance double 0 0.0001 0 0.1 1 2 Controls the relative primal tolerance used in PDLP's primal feasibility check @@ -111,6 +124,8 @@ mip_implied_bound_cuts integer 0 -1 -1 1 1 3 Controls whether to enable implied mip_clique_cuts integer 0 -1 -1 1 1 3 Controls whether to enable clique cuts (-1 auto/default, 0 off, >0 on). mip_zero_half_cuts integer 0 -1 -1 1 1 3 Controls whether to use zero-half cuts (-1 automatic, 0 off, 1 on) mip_rins integer 0 -1 -1 1 1 3 Controls whether to use (recursive) RINS (-1 automatic, 0 off, 1 on) +mip_rens integer 0 -1 -1 1 1 3 Controls whether to use the RENS (relaxation enforced neighborhood search) heuristic (-1 automatic, 0 off, 1 on) +mip_mutation integer 0 -1 -1 1 1 3 Controls whether to use the mutation heuristic, which fixes a random subset of integer variables to their incumbent values (-1 automatic, 0 off, 1 on) mip_determinism_mode enumint 0 0 1 3 Controls whether the MIP solver runs in opportunistic or deterministic mode 0 1 opportunistic, results may vary between runs due to parallelism (default) 1 1 deterministic (experimental), improves reproducibility across runs with the same number of threads @@ -159,6 +174,11 @@ mip_hyper_submip_target_mip_gap double 0 0.01 0 1 1 3 Controls MIP gap target fo mip_hyper_submip_max_level integer 0 10 0 maxint 1 3 Controls maximum sub-MIP recursion level mip_hyper_submip_iteration_limit_ratio double 0 0.8 0 1 1 3 Controls sub-MIP simplex iteration limit as a factor of the parent branch-and-bound iterations mip_hyper_submip_enable_cpufj boolean 0 1 1 3 Controls whether CPU feasibility jump runs over the sub-MIP +mip_hyper_submip_node_limit_offset integer 0 200 0 maxint 1 3 Controls base node limit for the sub-MIP +mip_hyper_submip_iteration_limit_offset integer 0 10000 0 maxint 1 3 Controls base sub-MIP simplex iteration limit for root heuristics +mip_hyper_submip_round_close_ratio double 0 0.8 0 1 1 3 Controls share of the still unfixed integers left for later neighbourhood rounds (0 reaches the target fix rate in a single round) +mip_hyper_block_bve boolean 0 1 1 3 Controls whether blocks of binaries are eliminated in cuOpt's MIP presolve (needs mip_probing) +mip_hyper_heuristic_presolve_max_rounds integer 0 -1 -1 maxint 1 3 Controls the Papilo presolve rounds cap in heuristics (<0 derives it from the problem, 0 keeps the Papilo default) mip_hyper_diving_show_type boolean 0 0 1 3 log diving heuristic type when it finds a new incumbent mip_semi_continuous_big_m double 0 1e10 1 maxdouble 1 3 Controls the Big-M coefficient used when linearizing semi-continuous variable constraints From 5db50e0fcce21314d5b3d0dfde4b700e89f5eb74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Fri, 2 Oct 2026 13:49:38 +0200 Subject: [PATCH 11/19] Report iterations and nodes to GAMS via cuOpt solution attributes --- gmscuopt.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/gmscuopt.c b/gmscuopt.c index 94360d7..ba0ee14 100644 --- a/gmscuopt.c +++ b/gmscuopt.c @@ -877,6 +877,23 @@ int main(int argc, char *argv[]) } gmoSetHeadnTail(gmo, gmoHresused, solution_time); + // Iterations and nodes; cuOpt only provides the MIP attributes for MIP solutions and the LP + // attributes for LP solutions (otherwise CUOPT_INVALID_ARGUMENT) + cuopt_int_t nodes = -1; +#ifdef CUOPT_SOLUTION_ATTR_MIP_NUM_NODES + cuopt_int_t iterations = 0; + if (cuOptGetSolutionIntAttribute(solution, CUOPT_SOLUTION_ATTR_MIP_NUM_NODES, &nodes) == CUOPT_SUCCESS) { + gmoSetHeadnTail(gmo, gmoTmipnod, nodes); + if (cuOptGetSolutionIntAttribute(solution, CUOPT_SOLUTION_ATTR_MIP_NUM_SIMPLEX_ITERATIONS, &iterations) == CUOPT_SUCCESS) + gmoSetHeadnTail(gmo, gmoHiterused, iterations); + } + else { + nodes = -1; + if (cuOptGetSolutionIntAttribute(solution, CUOPT_SOLUTION_ATTR_LP_NUM_ITERATIONS, &iterations) == CUOPT_SUCCESS) + gmoSetHeadnTail(gmo, gmoHiterused, iterations); + } +#endif + int is_mip = has_integer_vars && (gmoModelType(gmo) == gmoProc_mip || gmoModelType(gmo) == gmoProc_miqcp); int have_solution = 0; int limit_point = 0; // continuous model stopped by an iteration/time limit @@ -932,7 +949,7 @@ int main(int argc, char *argv[]) // cuOpt does not expose the work units spent, so a set work limit is assumed to be the cause if (solution_time >= 0.99 * time_limit || work_limit < 1e10) gmoSolveStatSet(gmo, gmoSolveStat_Resource); - else if (node_limit < INT32_MAX) + else if (node_limit < INT32_MAX && (nodes < 0 || nodes >= node_limit)) // nodes < 0: unknown gmoSolveStatSet(gmo, gmoSolveStat_Iteration); else gmoSolveStatSet(gmo, gmoSolveStat_Solver); From 1654974ed71c4579770172ba0710cb029566bd49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Fri, 2 Oct 2026 13:50:03 +0200 Subject: [PATCH 12/19] Pass GAMS nodlim to cuOpt node_limit --- gmscuopt.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gmscuopt.c b/gmscuopt.c index ba0ee14..eb067d9 100644 --- a/gmscuopt.c +++ b/gmscuopt.c @@ -248,6 +248,13 @@ int main(int argc, char *argv[]) goto DONE; } } + if (gevGetIntOpt(gev, gevNodeLim) > 0) { // GAMS nodlim=0 means no limit + status = cuOptSetIntegerParameter(settings, CUOPT_NODE_LIMIT, gevGetIntOpt(gev, gevNodeLim)); + if (status != CUOPT_SUCCESS) { + printOut(gev, "Error setting node limit: %d\n", status); + goto DONE; + } + } if (gevGetDblOpt(gev, gevResLim) < RESLIM_INFINITY) { status = cuOptSetFloatParameter(settings, CUOPT_TIME_LIMIT, gevGetDblOpt(gev, gevResLim)); if (status != CUOPT_SUCCESS) { From 5cdd0661b1607e4d66232fa59987afc079647d0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Fri, 2 Oct 2026 14:05:27 +0200 Subject: [PATCH 13/19] Update README: system library requirements, manual gamsconfig setup, GPU arch per CUDA version, gamslib test [skip ci] --- README.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c086500..0e31f32 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,9 @@ Supported model types are LP, MIP, RMIP, QCP, RMIQCP. QCP and RMIQCP models must - **CPU architecture:** x86_64, arm64 - **GAMS:** Version 54 or newer - **GAMSPy:** Version 1.12.1 or newer -- **NVIDIA GPU:** Volta architecture or better +- **NVIDIA GPU:** Volta architecture or better with CUDA 12, Turing architecture or better with CUDA 13 - **CUDA Runtime Libraries:** 12 or 13 +- **System libraries:** OpenSSL 3 (`libssl.so.3`, `libcrypto.so.3`) and zlib (`libz.so.1`) ## Installation using `fetch-cuoptlink.py` @@ -70,9 +71,9 @@ python fetch-cuoptlink.py uninstall -g /opt/gams/gams55.0 - Make sure [CUDA runtime](https://developer.nvidia.com/cuda-downloads?target_os=Linux) is installed - Download and unpack `cuopt-link-release-cu12-{x86_64,arm64}.zip` or `cuopt-link-release-cu13-{x86_64,arm64}.zip` (for CUDA 12 and 13 respectively) from the [releases page](https://github.com/GAMS-dev/cuoptlink-builder/releases): - Unpack the contents of `cuopt-link-release-cu*-*.zip` into your GAMS system directory. For GAMSPy, you can find out your system directory by running `gamspy show base`. So for example you can run `unzip -o cuopt-link-release-cu*-*.zip -d $(gamspy show base)`. - - **Caution:** This will overwrite any existing `gamsconfig.yaml` file in that directory. The contained `gamsconfig.yaml` contains a `solverConfig` section to make cuOpt available to GAMS. + - The archive contains a `gamsconfig_cuopt.yaml` with a `solverConfig` section that makes cuOpt available to GAMS. If the GAMS system directory has no `gamsconfig.yaml` yet, copy it, e.g. `cp gamsconfig_cuopt.yaml gamsconfig.yaml`. Otherwise add its `solverConfig` entry to the existing `gamsconfig.yaml` (`fetch-cuoptlink.py` does this merge automatically). -The neccessary files from the CUDA 12 or 13 runtime can also be downloaded as convenient archive `cu12-runtime-{x86_64,arm64}.zip` or `cu13-runtime-{x86_64,arm64}.zip` from the [releases page](https://github.com/GAMS-dev/cuoptlink-builder/releases). +The necessary files from the CUDA 12 or 13 runtime can also be downloaded as convenient archive `cu12-runtime-{x86_64,arm64}.zip` or `cu13-runtime-{x86_64,arm64}.zip` from the [releases page](https://github.com/GAMS-dev/cuoptlink-builder/releases). ## Test the setup @@ -106,11 +107,12 @@ gams mymodel lp=cuopt optfile=1 ### Notebooks - [examples/trnsport_cuopt.ipynb](examples/trnsport_cuopt.ipynb) for CUDA 12 on x86_64 -- [examples/trnsport_cuopt.ipynb](examples/trnsport_cuopt_cu13.ipynb) for CUDA 13 on x86_64 +- [examples/trnsport_cuopt_cu13.ipynb](examples/trnsport_cuopt_cu13.ipynb) for CUDA 13 on x86_64 ### GAMS models Various GAMS models can be found in subfolder `examples/models` and are used to verify the solver link. + ### Regression tests The self-checking models in `examples/models/regression_tests` cover dual signs and reduced costs, QP/QCQP marginals, RMIQCP, option handling, error reporting, LP limit points, GMO handling (e.g. `=N=` rows, `requestMarginals=2`), rejection of unsupported features (SOS, semi-integer, MIQCP) and solve/model status mapping. Each model aborts if a result deviates from the reference values (obtained with CPLEX). Run them all against the GAMS system found in your `PATH` (it needs a GPU and the installed solver link): @@ -120,3 +122,13 @@ examples/models/regression_tests/run_tests.sh ``` The script prints `[PASS]` or `[FAIL]` per model and keeps the listing and log file of failed models for inspection. Its exit code is the number of failed models. + +### gamslib regression test + +`tests/test-gamslib-cuopt.py` solves the gamslib models listed in `tests/baseline.txt` with cuOpt and compares the objective values against a CPLEX baseline. It needs a GPU and the installed solver link: + +``` +python3 tests/test-gamslib-cuopt.py -g -j 2 # -g defaults to the GAMS found in PATH +``` + +Use `-r` to change the time limit per model (default 120s), `-t` for the relative tolerance (default 1e-6) and pass model names to run only a subset. The exit code is 1 if any model mismatches or fails to produce a solution. From cadddb73c02609cafd95220f8e4fbb9e23f075f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Fri, 2 Oct 2026 14:41:26 +0200 Subject: [PATCH 14/19] Use a harder market split instance in statuses.gms so the time-limit case cannot end early [skip ci] --- examples/models/regression_tests/statuses.gms | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/models/regression_tests/statuses.gms b/examples/models/regression_tests/statuses.gms index 27d1835..6575635 100644 --- a/examples/models/regression_tests/statuses.gms +++ b/examples/models/regression_tests/statuses.gms @@ -40,8 +40,9 @@ abort$(mInfMip.modelstat <> %modelStat.integerInfeasible% and mInfMip.modelstat * --- MIP stopped by the time limit with an incumbent: solve status 3, model status 8 * Market split instance (Cornuejols/Dawande): feasible incumbents are trivial, proving -* optimality is very hard for branch-and-bound. -Set i 'rows' /r1*r4/, j 'columns' /c1*c40/; +* optimality is very hard for branch-and-bound. With n = 10(m-1) columns for m rows, an exact +* split (objective 0) almost never exists, so the solve cannot end early by finding one. +Set i 'rows' /r1*r6/, j 'columns' /c1*c50/; Parameter a(i,j), d(i); option seed = 12345; a(i,j) = uniformInt(0, 99); From 11e690c5bdd65c287716a1cb379987a3ea8a95dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Fri, 2 Oct 2026 14:41:26 +0200 Subject: [PATCH 15/19] Allow model-specific time limits in the gamslib baseline, give poutil 300s [skip ci] --- README.md | 2 +- tests/baseline.txt | 2 +- tests/test-gamslib-cuopt.py | 23 +++++++++++++---------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 0e31f32..3122010 100644 --- a/README.md +++ b/README.md @@ -131,4 +131,4 @@ The script prints `[PASS]` or `[FAIL]` per model and keeps the listing and log f python3 tests/test-gamslib-cuopt.py -g -j 2 # -g defaults to the GAMS found in PATH ``` -Use `-r` to change the time limit per model (default 120s), `-t` for the relative tolerance (default 1e-6) and pass model names to run only a subset. The exit code is 1 if any model mismatches or fails to produce a solution. +Use `-r` to change the time limit per model (default 120s; an optional fourth column in `tests/baseline.txt` sets a model-specific time limit instead), `-t` for the relative tolerance (default 1e-6) and pass model names to run only a subset. The exit code is 1 if any model mismatches or fails to produce a solution. diff --git a/tests/baseline.txt b/tests/baseline.txt index c3509d2..c0f59a7 100644 --- a/tests/baseline.txt +++ b/tests/baseline.txt @@ -42,7 +42,7 @@ pak LP 1075.5471391775 paklive LP 19468.0876969476 pdi LP 294070 port LP 0.298363636363636 -poutil MIP 266793 +poutil MIP 266793 300 prodmix LP 18666.6666666667 prodsch MIP 3254.02381132426 prodsp LP 17869.0449355452 diff --git a/tests/test-gamslib-cuopt.py b/tests/test-gamslib-cuopt.py index 924050a..c3cb1b4 100644 --- a/tests/test-gamslib-cuopt.py +++ b/tests/test-gamslib-cuopt.py @@ -1,8 +1,9 @@ """Regression test: solve gamslib models with cuOpt and compare against CPLEX. -Each model listed in baseline.txt (name, model type, CPLEX objective) is -extracted with `gamslib`, solved with `solver=cuopt`, and the objective value -reported in the GAMS trace file is compared against the CPLEX reference. +Each model listed in baseline.txt (name, model type, CPLEX objective and optionally a +model-specific time limit in seconds that replaces --reslim) is extracted with `gamslib`, +solved with `solver=cuopt`, and the objective value reported in the GAMS trace file is +compared against the CPLEX reference. Run with: python3 tests/test-gamslib-cuopt.py [-g GAMS_DIR] [-j JOBS] [model ...] @@ -47,13 +48,14 @@ def rel_diff(self) -> float | None: return abs(self.obj - self.ref) / max(1.0, abs(self.ref)) -def read_baseline(path: str) -> list[tuple[str, str, float]]: +def read_baseline(path: str) -> list[tuple[str, str, float, int | None]]: entries = [] with open(path) as f: for line in f: fields = line.split() - if len(fields) == 3: - entries.append((fields[0], fields[1], float(fields[2]))) + if len(fields) in (3, 4): + reslim = int(fields[3]) if len(fields) == 4 else None + entries.append((fields[0], fields[1], float(fields[2]), reslim)) return entries @@ -130,8 +132,6 @@ def main() -> int: entries = [e for e in entries if e[0] in args.models] work_dir = tempfile.mkdtemp(prefix="gamslib-cuopt-") - # Some models set their own resLim, so leave generous headroom beyond --reslim. - timeout = 2 * args.reslim + 60 row = "{:6} {:12} {:6} {:>9} {:>9} {:>9} {:>17} {:>17} {}" print(f"cuOpt vs. CPLEX on {len(entries)} gamslib models " @@ -142,8 +142,11 @@ def main() -> int: print("-" * len(header), flush=True) def job(entry): - name, model_type, ref = entry - res = run_model(gams_dir, work_dir, name, model_type, ref, args.reslim, timeout) + name, model_type, ref, model_reslim = entry + reslim = model_reslim or args.reslim + # Some models set their own resLim, so leave generous headroom beyond reslim. + timeout = 2 * reslim + 60 + res = run_model(gams_dir, work_dir, name, model_type, ref, reslim, timeout) rel = res.rel_diff() ok = res.error is None and rel is not None and rel <= args.rtol obj = "NA" if res.obj is None else f"{res.obj:.10g}" From 21c682b58012921fa91c1caea98a5da0b268d10a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Fri, 2 Oct 2026 15:13:57 +0200 Subject: [PATCH 16/19] Add mip_hyper_presolve_indicator_strengthening option (cuOpt #1983) [skip ci] --- assets/optcuopt.def | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/optcuopt.def b/assets/optcuopt.def index 2cd40cb..329f922 100644 --- a/assets/optcuopt.def +++ b/assets/optcuopt.def @@ -178,6 +178,7 @@ mip_hyper_submip_node_limit_offset integer 0 200 0 maxint 1 3 Controls base node mip_hyper_submip_iteration_limit_offset integer 0 10000 0 maxint 1 3 Controls base sub-MIP simplex iteration limit for root heuristics mip_hyper_submip_round_close_ratio double 0 0.8 0 1 1 3 Controls share of the still unfixed integers left for later neighbourhood rounds (0 reaches the target fix rate in a single round) mip_hyper_block_bve boolean 0 1 1 3 Controls whether blocks of binaries are eliminated in cuOpt's MIP presolve (needs mip_probing) +mip_hyper_presolve_indicator_strengthening boolean 0 1 1 3 Controls whether implied indicator rows are appended and capacity rows are lifted by their indicator before Papilo presolve (MIP only) mip_hyper_heuristic_presolve_max_rounds integer 0 -1 -1 maxint 1 3 Controls the Papilo presolve rounds cap in heuristics (<0 derives it from the problem, 0 keeps the Papilo default) mip_hyper_diving_show_type boolean 0 0 1 3 log diving heuristic type when it finds a new incumbent mip_semi_continuous_big_m double 0 1e10 1 maxdouble 1 3 Controls the Big-M coefficient used when linearizing semi-continuous variable constraints From 8edd916570316cd57f1231f4980c208a0b426c93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Sun, 4 Oct 2026 09:54:38 +0200 Subject: [PATCH 17/19] build: adapt cuOpt link packaging to modular 26.10 wheels --- .github/workflows/main-arm64.yml | 49 ++++++++++++++++++------------- .github/workflows/main-x86_64.yml | 49 ++++++++++++++++++------------- build-link.sh | 30 +++++++++++-------- 3 files changed, 76 insertions(+), 52 deletions(-) diff --git a/.github/workflows/main-arm64.yml b/.github/workflows/main-arm64.yml index c457b12..bc8e7a2 100644 --- a/.github/workflows/main-arm64.yml +++ b/.github/workflows/main-arm64.yml @@ -44,23 +44,25 @@ jobs: - name: Compile GAMS/cuOpt-link binary "gmscuopt.out" for CUDA 12 and then for CUDA 13 run: | export GAMSCAPI="gamsdist/apifiles/C/api" - export CUOPT="venvs/cu12/lib/python3.13/site-packages/libcuopt" + export CUOPT="venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt" export JITLINK="venvs/cu12/lib/python3.13/site-packages/nvidia/nvjitlink/lib" export CUOPT_VERSION="`cat "$CUOPT/VERSION"`" export CUOPT_HASH="`cat "$CUOPT/GIT_COMMIT"`" gcc -Wall gmscuopt.c -o gmscuopt-cu12.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I $GAMSCAPI $GAMSCAPI/gmomcc.c $GAMSCAPI/optcc.c $GAMSCAPI/gevmcc.c \ - -I $CUOPT/include $JITLINK/libnvJitLink.so.12 -L $CUOPT/lib64 -lcuopt_mathopt + -I $CUOPT/include -I venvs/cu12/lib/python3.13/site-packages/libcuopt_client/include $JITLINK/libnvJitLink.so.12 -L $CUOPT/lib64 -lcuopt_mathopt \ + -L venvs/cu12/lib/python3.13/site-packages/libcuopt_client/lib64 -lcuopt_client patchelf --set-rpath \$ORIGIN gmscuopt-cu12.out - export CUOPT="venvs/cu13/lib/python3.13/site-packages/libcuopt" + export CUOPT="venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt" export JITLINK="venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib" export CUOPT_VERSION="`cat "$CUOPT/VERSION"`" export CUOPT_HASH="`cat "$CUOPT/GIT_COMMIT"`" gcc -Wall gmscuopt.c -o gmscuopt-cu13.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I $GAMSCAPI $GAMSCAPI/gmomcc.c $GAMSCAPI/optcc.c $GAMSCAPI/gevmcc.c \ - -I $CUOPT/include $JITLINK/libnvJitLink.so.13 -L $CUOPT/lib64 -lcuopt_mathopt + -I $CUOPT/include -I venvs/cu13/lib/python3.13/site-packages/libcuopt_client/include $JITLINK/libnvJitLink.so.13 -L $CUOPT/lib64 -lcuopt_mathopt \ + -L venvs/cu13/lib/python3.13/site-packages/libcuopt_client/lib64 -lcuopt_client patchelf --set-rpath \$ORIGIN gmscuopt-cu13.out # Collect dependencies for link and runtime convenience archive @@ -69,13 +71,16 @@ jobs: mkdir release-cu12 cp gmscuopt-cu12.out release-cu12/gmscuopt.out cp assets/* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_mathopt.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_client.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libgomp-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libtbb-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libtbbmalloc-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcudss_mtlayer_cuopt.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libcudart-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcuopt_mathopt.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client/lib64/libcuopt_client.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libgomp-*.so* release-cu12/ + # Both suffixed and unsuffixed client wheels may own libcuopt_client.so; ship either wheel's OpenMP runtime. + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client_cu12.libs/libgomp-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client.libs/libgomp-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libtbb-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libtbbmalloc-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcudss_mtlayer_cuopt.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libcudart-*.so* release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/rapids_logger/lib64/librapids_logger.so release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/librmm/lib64/librmm.so release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/nccl/lib/libnccl.so* release-cu12/ @@ -87,17 +92,20 @@ jobs: cp venvs/cu12/lib/python3.13/site-packages/nvidia/nvjitlink/lib/libnvJitLink.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/curand/lib/libcurand.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/cusparse/lib/libcusparse.so* runtime-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libcares-*.so* runtime-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client_cu12.libs/libcares-*.so* runtime-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client.libs/libcares-*.so* runtime-cu12/ mkdir release-cu13 cp gmscuopt-cu13.out release-cu13/gmscuopt.out cp assets/* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_mathopt.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_client.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libgomp-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libtbb-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libtbbmalloc-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcudss_mtlayer_cuopt.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libcudart-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcuopt_mathopt.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client/lib64/libcuopt_client.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libgomp-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client_cu13.libs/libgomp-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client.libs/libgomp-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libtbb-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libtbbmalloc-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcudss_mtlayer_cuopt.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libcudart-*.so* release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/rapids_logger/lib64/librapids_logger.so release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/librmm/lib64/librmm.so release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/nccl/lib/libnccl.so* release-cu13/ @@ -109,7 +117,8 @@ jobs: cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcurand.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcusolver.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcusparse.so* runtime-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libcares-*.so* runtime-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client_cu13.libs/libcares-*.so* runtime-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client.libs/libcares-*.so* runtime-cu13/ # Upload artifacts - name: Upload CUDA 12 link artifact to GitHub Actions (always) diff --git a/.github/workflows/main-x86_64.yml b/.github/workflows/main-x86_64.yml index 66485ed..aac532a 100644 --- a/.github/workflows/main-x86_64.yml +++ b/.github/workflows/main-x86_64.yml @@ -44,23 +44,25 @@ jobs: - name: Compile GAMS/cuOpt-link binary "gmscuopt.out" for CUDA 12 and then for CUDA 13 run: | export GAMSCAPI="gamsdist/apifiles/C/api" - export CUOPT="venvs/cu12/lib/python3.13/site-packages/libcuopt" + export CUOPT="venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt" export JITLINK="venvs/cu12/lib/python3.13/site-packages/nvidia/nvjitlink/lib" export CUOPT_VERSION="`cat "$CUOPT/VERSION"`" export CUOPT_HASH="`cat "$CUOPT/GIT_COMMIT"`" gcc -Wall gmscuopt.c -o gmscuopt-cu12.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I $GAMSCAPI $GAMSCAPI/gmomcc.c $GAMSCAPI/optcc.c $GAMSCAPI/gevmcc.c \ - -I $CUOPT/include $JITLINK/libnvJitLink.so.12 -L $CUOPT/lib64 -lcuopt_mathopt + -I $CUOPT/include -I venvs/cu12/lib/python3.13/site-packages/libcuopt_client/include $JITLINK/libnvJitLink.so.12 -L $CUOPT/lib64 -lcuopt_mathopt \ + -L venvs/cu12/lib/python3.13/site-packages/libcuopt_client/lib64 -lcuopt_client patchelf --set-rpath \$ORIGIN gmscuopt-cu12.out - export CUOPT="venvs/cu13/lib/python3.13/site-packages/libcuopt" + export CUOPT="venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt" export JITLINK="venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib" export CUOPT_VERSION="`cat "$CUOPT/VERSION"`" export CUOPT_HASH="`cat "$CUOPT/GIT_COMMIT"`" gcc -Wall gmscuopt.c -o gmscuopt-cu13.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I $GAMSCAPI $GAMSCAPI/gmomcc.c $GAMSCAPI/optcc.c $GAMSCAPI/gevmcc.c \ - -I $CUOPT/include $JITLINK/libnvJitLink.so.13 -L $CUOPT/lib64 -lcuopt_mathopt + -I $CUOPT/include -I venvs/cu13/lib/python3.13/site-packages/libcuopt_client/include $JITLINK/libnvJitLink.so.13 -L $CUOPT/lib64 -lcuopt_mathopt \ + -L venvs/cu13/lib/python3.13/site-packages/libcuopt_client/lib64 -lcuopt_client patchelf --set-rpath \$ORIGIN gmscuopt-cu13.out # Collect dependencies for link and runtime convenience archive @@ -69,13 +71,16 @@ jobs: mkdir release-cu12 cp gmscuopt-cu12.out release-cu12/gmscuopt.out cp assets/* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_mathopt.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_client.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libgomp-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libtbb-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libtbbmalloc-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcudss_mtlayer_cuopt.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libcudart-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcuopt_mathopt.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client/lib64/libcuopt_client.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libgomp-*.so* release-cu12/ + # Both suffixed and unsuffixed client wheels may own libcuopt_client.so; ship either wheel's OpenMP runtime. + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client_cu12.libs/libgomp-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client.libs/libgomp-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libtbb-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libtbbmalloc-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcudss_mtlayer_cuopt.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libcudart-*.so* release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/rapids_logger/lib64/librapids_logger.so release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/librmm/lib64/librmm.so release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/nccl/lib/libnccl.so* release-cu12/ @@ -87,17 +92,20 @@ jobs: cp venvs/cu12/lib/python3.13/site-packages/nvidia/nvjitlink/lib/libnvJitLink.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/curand/lib/libcurand.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/cusparse/lib/libcusparse.so* runtime-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libcares-*.so* runtime-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client_cu12.libs/libcares-*.so* runtime-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client.libs/libcares-*.so* runtime-cu12/ mkdir release-cu13 cp gmscuopt-cu13.out release-cu13/gmscuopt.out cp assets/* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_mathopt.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_client.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libgomp-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libtbb-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libtbbmalloc-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcudss_mtlayer_cuopt.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libcudart-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcuopt_mathopt.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client/lib64/libcuopt_client.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libgomp-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client_cu13.libs/libgomp-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client.libs/libgomp-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libtbb-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libtbbmalloc-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcudss_mtlayer_cuopt.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libcudart-*.so* release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/rapids_logger/lib64/librapids_logger.so release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/librmm/lib64/librmm.so release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/nccl/lib/libnccl.so* release-cu13/ @@ -109,7 +117,8 @@ jobs: cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcurand.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcusolver.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcusparse.so* runtime-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libcares-*.so* runtime-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client_cu13.libs/libcares-*.so* runtime-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client.libs/libcares-*.so* runtime-cu13/ # Upload artifacts - name: Upload CUDA 12 link artifact to GitHub Actions (always) diff --git a/build-link.sh b/build-link.sh index bbdc987..b9840ba 100755 --- a/build-link.sh +++ b/build-link.sh @@ -6,8 +6,7 @@ set -e # Users can export these before running the script, otherwise defaults are used. GAMSDIST="${GAMSDIST:-$HOME/gamsdist}" WORKSPACE="${WORKSPACE:-$(pwd)}" -CUOPT_VERSION="${CUOPT_VERSION:-26.08}" -CUOPT_HASH="${CUOPT_HASH:-12345}" +# Read build provenance from the mathopt wheel unless explicitly overridden below. # 2. Dynamically find the site-packages directory to avoid hardcoding the Python version # or the venv directory name (some setups use "venv", others "uv"-style ".venv"). @@ -27,8 +26,10 @@ fi # 3. Export specific build paths export GAMSCAPI="$GAMSDIST/apifiles/C/api" -export CUOPT="$SITE_PACKAGES/libcuopt" +export CUOPT="$SITE_PACKAGES/libcuopt_mathopt" export JITLINK="$SITE_PACKAGES/nvidia/cu13/lib" +CUOPT_VERSION="${CUOPT_VERSION:-$(<"$CUOPT/VERSION")}" +CUOPT_HASH="${CUOPT_HASH:-$(<"$CUOPT/GIT_COMMIT")}" echo "Building GAMS cuOpt solver link..." echo "Using GAMSDIST: $GAMSDIST" @@ -39,8 +40,9 @@ gcc -g3 -O0 -Wall gmscuopt.c -o gmscuopt-cu13.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" \ -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I "$GAMSCAPI" "$GAMSCAPI/gmomcc.c" "$GAMSCAPI/optcc.c" "$GAMSCAPI/gevmcc.c" \ - -I "$CUOPT/include" "$JITLINK/libnvJitLink.so.13" \ - -L "$CUOPT/lib64" -lcuopt_mathopt + -I "$CUOPT/include" -I "$SITE_PACKAGES/libcuopt_client/include" "$JITLINK/libnvJitLink.so.13" \ + -L "$CUOPT/lib64" -lcuopt_mathopt \ + -L "$SITE_PACKAGES/libcuopt_client/lib64" -lcuopt_client # 5. Patch RPATH patchelf --set-rpath \$ORIGIN gmscuopt-cu13.out @@ -54,12 +56,15 @@ mkdir -p "$GAMSDIST" mv gmscuopt-cu13.out "$GAMSDIST/gmscuopt.out" cp "$CUOPT/lib64/libcuopt_mathopt.so" "$GAMSDIST/" -cp "$CUOPT/lib64/libcuopt_client.so" "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libgomp-*.so* "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libtbb-*.so* "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libtbbmalloc-*.so* "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt/lib64/libcudss_mtlayer_cuopt.so "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libcudart-*.so* "$GAMSDIST/" +cp "$SITE_PACKAGES/libcuopt_client/lib64/libcuopt_client.so" "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_mathopt_cu13.libs/libgomp-*.so* "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_client_cu13.libs/libgomp-*.so* "$GAMSDIST/" +# The unsuffixed client wheel can also be installed and owns the same library path. +cp "$SITE_PACKAGES"/libcuopt_client.libs/libgomp-*.so* "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_mathopt_cu13.libs/libtbb-*.so* "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_mathopt_cu13.libs/libtbbmalloc-*.so* "$GAMSDIST/" +cp "$CUOPT/lib64/libcudss_mtlayer_cuopt.so" "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_mathopt_cu13.libs/libcudart-*.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/rapids_logger/lib64/librapids_logger.so "$GAMSDIST/" cp "$SITE_PACKAGES"/librmm/lib64/librmm.so "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcudss.so* "$GAMSDIST/" @@ -69,7 +74,8 @@ cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcublasLt.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcurand.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcusolver.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcusparse.so* "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libcares-*.so* "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_client_cu13.libs/libcares-*.so* "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_client.libs/libcares-*.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/nccl/lib/libnccl.so* "$GAMSDIST/" # Copy assets (suppress errors if directory is empty or missing) From 4855ada483f66202f2f46a2fc1414d5b8f2a5d85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Sun, 4 Oct 2026 10:32:04 +0200 Subject: [PATCH 18/19] Revert "build: adapt cuOpt link packaging to modular 26.10 wheels" --- .github/workflows/main-arm64.yml | 49 +++++++++++++------------------ .github/workflows/main-x86_64.yml | 49 +++++++++++++------------------ build-link.sh | 30 ++++++++----------- 3 files changed, 52 insertions(+), 76 deletions(-) diff --git a/.github/workflows/main-arm64.yml b/.github/workflows/main-arm64.yml index bc8e7a2..c457b12 100644 --- a/.github/workflows/main-arm64.yml +++ b/.github/workflows/main-arm64.yml @@ -44,25 +44,23 @@ jobs: - name: Compile GAMS/cuOpt-link binary "gmscuopt.out" for CUDA 12 and then for CUDA 13 run: | export GAMSCAPI="gamsdist/apifiles/C/api" - export CUOPT="venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt" + export CUOPT="venvs/cu12/lib/python3.13/site-packages/libcuopt" export JITLINK="venvs/cu12/lib/python3.13/site-packages/nvidia/nvjitlink/lib" export CUOPT_VERSION="`cat "$CUOPT/VERSION"`" export CUOPT_HASH="`cat "$CUOPT/GIT_COMMIT"`" gcc -Wall gmscuopt.c -o gmscuopt-cu12.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I $GAMSCAPI $GAMSCAPI/gmomcc.c $GAMSCAPI/optcc.c $GAMSCAPI/gevmcc.c \ - -I $CUOPT/include -I venvs/cu12/lib/python3.13/site-packages/libcuopt_client/include $JITLINK/libnvJitLink.so.12 -L $CUOPT/lib64 -lcuopt_mathopt \ - -L venvs/cu12/lib/python3.13/site-packages/libcuopt_client/lib64 -lcuopt_client + -I $CUOPT/include $JITLINK/libnvJitLink.so.12 -L $CUOPT/lib64 -lcuopt_mathopt patchelf --set-rpath \$ORIGIN gmscuopt-cu12.out - export CUOPT="venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt" + export CUOPT="venvs/cu13/lib/python3.13/site-packages/libcuopt" export JITLINK="venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib" export CUOPT_VERSION="`cat "$CUOPT/VERSION"`" export CUOPT_HASH="`cat "$CUOPT/GIT_COMMIT"`" gcc -Wall gmscuopt.c -o gmscuopt-cu13.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I $GAMSCAPI $GAMSCAPI/gmomcc.c $GAMSCAPI/optcc.c $GAMSCAPI/gevmcc.c \ - -I $CUOPT/include -I venvs/cu13/lib/python3.13/site-packages/libcuopt_client/include $JITLINK/libnvJitLink.so.13 -L $CUOPT/lib64 -lcuopt_mathopt \ - -L venvs/cu13/lib/python3.13/site-packages/libcuopt_client/lib64 -lcuopt_client + -I $CUOPT/include $JITLINK/libnvJitLink.so.13 -L $CUOPT/lib64 -lcuopt_mathopt patchelf --set-rpath \$ORIGIN gmscuopt-cu13.out # Collect dependencies for link and runtime convenience archive @@ -71,16 +69,13 @@ jobs: mkdir release-cu12 cp gmscuopt-cu12.out release-cu12/gmscuopt.out cp assets/* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcuopt_mathopt.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client/lib64/libcuopt_client.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libgomp-*.so* release-cu12/ - # Both suffixed and unsuffixed client wheels may own libcuopt_client.so; ship either wheel's OpenMP runtime. - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client_cu12.libs/libgomp-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client.libs/libgomp-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libtbb-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libtbbmalloc-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcudss_mtlayer_cuopt.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libcudart-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_mathopt.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_client.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libgomp-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libtbb-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libtbbmalloc-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcudss_mtlayer_cuopt.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libcudart-*.so* release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/rapids_logger/lib64/librapids_logger.so release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/librmm/lib64/librmm.so release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/nccl/lib/libnccl.so* release-cu12/ @@ -92,20 +87,17 @@ jobs: cp venvs/cu12/lib/python3.13/site-packages/nvidia/nvjitlink/lib/libnvJitLink.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/curand/lib/libcurand.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/cusparse/lib/libcusparse.so* runtime-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client_cu12.libs/libcares-*.so* runtime-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client.libs/libcares-*.so* runtime-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libcares-*.so* runtime-cu12/ mkdir release-cu13 cp gmscuopt-cu13.out release-cu13/gmscuopt.out cp assets/* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcuopt_mathopt.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client/lib64/libcuopt_client.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libgomp-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client_cu13.libs/libgomp-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client.libs/libgomp-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libtbb-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libtbbmalloc-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcudss_mtlayer_cuopt.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libcudart-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_mathopt.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_client.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libgomp-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libtbb-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libtbbmalloc-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcudss_mtlayer_cuopt.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libcudart-*.so* release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/rapids_logger/lib64/librapids_logger.so release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/librmm/lib64/librmm.so release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/nccl/lib/libnccl.so* release-cu13/ @@ -117,8 +109,7 @@ jobs: cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcurand.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcusolver.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcusparse.so* runtime-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client_cu13.libs/libcares-*.so* runtime-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client.libs/libcares-*.so* runtime-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libcares-*.so* runtime-cu13/ # Upload artifacts - name: Upload CUDA 12 link artifact to GitHub Actions (always) diff --git a/.github/workflows/main-x86_64.yml b/.github/workflows/main-x86_64.yml index aac532a..66485ed 100644 --- a/.github/workflows/main-x86_64.yml +++ b/.github/workflows/main-x86_64.yml @@ -44,25 +44,23 @@ jobs: - name: Compile GAMS/cuOpt-link binary "gmscuopt.out" for CUDA 12 and then for CUDA 13 run: | export GAMSCAPI="gamsdist/apifiles/C/api" - export CUOPT="venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt" + export CUOPT="venvs/cu12/lib/python3.13/site-packages/libcuopt" export JITLINK="venvs/cu12/lib/python3.13/site-packages/nvidia/nvjitlink/lib" export CUOPT_VERSION="`cat "$CUOPT/VERSION"`" export CUOPT_HASH="`cat "$CUOPT/GIT_COMMIT"`" gcc -Wall gmscuopt.c -o gmscuopt-cu12.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I $GAMSCAPI $GAMSCAPI/gmomcc.c $GAMSCAPI/optcc.c $GAMSCAPI/gevmcc.c \ - -I $CUOPT/include -I venvs/cu12/lib/python3.13/site-packages/libcuopt_client/include $JITLINK/libnvJitLink.so.12 -L $CUOPT/lib64 -lcuopt_mathopt \ - -L venvs/cu12/lib/python3.13/site-packages/libcuopt_client/lib64 -lcuopt_client + -I $CUOPT/include $JITLINK/libnvJitLink.so.12 -L $CUOPT/lib64 -lcuopt_mathopt patchelf --set-rpath \$ORIGIN gmscuopt-cu12.out - export CUOPT="venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt" + export CUOPT="venvs/cu13/lib/python3.13/site-packages/libcuopt" export JITLINK="venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib" export CUOPT_VERSION="`cat "$CUOPT/VERSION"`" export CUOPT_HASH="`cat "$CUOPT/GIT_COMMIT"`" gcc -Wall gmscuopt.c -o gmscuopt-cu13.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I $GAMSCAPI $GAMSCAPI/gmomcc.c $GAMSCAPI/optcc.c $GAMSCAPI/gevmcc.c \ - -I $CUOPT/include -I venvs/cu13/lib/python3.13/site-packages/libcuopt_client/include $JITLINK/libnvJitLink.so.13 -L $CUOPT/lib64 -lcuopt_mathopt \ - -L venvs/cu13/lib/python3.13/site-packages/libcuopt_client/lib64 -lcuopt_client + -I $CUOPT/include $JITLINK/libnvJitLink.so.13 -L $CUOPT/lib64 -lcuopt_mathopt patchelf --set-rpath \$ORIGIN gmscuopt-cu13.out # Collect dependencies for link and runtime convenience archive @@ -71,16 +69,13 @@ jobs: mkdir release-cu12 cp gmscuopt-cu12.out release-cu12/gmscuopt.out cp assets/* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcuopt_mathopt.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client/lib64/libcuopt_client.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libgomp-*.so* release-cu12/ - # Both suffixed and unsuffixed client wheels may own libcuopt_client.so; ship either wheel's OpenMP runtime. - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client_cu12.libs/libgomp-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client.libs/libgomp-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libtbb-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libtbbmalloc-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcudss_mtlayer_cuopt.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libcudart-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_mathopt.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_client.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libgomp-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libtbb-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libtbbmalloc-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcudss_mtlayer_cuopt.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libcudart-*.so* release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/rapids_logger/lib64/librapids_logger.so release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/librmm/lib64/librmm.so release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/nccl/lib/libnccl.so* release-cu12/ @@ -92,20 +87,17 @@ jobs: cp venvs/cu12/lib/python3.13/site-packages/nvidia/nvjitlink/lib/libnvJitLink.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/curand/lib/libcurand.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/cusparse/lib/libcusparse.so* runtime-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client_cu12.libs/libcares-*.so* runtime-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client.libs/libcares-*.so* runtime-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libcares-*.so* runtime-cu12/ mkdir release-cu13 cp gmscuopt-cu13.out release-cu13/gmscuopt.out cp assets/* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcuopt_mathopt.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client/lib64/libcuopt_client.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libgomp-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client_cu13.libs/libgomp-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client.libs/libgomp-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libtbb-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libtbbmalloc-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcudss_mtlayer_cuopt.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libcudart-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_mathopt.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_client.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libgomp-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libtbb-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libtbbmalloc-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcudss_mtlayer_cuopt.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libcudart-*.so* release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/rapids_logger/lib64/librapids_logger.so release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/librmm/lib64/librmm.so release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/nccl/lib/libnccl.so* release-cu13/ @@ -117,8 +109,7 @@ jobs: cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcurand.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcusolver.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcusparse.so* runtime-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client_cu13.libs/libcares-*.so* runtime-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client.libs/libcares-*.so* runtime-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libcares-*.so* runtime-cu13/ # Upload artifacts - name: Upload CUDA 12 link artifact to GitHub Actions (always) diff --git a/build-link.sh b/build-link.sh index b9840ba..bbdc987 100755 --- a/build-link.sh +++ b/build-link.sh @@ -6,7 +6,8 @@ set -e # Users can export these before running the script, otherwise defaults are used. GAMSDIST="${GAMSDIST:-$HOME/gamsdist}" WORKSPACE="${WORKSPACE:-$(pwd)}" -# Read build provenance from the mathopt wheel unless explicitly overridden below. +CUOPT_VERSION="${CUOPT_VERSION:-26.08}" +CUOPT_HASH="${CUOPT_HASH:-12345}" # 2. Dynamically find the site-packages directory to avoid hardcoding the Python version # or the venv directory name (some setups use "venv", others "uv"-style ".venv"). @@ -26,10 +27,8 @@ fi # 3. Export specific build paths export GAMSCAPI="$GAMSDIST/apifiles/C/api" -export CUOPT="$SITE_PACKAGES/libcuopt_mathopt" +export CUOPT="$SITE_PACKAGES/libcuopt" export JITLINK="$SITE_PACKAGES/nvidia/cu13/lib" -CUOPT_VERSION="${CUOPT_VERSION:-$(<"$CUOPT/VERSION")}" -CUOPT_HASH="${CUOPT_HASH:-$(<"$CUOPT/GIT_COMMIT")}" echo "Building GAMS cuOpt solver link..." echo "Using GAMSDIST: $GAMSDIST" @@ -40,9 +39,8 @@ gcc -g3 -O0 -Wall gmscuopt.c -o gmscuopt-cu13.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" \ -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I "$GAMSCAPI" "$GAMSCAPI/gmomcc.c" "$GAMSCAPI/optcc.c" "$GAMSCAPI/gevmcc.c" \ - -I "$CUOPT/include" -I "$SITE_PACKAGES/libcuopt_client/include" "$JITLINK/libnvJitLink.so.13" \ - -L "$CUOPT/lib64" -lcuopt_mathopt \ - -L "$SITE_PACKAGES/libcuopt_client/lib64" -lcuopt_client + -I "$CUOPT/include" "$JITLINK/libnvJitLink.so.13" \ + -L "$CUOPT/lib64" -lcuopt_mathopt # 5. Patch RPATH patchelf --set-rpath \$ORIGIN gmscuopt-cu13.out @@ -56,15 +54,12 @@ mkdir -p "$GAMSDIST" mv gmscuopt-cu13.out "$GAMSDIST/gmscuopt.out" cp "$CUOPT/lib64/libcuopt_mathopt.so" "$GAMSDIST/" -cp "$SITE_PACKAGES/libcuopt_client/lib64/libcuopt_client.so" "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_mathopt_cu13.libs/libgomp-*.so* "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_client_cu13.libs/libgomp-*.so* "$GAMSDIST/" -# The unsuffixed client wheel can also be installed and owns the same library path. -cp "$SITE_PACKAGES"/libcuopt_client.libs/libgomp-*.so* "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_mathopt_cu13.libs/libtbb-*.so* "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_mathopt_cu13.libs/libtbbmalloc-*.so* "$GAMSDIST/" -cp "$CUOPT/lib64/libcudss_mtlayer_cuopt.so" "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_mathopt_cu13.libs/libcudart-*.so* "$GAMSDIST/" +cp "$CUOPT/lib64/libcuopt_client.so" "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libgomp-*.so* "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libtbb-*.so* "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libtbbmalloc-*.so* "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt/lib64/libcudss_mtlayer_cuopt.so "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libcudart-*.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/rapids_logger/lib64/librapids_logger.so "$GAMSDIST/" cp "$SITE_PACKAGES"/librmm/lib64/librmm.so "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcudss.so* "$GAMSDIST/" @@ -74,8 +69,7 @@ cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcublasLt.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcurand.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcusolver.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcusparse.so* "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_client_cu13.libs/libcares-*.so* "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_client.libs/libcares-*.so* "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libcares-*.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/nccl/lib/libnccl.so* "$GAMSDIST/" # Copy assets (suppress errors if directory is empty or missing) From ba4488731cdfe2a797cd625e05a2b7fe725f4037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Sun, 4 Oct 2026 10:38:45 +0200 Subject: [PATCH 19/19] ci: pin libcuopt to last pre-modular nightly 26.10.0a223 --- .github/workflows/main-arm64.yml | 4 ++-- .github/workflows/main-x86_64.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main-arm64.yml b/.github/workflows/main-arm64.yml index c457b12..0cc310a 100644 --- a/.github/workflows/main-arm64.yml +++ b/.github/workflows/main-arm64.yml @@ -28,9 +28,9 @@ jobs: run: | mkdir -p venvs uv venv venvs/cu12 - uv pip install --python venvs/cu12 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'cuopt-cu12>=26.10.0a0' -qq + uv pip install --python venvs/cu12 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-cu12==26.10.0a223.post261002122804' -qq uv venv venvs/cu13 - uv pip install --python venvs/cu13 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'cuopt-cu13>=26.10.0a0' -qq + uv pip install --python venvs/cu13 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-cu13==26.10.0a223.post261002122804' -qq # Get GAMS (ARM64 version) - name: Download and extract latest GAMS distribution diff --git a/.github/workflows/main-x86_64.yml b/.github/workflows/main-x86_64.yml index 66485ed..4b1f3dc 100644 --- a/.github/workflows/main-x86_64.yml +++ b/.github/workflows/main-x86_64.yml @@ -28,9 +28,9 @@ jobs: run: | mkdir -p venvs uv venv venvs/cu12 - uv pip install --python venvs/cu12 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'cuopt-cu12>=26.10.0a0' -qq + uv pip install --python venvs/cu12 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-cu12==26.10.0a223.post261002122804' -qq uv venv venvs/cu13 - uv pip install --python venvs/cu13 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'cuopt-cu13>=26.10.0a0' -qq + uv pip install --python venvs/cu13 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-cu13==26.10.0a223.post261002122804' -qq # Get GAMS - name: Download and extract latest GAMS distribution