Describe the bug
With multi-GPU PDLP (method=PDLP, num_gpus=-1 or > 1) and presolve off, an LP created with the C API function cuOptCreateProblem (row types + RHS) reaches the solver with 0 constraints. cuOptSolve then fails with CUOPT_VALIDATION_ERROR (4) ("Distributed PDLP from mps requires at least one constraint"). The same LP created with cuOptCreateRangedProblem solves fine, and so does single-GPU PDLP with either form.
CC @mlubin @Bubullzz
Steps/Code to reproduce bug
Reproduces on a single GPU, since num_gpus=-1 means "all visible GPUs" and still selects the multi-GPU PDLP path.
Minimal reproducible example multi-gpu-bug.c:
/* Multi-GPU PDLP (presolve off) sees 0 constraints for problems created with
* cuOptCreateProblem (row types + RHS).
* LP: min -x - y s.t. x + y <= 1, 0 <= x, y <= 10 (optimum -1) */
#include <cuopt/mathematical_optimization/cuopt_c.h>
#include <stdio.h>
int main(void)
{
cuopt_int_t offsets[] = {0, 2}, indices[] = {0, 1};
cuopt_float_t values[] = {1.0, 1.0}, obj[] = {-1.0, -1.0};
cuopt_float_t lb[] = {0.0, 0.0}, ub[] = {10.0, 10.0};
char vtypes[] = {CUOPT_CONTINUOUS, CUOPT_CONTINUOUS};
char sense[] = {CUOPT_LESS_THAN};
cuopt_float_t rhs[] = {1.0};
cuOptOptimizationProblem problem;
cuOptSolverSettings settings;
cuOptSolution solution;
/* Works with the ranged form instead:
* cuopt_float_t row_lb[] = {-CUOPT_INFINITY}, row_ub[] = {1.0};
* cuOptCreateRangedProblem(..., row_lb, row_ub, lb, ub, vtypes, &problem); */
cuOptCreateProblem(1, 2, CUOPT_MINIMIZE, 0.0, obj, offsets, indices, values,
sense, rhs, lb, ub, vtypes, &problem);
cuopt_int_t num_constraints = -1;
cuOptGetNumConstraints(problem, &num_constraints);
printf("Num constraints in problem = %d\n", num_constraints);
cuOptCreateSolverSettings(&settings);
cuOptSetIntegerParameter(settings, CUOPT_METHOD, CUOPT_METHOD_PDLP);
cuOptSetIntegerParameter(settings, CUOPT_PRESOLVE, CUOPT_PRESOLVE_OFF);
/* all visible GPUs (-1) => multi-GPU PDLP codepath */
cuOptSetIntegerParameter(settings, CUOPT_NUM_GPUS, -1);
printf("cuOptSolve status = %d\n", cuOptSolve(problem, settings, &solution));
return 0;
}
Build and run:
gcc multi-gpu-bug.c -o multi-gpu-bug -I$LIBCUOPT/include -L$LIBCUOPT/lib64 -lcuopt -Wl,-rpath,$LIBCUOPT/lib64
./multi-gpu-bug
Output:
Num constraints in problem = 1
cuOpt version: 26.10.0, git hash: a42e4ca6, host arch: x86_64, device archs: 75-real,80-real,86-real,90a-real,100f-real,120a-real,120
CPU: 13th Gen Intel(R) Core(TM) i7-13700H, threads: 10C/20T, RAM usage: 2.13/23.47GiB
CPU SIMD target: AVX2
CUDA 13.3, device: NVIDIA RTX A1000 6GB Laptop GPU (ID 0), VRAM: 6.00 GiB
CUDA device UUID: 542ae55e-08e0-0257-e3e5-6ac1f557fd25
Solving a problem with 0 constraints, 2 variables (0 integers), and 2 nonzeros
Solving with distributed PDLP on 1 GPUs.
cuOptSolve status = 4
With cuOptCreateRangedProblem, or with num_gpus=1, the solver reports 1 constraint and finds the optimum of -1.
Expected behavior
Multi-GPU PDLP should accept constraints given as row types + RHS, the same way single-GPU PDLP does. For example, op_problem_to_mps_data_model() could build constraint lower/upper bounds from row types + RHS when they are empty, like set_bounds_if_not_set() does.
Separately, the validation message isn't printed: cuOptSolve returns 4, but "Distributed PDLP from mps requires at least one constraint" never appears in the log.
Environment details:
- System: WSL2, Ubuntu 26.04.1 LTS, x86_64, NVIDIA RTX A1000 6GB Laptop GPU, driver 597.16, CUDA 13.3
- Method of cuOpt install: pip, nightly wheels
cuopt-cu13 / libcuopt-cu13 26.10.0a222.post261002050825 (git hash a42e4ca), used through the C API
- Beware my machine is only single GPU but looking at
solve.cu it appears num_gpus=-1 is enough to make cuOpt exercise the multi GPU codepath.
Additional context
We hit this (see here) in the GAMS/cuOpt link, which uses the C API with multi GPU support added in #1958. Our workaround is to always build the problem with cuOptCreateRangedProblem, as otherwise it would only work fine with num_gpus=1.
Describe the bug
With multi-GPU PDLP (
method=PDLP,num_gpus=-1or> 1) and presolve off, an LP created with the C API functioncuOptCreateProblem(row types + RHS) reaches the solver with 0 constraints.cuOptSolvethen fails withCUOPT_VALIDATION_ERROR(4) ("Distributed PDLP from mps requires at least one constraint"). The same LP created withcuOptCreateRangedProblemsolves fine, and so does single-GPU PDLP with either form.CC @mlubin @Bubullzz
Steps/Code to reproduce bug
Reproduces on a single GPU, since
num_gpus=-1means "all visible GPUs" and still selects the multi-GPU PDLP path.Minimal reproducible example
multi-gpu-bug.c:Build and run:
Output:
With
cuOptCreateRangedProblem, or withnum_gpus=1, the solver reports 1 constraint and finds the optimum of -1.Expected behavior
Multi-GPU PDLP should accept constraints given as row types + RHS, the same way single-GPU PDLP does. For example,
op_problem_to_mps_data_model()could build constraint lower/upper bounds from row types + RHS when they are empty, likeset_bounds_if_not_set()does.Separately, the validation message isn't printed:
cuOptSolvereturns 4, but "Distributed PDLP from mps requires at least one constraint" never appears in the log.Environment details:
cuopt-cu13/libcuopt-cu1326.10.0a222.post261002050825(git hash a42e4ca), used through the C APIsolve.cuit appearsnum_gpus=-1is enough to make cuOpt exercise the multi GPU codepath.Additional context
We hit this (see here) in the GAMS/cuOpt link, which uses the C API with multi GPU support added in #1958. Our workaround is to always build the problem with
cuOptCreateRangedProblem, as otherwise it would only work fine withnum_gpus=1.