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