MILP C API Examples#

Example With Data#

This example demonstrates how to use the MILP solver in C. More details on the API can be found in C API.

The example code is available at ../lp-milp/examples/simple_milp_example.c (download):

  1/*
  2 * SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  3 * SPDX-License-Identifier: Apache-2.0
  4 */
  5/*
  6 * Simple test program for cuOpt MILP solver
  7 */
  8
  9// Include the cuOpt linear programming solver header
 10#include <cuopt/linear_programming/cuopt_c.h>
 11#include <stdio.h>
 12#include <stdlib.h>
 13
 14// Convert termination status to string
 15const char* termination_status_to_string(cuopt_int_t termination_status)
 16{
 17  switch (termination_status) {
 18    case CUOPT_TERMINATION_STATUS_OPTIMAL:
 19      return "Optimal";
 20    case CUOPT_TERMINATION_STATUS_INFEASIBLE:
 21      return "Infeasible";
 22    case CUOPT_TERMINATION_STATUS_UNBOUNDED:
 23      return "Unbounded";
 24    case CUOPT_TERMINATION_STATUS_ITERATION_LIMIT:
 25      return "Iteration limit";
 26    case CUOPT_TERMINATION_STATUS_TIME_LIMIT:
 27      return "Time limit";
 28    case CUOPT_TERMINATION_STATUS_NUMERICAL_ERROR:
 29      return "Numerical error";
 30    case CUOPT_TERMINATION_STATUS_PRIMAL_FEASIBLE:
 31      return "Primal feasible";
 32    case CUOPT_TERMINATION_STATUS_FEASIBLE_FOUND:
 33      return "Feasible found";
 34    default:
 35      return "Unknown";
 36  }
 37}
 38
 39// Test simple MILP problem
 40cuopt_int_t test_simple_milp()
 41{
 42  cuOptOptimizationProblem problem = NULL;
 43  cuOptSolverSettings settings     = NULL;
 44  cuOptSolution solution           = NULL;
 45
 46  /* Solve the following MILP:
 47     minimize -0.2*x1 + 0.1*x2
 48     subject to:
 49     3.0*x1 + 4.0*x2 <= 5.4
 50     2.7*x1 + 10.1*x2 <= 4.9
 51     x1, x2 >= 0
 52     x1 is integer
 53     x2 is continuous
 54  */
 55
 56  cuopt_int_t num_variables   = 2;
 57  cuopt_int_t num_constraints = 2;
 58  cuopt_int_t nnz             = 4;
 59
 60  // CSR format constraint matrix
 61  // https://docs.nvidia.com/nvpl/latest/sparse/storage_format/sparse_matrix.html#compressed-sparse-row-csr
 62  // From the constraints:
 63  // 3.0*x1 + 4.0*x2 <= 5.4
 64  // 2.7*x1 + 10.1*x2 <= 4.9
 65  cuopt_int_t row_offsets[]    = {0, 2, 4};
 66  cuopt_int_t column_indices[] = {0, 1, 0, 1};
 67  cuopt_float_t values[]       = {3.0, 4.0, 2.7, 10.1};
 68
 69  // Objective coefficients
 70  // From the objective function: minimize -0.2*x1 + 0.1*x2
 71  // -0.2 is the coefficient of x1
 72  // 0.1 is the coefficient of x2
 73  cuopt_float_t objective_coefficients[] = {-0.2, 0.1};
 74
 75  // Constraint bounds
 76  // From the constraints:
 77  // 3.0*x1 + 4.0*x2 <= 5.4
 78  // 2.7*x1 + 10.1*x2 <= 4.9
 79  cuopt_float_t constraint_upper_bounds[] = {5.4, 4.9};
 80  cuopt_float_t constraint_lower_bounds[] = {-CUOPT_INFINITY, -CUOPT_INFINITY};
 81
 82  // Variable bounds
 83  // From the constraints:
 84  // x1, x2 >= 0
 85  cuopt_float_t var_lower_bounds[] = {0.0, 0.0};
 86  cuopt_float_t var_upper_bounds[] = {CUOPT_INFINITY, CUOPT_INFINITY};
 87
 88  // Variable types
 89  // x1 is integer
 90  // x2 is continuous
 91  char variable_types[] = {CUOPT_INTEGER, CUOPT_CONTINUOUS};
 92
 93  cuopt_int_t status;
 94  cuopt_float_t time;
 95  cuopt_int_t termination_status;
 96  cuopt_float_t objective_value;
 97
 98  printf("Creating and solving simple MILP problem...\n");
 99
100  // Create the problem
101  status = cuOptCreateRangedProblem(num_constraints,
102                                    num_variables,
103                                    CUOPT_MINIMIZE,
104                                    0.0,  // objective offset
105                                    objective_coefficients,
106                                    row_offsets,
107                                    column_indices,
108                                    values,
109                                    constraint_lower_bounds,
110                                    constraint_upper_bounds,
111                                    var_lower_bounds,
112                                    var_upper_bounds,
113                                    variable_types,
114                                    &problem);
115  if (status != CUOPT_SUCCESS) {
116    printf("Error creating problem: %d\n", status);
117    goto DONE;
118  }
119
120  // Create solver settings
121  status = cuOptCreateSolverSettings(&settings);
122  if (status != CUOPT_SUCCESS) {
123    printf("Error creating solver settings: %d\n", status);
124    goto DONE;
125  }
126
127  // Set solver parameters
128  status = cuOptSetFloatParameter(settings, CUOPT_MIP_ABSOLUTE_TOLERANCE, 0.0001);
129  if (status != CUOPT_SUCCESS) {
130    printf("Error setting optimality tolerance: %d\n", status);
131    goto DONE;
132  }
133
134  // Solve the problem
135  status = cuOptSolve(problem, settings, &solution);
136  if (status != CUOPT_SUCCESS) {
137    printf("Error solving problem: %d\n", status);
138    goto DONE;
139  }
140
141  // Get solution information
142  status = cuOptGetSolveTime(solution, &time);
143  if (status != CUOPT_SUCCESS) {
144    printf("Error getting solve time: %d\n", status);
145    goto DONE;
146  }
147
148  status = cuOptGetTerminationStatus(solution, &termination_status);
149  if (status != CUOPT_SUCCESS) {
150    printf("Error getting termination status: %d\n", status);
151    goto DONE;
152  }
153
154  status = cuOptGetObjectiveValue(solution, &objective_value);
155  if (status != CUOPT_SUCCESS) {
156    printf("Error getting objective value: %d\n", status);
157    goto DONE;
158  }
159
160  // Print results
161  printf("\nResults:\n");
162  printf("--------\n");
163  printf("Termination status: %s (%d)\n",
164         termination_status_to_string(termination_status),
165         termination_status);
166  printf("Solve time: %f seconds\n", time);
167  printf("Objective value: %f\n", objective_value);
168
169  // Get and print solution variables
170  cuopt_float_t* solution_values = (cuopt_float_t*)malloc(num_variables * sizeof(cuopt_float_t));
171  if (solution_values == NULL) {
172    printf("Error allocating solution values\n");
173    goto DONE;
174  }
175  status = cuOptGetPrimalSolution(solution, solution_values);
176  if (status != CUOPT_SUCCESS) {
177    printf("Error getting solution values: %d\n", status);
178    free(solution_values);
179    goto DONE;
180  }
181
182  printf("\nSolution: \n");
183  for (cuopt_int_t i = 0; i < num_variables; i++) {
184    printf("x%d = %f\n", i + 1, solution_values[i]);
185  }
186  free(solution_values);
187
188DONE:
189  cuOptDestroyProblem(&problem);
190  cuOptDestroySolverSettings(&settings);
191  cuOptDestroySolution(&solution);
192
193  return status;
194}
195
196int main()
197{
198  // Run the test
199  cuopt_int_t status = test_simple_milp();
200
201  if (status == CUOPT_SUCCESS) {
202    printf("\nTest completed successfully!\n");
203    return 0;
204  } else {
205    printf("\nTest failed with status: %d\n", status);
206    return 1;
207  }
208}

It is necessary to have the path for include and library dirs ready, if you know the paths, please add them to the path variables directly. Otherwise, run the following commands to find the path and assign it to the path variables. The following commands are for Linux and might fail in cases where the cuopt library is not installed or there are multiple cuopt libraries in the system.

If you have built it locally, libcuopt.so will be in the build directory cpp/build and include directoy would be cpp/include.

# Find the cuopt header file and assign to INCLUDE_PATH
INCLUDE_PATH=$(find / -name "cuopt_c.h" -path "*/linear_programming/*" -printf "%h\n" | sed 's/\/linear_programming//' 2>/dev/null)
# Find the libcuopt library and assign to LIBCUOPT_LIBRARY_PATH
LIBCUOPT_LIBRARY_PATH=$(find / -name "libcuopt.so" 2>/dev/null)

Build and run the example

# Build and run the example
gcc -I $INCLUDE_PATH -L $LIBCUOPT_LIBRARY_PATH -o simple_milp_example simple_milp_example.c -lcuopt
./simple_milp_example

You should see the following output:

Output#
 Creating and solving simple LP problem...
 Solving a problem with 2 constraints 2 variables (1 integers) and 4 nonzeros
 Objective offset 0.000000 scaling_factor 1.000000
 After trivial presolve updated 2 constraints 2 variables
 Running presolve!
 After trivial presolve updated 2 constraints 2 variables
 Solving LP root relaxation
 Scaling matrix. Maximum column norm 1.046542e+00
 Dual Simplex Phase 1
 Dual feasible solution found.
 Dual Simplex Phase 2
  Iter     Objective   Primal Infeas  Perturb  Time
     1 -2.00000000e-01 1.46434160e+00 0.00e+00 0.00

 Root relaxation solution found in 2 iterations and 0.00s
 Root relaxation objective -2.00000000e-01

 Optimal solution found at root node. Objective -2.0000000000000001e-01. Time 0.00.
 B&B added a solution to population, solution queue size 0 with objective -0.2
 Solution objective: -0.200000 , relative_mip_gap 0.000000 solution_bound -0.200000 presolve_time 0.041144 total_solve_time 0.000000 max constraint violation 0.000000 max int violation 0.000000 max var bounds violation 0.000000 nodes 0 simplex_iterations 0

 Results:
 --------
 Termination status: Optimal (1)
 Solve time: 0.000000 seconds
 Objective value: -0.200000

 Solution:
 x1 = 1.000000
 x2 = 0.000000

 Test completed successfully!

Example With MPS File#

This example demonstrates how to use the cuOpt solver in C to solve an MPS file.

The example code is available at examples/milp_mps_example.c (download):

  1/*
  2 * SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  3 * SPDX-License-Identifier: Apache-2.0
  4 */
  5/*
  6 * Example program for solving MPS files with cuOpt MILP solver
  7 */
  8
  9#include <cuopt/linear_programming/cuopt_c.h>
 10#include <stdio.h>
 11#include <stdlib.h>
 12
 13const char* termination_status_to_string(cuopt_int_t termination_status)
 14{
 15  switch (termination_status) {
 16    case CUOPT_TERMINATION_STATUS_OPTIMAL:
 17      return "Optimal";
 18    case CUOPT_TERMINATION_STATUS_INFEASIBLE:
 19      return "Infeasible";
 20    case CUOPT_TERMINATION_STATUS_UNBOUNDED:
 21      return "Unbounded";
 22    case CUOPT_TERMINATION_STATUS_ITERATION_LIMIT:
 23      return "Iteration limit";
 24    case CUOPT_TERMINATION_STATUS_TIME_LIMIT:
 25      return "Time limit";
 26    case CUOPT_TERMINATION_STATUS_NUMERICAL_ERROR:
 27      return "Numerical error";
 28    case CUOPT_TERMINATION_STATUS_PRIMAL_FEASIBLE:
 29      return "Primal feasible";
 30    case CUOPT_TERMINATION_STATUS_FEASIBLE_FOUND:
 31      return "Feasible found";
 32    case CUOPT_TERMINATION_STATUS_UNBOUNDED_OR_INFEASIBLE:
 33      return "Unbounded or infeasible";
 34    default:
 35      return "Unknown";
 36  }
 37}
 38
 39cuopt_int_t solve_mps_file(const char* filename)
 40{
 41  cuOptOptimizationProblem problem = NULL;
 42  cuOptSolverSettings settings     = NULL;
 43  cuOptSolution solution           = NULL;
 44  cuopt_int_t status;
 45  cuopt_float_t time;
 46  cuopt_int_t termination_status;
 47  cuopt_float_t objective_value;
 48  cuopt_int_t num_variables;
 49  cuopt_float_t* solution_values = NULL;
 50
 51  printf("Reading and solving MPS file: %s\n", filename);
 52
 53  // Create the problem from MPS file
 54  status = cuOptReadProblem(filename, &problem);
 55  if (status != CUOPT_SUCCESS) {
 56    printf("Error creating problem from MPS file: %d\n", status);
 57    goto DONE;
 58  }
 59
 60  // Get problem size
 61  status = cuOptGetNumVariables(problem, &num_variables);
 62  if (status != CUOPT_SUCCESS) {
 63    printf("Error getting number of variables: %d\n", status);
 64    goto DONE;
 65  }
 66
 67  // Create solver settings
 68  status = cuOptCreateSolverSettings(&settings);
 69  if (status != CUOPT_SUCCESS) {
 70    printf("Error creating solver settings: %d\n", status);
 71    goto DONE;
 72  }
 73
 74  // Set solver parameters
 75  status = cuOptSetFloatParameter(settings, CUOPT_ABSOLUTE_PRIMAL_TOLERANCE, 0.0001);
 76  if (status != CUOPT_SUCCESS) {
 77    printf("Error setting optimality tolerance: %d\n", status);
 78    goto DONE;
 79  }
 80
 81  // Solve the problem
 82  status = cuOptSolve(problem, settings, &solution);
 83  if (status != CUOPT_SUCCESS) {
 84    printf("Error solving problem: %d\n", status);
 85    goto DONE;
 86  }
 87
 88  // Get solution information
 89  status = cuOptGetSolveTime(solution, &time);
 90  if (status != CUOPT_SUCCESS) {
 91    printf("Error getting solve time: %d\n", status);
 92    goto DONE;
 93  }
 94
 95  status = cuOptGetTerminationStatus(solution, &termination_status);
 96  if (status != CUOPT_SUCCESS) {
 97    printf("Error getting termination status: %d\n", status);
 98    goto DONE;
 99  }
100
101  const int has_primal_solution =
102    termination_status == CUOPT_TERMINATION_STATUS_OPTIMAL ||
103    termination_status == CUOPT_TERMINATION_STATUS_PRIMAL_FEASIBLE ||
104    termination_status == CUOPT_TERMINATION_STATUS_FEASIBLE_FOUND;
105
106  if (has_primal_solution) {
107    status = cuOptGetObjectiveValue(solution, &objective_value);
108    if (status != CUOPT_SUCCESS) {
109      printf("Error getting objective value: %d\n", status);
110      goto DONE;
111    }
112  }
113
114  // Print results
115  printf("\nResults:\n");
116  printf("--------\n");
117  printf("Number of variables: %d\n", num_variables);
118  printf("Termination status: %s (%d)\n",
119         termination_status_to_string(termination_status),
120         termination_status);
121  printf("Solve time: %f seconds\n", time);
122  printf("Objective value: %f\n", objective_value);
123
124  // Get and print solution variables
125  if (has_primal_solution) {
126  solution_values = (cuopt_float_t*)malloc(num_variables * sizeof(cuopt_float_t));
127  status          = cuOptGetPrimalSolution(solution, solution_values);
128  if (status != CUOPT_SUCCESS) {
129    printf("Error getting solution values: %d\n", status);
130    goto DONE;
131  }
132  }
133
134  printf("\nSolution: \n");
135  for (cuopt_int_t i = 0; i < num_variables; i++) {
136    printf("x%d = %f\n", i + 1, solution_values[i]);
137  }
138
139DONE:
140  if (solution_values != NULL) {
141    free(solution_values);
142  }
143  cuOptDestroyProblem(&problem);
144  cuOptDestroySolverSettings(&settings);
145  cuOptDestroySolution(&solution);
146
147  return status;
148}
149
150int main(int argc, char* argv[])
151{
152  if (argc != 2) {
153    printf("Usage: %s <mps_file_path>\n", argv[0]);
154    return 1;
155  }
156
157  // Run the solver
158  cuopt_int_t status = solve_mps_file(argv[1]);
159
160  if (status == CUOPT_SUCCESS) {
161    printf("\nSolver completed successfully!\n");
162    return 0;
163  } else {
164    printf("\nSolver failed with status: %d\n", status);
165    return 1;
166  }
167}

It is necessary to have the path for include and library dirs ready, if you know the paths, please add them to the path variables directly. Otherwise, run the following commands to find the path and assign it to the path variables. The following commands are for Linux and might fail in cases where the cuopt library is not installed or there are multiple cuopt libraries in the system.

If you have built it locally, libcuopt.so will be in the build directory cpp/build and include directoy would be cpp/include.

# Find the cuopt header file and assign to INCLUDE_PATH
INCLUDE_PATH=$(find / -name "cuopt_c.h" -path "*/linear_programming/*" -printf "%h\n" | sed 's/\/linear_programming//' 2>/dev/null)
# Find the libcuopt library and assign to LIBCUOPT_LIBRARY_PATH
LIBCUOPT_LIBRARY_PATH=$(find / -name "libcuopt.so" 2>/dev/null)

A sample MILP MPS file (download mip_sample.mps):

 1* Example 2.1 from N & W
 2* Optimal solution -28
 3NAME          EXAMPLE21
 4ROWS
 5 N  OBJ
 6 L  C1
 7 L  C2
 8 L  C3
 9COLUMNS
10  MARK0001  'MARKER'                 'INTORG'
11    X1        OBJ             -7
12    X1        C1              -1
13    X1        C2               5
14    X1        C3              -2
15    X2        OBJ             -2
16    X2        C1               2
17    X2        C2               1
18    X2        C3              -2
19  MARK0001  'MARKER'                 'INTEND'
20RHS
21    RHS       C1               4
22    RHS       C2              20
23    RHS       C3              -7
24BOUNDS
25 UP BOUND     X1               10
26 UP BOUND     X2               10
27ENDATA

Build and run the example

# Build and run the example
gcc -I $INCLUDE_PATH -L $LIBCUOPT_LIBRARY_PATH -o milp_mps_example milp_mps_example.c -lcuopt
./milp_mps_example mip_sample.mps

You should see the following output:

Output#
 Reading and solving MPS file: sample.mps
 Solving a problem with 3 constraints 2 variables (2 integers) and 6 nonzeros
 Objective offset 0.000000 scaling_factor 1.000000
 After trivial presolve updated 3 constraints 2 variables
 Running presolve!
 After trivial presolve updated 3 constraints 2 variables
 Solving LP root relaxation
 Scaling matrix. Maximum column norm 1.225464e+00
 Dual Simplex Phase 1
 Dual feasible solution found.
 Dual Simplex Phase 2
  Iter     Objective   Primal Infeas  Perturb  Time
     1 -3.04000000e+01 7.57868205e+00 0.00e+00 0.00

 Root relaxation solution found in 3 iterations and 0.00s
 Root relaxation objective -3.01818182e+01

 Strong branching on 2 fractional variables
 | Explored | Unexplored | Objective   |    Bound    | Depth | Iter/Node |  Gap   |    Time
         0        1                +inf  -3.018182e+01      1   0.0e+00       -        0.00
 B       3        1       -2.700000e+01  -2.980000e+01      2   6.7e-01     10.4%      0.00
 B&B added a solution to population, solution queue size 0 with objective -27
 B       4        0       -2.800000e+01  -2.980000e+01      2   7.5e-01      6.4%      0.00
 B&B added a solution to population, solution queue size 1 with objective -28
 Explored 4 nodes in 0.00s.
 Absolute Gap 0.000000e+00 Objective -2.8000000000000004e+01 Lower Bound -2.8000000000000004e+01
 Optimal solution found.
 Generated fast solution in 0.136067 seconds with objective -28.000000
 Solution objective: -28.000000 , relative_mip_gap 0.000000 solution_bound -28.000000 presolve_time 0.039433 total_solve_time 0.000000 max constraint violation 0.000000 max int violation 0.000000 max var bounds violation 0.000000 nodes 4 simplex_iterations 3

 Results:
 --------
 Number of variables: 2
 Termination status: Optimal (1)
 Solve time: 0.000000 seconds
 Objective value: -28.000000

 Solution:
 x1 = 4.000000
 x2 = 0.000000

 Solver completed successfully!