Implement C APIs for adding quadratic objectives and constraints#1247
Implement C APIs for adding quadratic objectives and constraints#1247rg20 wants to merge 12 commits into
Conversation
|
/ok to test 7a67568 |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds C APIs ChangesIncremental quadratic objective and constraint addition
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
cpp/tests/linear_programming/c_api_tests/c_api_test.c (1)
1206-1392: ⚡ Quick winConsider adding edge case tests for the new incremental quadratic API.
The migrated tests cover the basic happy path but the new incremental workflow introduces edge cases that should be validated:
- Multiple calls: Calling
cuOptAddQuadraticObjectivemultiple times on the same problem (accumulation behavior)- Duplicate triplets: Same
(row, col)appearing multiple times in a single call- Empty entries: Calling with
num_entries=0- Off-diagonal terms: Quadratic terms like
x1*x2- QCQP constraints:
cuOptAddQuadraticConstrainthas no test coverageAs per coding guidelines, tests should "ensure coverage hits edge cases introduced by the new flow (e.g., multiple calls, duplicate (row,col) triplets, empty entries, and correct QCQP constraint behavior)."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cpp/tests/linear_programming/c_api_tests/c_api_test.c` around lines 1206 - 1392, The tests only cover the basic quadratic happy path; add new test cases (new functions or extending test_quadratic_problem/test_quadratic_ranged_problem) that exercise the incremental quadratic API edge cases: call cuOptAddQuadraticObjective multiple times on the same problem to verify accumulation behavior, submit duplicate (row,col) triplets in a single cuOptAddQuadraticObjective call to confirm they are summed/handled, call cuOptAddQuadraticObjective with num_entries=0 to ensure it is a no-op and returns success, include off-diagonal terms (e.g., Q entries for (0,1) and (1,0)) and verify solution/objective, and add tests for cuOptAddQuadraticConstraint (QCQP) using cuOptCreateProblem/cuOptCreateRangedProblem then cuOptSolve to check termination status and objective; in each test assert the returned status is CUOPT_SUCCESS, validate expected objective/termination values, and always call cuOptDestroyProblem/cuOptDestroySolverSettings/cuOptDestroySolution for cleanup.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cpp/include/cuopt/linear_programming/cuopt_c.h`:
- Around line 436-473: The PR adds new C ABI entry points
(cuOptAddQuadraticObjective and cuOptAddQuadraticConstraint) which expand the
public ABI surface; update the maintainer/action items by (1) confirming this
ABI change is intentional with the release manager, (2) adding an entry to the
project’s ABI/compatibility changelog and migration notes documenting these new
functions and their expected stability, and (3) tagging these declarations in
cuopt_c.h (or surrounding documentation) with an explicit note that they are
stable C ABI exports so reviewers know this was deliberate; reference the new
symbols cuOptAddQuadraticObjective and cuOptAddQuadraticConstraint when making
the changelog/migration entry.
In `@cpp/src/pdlp/cuopt_c.cpp`:
- Around line 539-563: Add a catch for std::exception in both extern "C" entry
points to prevent C++ exceptions escaping the C API: inside
cuOptAddQuadraticObjective (currently catching raft::exception) and likewise
inside cuOptAddQuadraticConstraint, append a catch(const std::exception& e) {
return CUOPT_INVALID_ARGUMENT; } (or equivalent) after the existing
raft::exception catch so any std::bad_alloc or other std::exception-derived
errors are handled and the function returns CUOPT_INVALID_ARGUMENT instead of
letting exceptions propagate.
In `@docs/cuopt/source/cuopt-c/lp-qp-milp/lp-qp-milp-c-api.rst`:
- Around line 54-58: Remove the inline deprecation note that mentions
cuOptCreateQuadraticProblem and cuOptCreateQuadraticRangedProblem from this rst
page and replace it with a short pointer to the centralized external docs policy
page; specifically, delete the block referencing cuOptCreateQuadraticProblem and
cuOptCreateQuadraticRangedProblem and instead add a single-sentence link or
reference directing readers to the external migration/deprecation guidance for
using cuOptCreateProblem / cuOptCreateRangedProblem and the recommended
cuOptAddQuadraticObjective (and cuOptAddQuadraticConstraint for QCQP) workflow.
---
Nitpick comments:
In `@cpp/tests/linear_programming/c_api_tests/c_api_test.c`:
- Around line 1206-1392: The tests only cover the basic quadratic happy path;
add new test cases (new functions or extending
test_quadratic_problem/test_quadratic_ranged_problem) that exercise the
incremental quadratic API edge cases: call cuOptAddQuadraticObjective multiple
times on the same problem to verify accumulation behavior, submit duplicate
(row,col) triplets in a single cuOptAddQuadraticObjective call to confirm they
are summed/handled, call cuOptAddQuadraticObjective with num_entries=0 to ensure
it is a no-op and returns success, include off-diagonal terms (e.g., Q entries
for (0,1) and (1,0)) and verify solution/objective, and add tests for
cuOptAddQuadraticConstraint (QCQP) using
cuOptCreateProblem/cuOptCreateRangedProblem then cuOptSolve to check termination
status and objective; in each test assert the returned status is CUOPT_SUCCESS,
validate expected objective/termination values, and always call
cuOptDestroyProblem/cuOptDestroySolverSettings/cuOptDestroySolution for cleanup.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 0452693c-7da8-4fd0-8824-7e13f30eb554
📒 Files selected for processing (4)
cpp/include/cuopt/linear_programming/cuopt_c.hcpp/src/pdlp/cuopt_c.cppcpp/tests/linear_programming/c_api_tests/c_api_test.cdocs/cuopt/source/cuopt-c/lp-qp-milp/lp-qp-milp-c-api.rst
| .. note:: | ||
| ``cuOptCreateQuadraticProblem`` and ``cuOptCreateQuadraticRangedProblem`` are deprecated. | ||
| Prefer ``cuOptCreateProblem`` or ``cuOptCreateRangedProblem`` followed by | ||
| ``cuOptAddQuadraticObjective`` (and ``cuOptAddQuadraticConstraint`` for QCQP). | ||
|
|
There was a problem hiding this comment.
Move this deprecation/migration note to external docs policy location.
Please avoid carrying deprecation/migration guidance inline here; keep this page concise and point to the external docs location instead.
Based on learnings: for RAPIDS/cuOpt, deprecation notices and migration guidance should live on the external docs site, not in-repo .rst docs.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/cuopt/source/cuopt-c/lp-qp-milp/lp-qp-milp-c-api.rst` around lines 54 -
58, Remove the inline deprecation note that mentions cuOptCreateQuadraticProblem
and cuOptCreateQuadraticRangedProblem from this rst page and replace it with a
short pointer to the centralized external docs policy page; specifically, delete
the block referencing cuOptCreateQuadraticProblem and
cuOptCreateQuadraticRangedProblem and instead add a single-sentence link or
reference directing readers to the external migration/deprecation guidance for
using cuOptCreateProblem / cuOptCreateRangedProblem and the recommended
cuOptAddQuadraticObjective (and cuOptAddQuadraticConstraint for QCQP) workflow.
|
|
||
| for (cuopt_int_t row = 0; row < num_rows; ++row) { | ||
| auto& entries = row_entries[row]; | ||
| std::sort(entries.begin(), entries.end()); |
There was a problem hiding this comment.
Do we need to sort here? That can be expensive. I'm not sure we require the entries to be sorted at this point.
| std::vector<cuopt_int_t>& indices, | ||
| std::vector<cuopt_float_t>& values) | ||
| { | ||
| std::map<triplet_key_t, cuopt_float_t, triplet_key_cmp_t> triplets; |
There was a problem hiding this comment.
I think this can be done more efficiently using an algorithm similar to the one below from:
https://github.com/DrTimothyAldenDavis/SuiteSparse/blob/dev/CSparse/Source/cs_compress.c
We can allocate a workspace w of size n inside cuOptOptimizationProblem to avoid the overhead of creating it each time.
cs *cs_compress (const cs *T)
{
csi m, n, nz, p, k, *Cp, *Ci, *w, *Ti, *Tj ;
double *Cx, *Tx ;
cs *C ;
if (!CS_TRIPLET (T)) return (NULL) ; /* check inputs */
m = T->m ; n = T->n ; Ti = T->i ; Tj = T->p ; Tx = T->x ; nz = T->nz ;
C = cs_spalloc (m, n, nz, Tx != NULL, 0) ; /* allocate result */
w = cs_calloc (n, sizeof (csi)) ; /* get workspace */
if (!C || !w) return (cs_done (C, w, NULL, 0)) ; /* out of memory */
Cp = C->p ; Ci = C->i ; Cx = C->x ;
for (k = 0 ; k < nz ; k++) w [Tj [k]]++ ; /* column counts */
cs_cumsum (Cp, w, n) ; /* column pointers */
for (k = 0 ; k < nz ; k++)
{
Ci [p = w [Tj [k]]++] = Ti [k] ; /* A(i,j) is the pth entry in C */
if (Cx) Cx [p] = Tx [k] ;
}
return (cs_done (C, w, NULL, 1)) ; /* success; free w and return C */
}
There was a problem hiding this comment.
Changed the implementation now
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
cpp/tests/linear_programming/c_api_tests/c_api_test.c (1)
1337-1375: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick winExercise non-trivial triplet assembly in one of these quadratic tests.
Both cases use already-sorted, duplicate-free diagonal triplets, so a bug in the new triplet-to-CSR merge/sort path would still pass. Please make at least one test use out-of-order triplets and/or duplicate
(row, col)entries that collapse to the sameQ, so the expected optimum stays unchanged while the conversion logic is actually exercised.♻️ Example tweak
- cuopt_int_t Q_row_index[] = {0, 1}; - cuopt_int_t Q_col_index[] = {0, 1}; - cuopt_float_t Q_coeff[] = {1.0, 4.0}; + cuopt_int_t Q_row_index[] = {1, 0, 1}; + cuopt_int_t Q_col_index[] = {1, 0, 1}; + cuopt_float_t Q_coeff[] = {1.5, 1.0, 2.5}; // duplicate (1,1), unsorted rows ... - status = cuOptAddQuadraticObjective(problem, 2, Q_row_index, Q_col_index, Q_coeff); + status = cuOptAddQuadraticObjective(problem, 3, Q_row_index, Q_col_index, Q_coeff);As per coding guidelines,
cpp/tests/**: "Numerical correctness validation (not just "runs without error")" and "When a bug fix lands, a regression test should cover the specific case."Also applies to: 1431-1467
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cpp/tests/linear_programming/c_api_tests/c_api_test.c` around lines 1337 - 1375, Current quadratic test uses already-sorted, unique diagonal triplets so the triplet-to-CSR merge/sort path isn't exercised; modify the test data passed to cuOptAddQuadraticObjective (Q_row_index, Q_col_index, Q_coeff) to include out-of-order entries and at least one duplicated (row,col) pair whose coefficients sum to the same final Q value (e.g., split a diagonal coefficient into two entries and place them non-sequentially), leaving the rest of the problem identical so the expected optimum remains unchanged; ensure the duplicated entries collapse correctly by keeping the same expected solution and verifying numerical correctness after calling cuOptAddQuadraticObjective.cpp/src/pdlp/cuopt_c.cpp (2)
267-278:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winReject negative dimensions and stop narrowing
cuopt_int_ttoint.Both constructors still use
num_constraints/num_variablesas array indices and vector sizes before proving they are non-negative, and the new validation/population loops narrownum_variablestoint. On 64-bit builds this can either walk pastINT_MAXincorrectly or, for negative counts, hit OOB reads / huge signed-to-size_tallocations instead of returningCUOPT_INVALID_ARGUMENT.As per coding guidelines: Flag missing input validation at library and server boundaries.
Also applies to: 300-303, 331-344, 367-376
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cpp/src/pdlp/cuopt_c.cpp` around lines 267 - 278, The code must validate num_variables and num_constraints are non-negative before using them as indices/sizes and must avoid narrowing cuopt_int_t to int in loops; add explicit checks that num_variables >= 0 and num_constraints >= 0 at the start of the constructor/validation functions (before any array accesses or vector allocations) and return CUOPT_INVALID_ARGUMENT if not, then change loops that currently use "for (int j = 0; j < num_variables; j++)" to use the original cuopt_int_t (or an unsigned size_t derived only after a signed non-negative check) when indexing variable_types and calling detail::is_valid_public_var_type_code, and apply the same pattern to the other mentioned ranges (the blocks around lines 300-303, 331-344, 367-376) so no signed-to-int narrowing or out-of-bounds accesses can occur.
625-644:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy liftAvoid copying all existing quadratic constraints on every append.
cuOptAddQuadraticConstraintcopies the entire existing quadratic-constraint vector, adds one entry, then writes the whole thing back. BuildingNquadratic constraints this way turns model construction into repeated deep copies of all priorQdata, which is exactly the bad case for an incremental QCQP API.As per coding guidelines: Flag excessive allocations in hot paths; prefer avoiding
O(n²)construction patterns when a scalable append path is available.
🧹 Nitpick comments (1)
cpp/include/cuopt/linear_programming/cuopt_c.h (1)
443-458: ⚡ Quick winDocument duplicate quadratic-triplet handling here too.
cuOptAddQuadraticConstraintgoes through the same COO accumulation path ascuOptAddQuadraticObjective, so repeated(row_index, col_index)pairs are summed before storage. Please state that in this docblock as well; right now the public contract is less precise than the implementation.As per coding guidelines: Verify parameter descriptions match actual types/behavior.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cpp/include/cuopt/linear_programming/cuopt_c.h` around lines 443 - 458, Update the cuOptAddQuadraticConstraint docblock to state that quadratic matrix entries provided in triplet/COO form (row_index, col_index, coeff) are accumulated/summed for duplicate (row_index, col_index) pairs before storage (same behavior as cuOptAddQuadraticObjective), and confirm the parameter descriptions reflect actual types and semantics used by the implementation (e.g., 0-based indices, lengths are quad_num_entries and num_lin_entries, and linear term uses parallel arrays linear_index/linear_coeff); adjust wording to match the implementation’s accumulation behavior and indexing conventions so the public contract is precise.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@cpp/src/pdlp/cuopt_c.cpp`:
- Around line 267-278: The code must validate num_variables and num_constraints
are non-negative before using them as indices/sizes and must avoid narrowing
cuopt_int_t to int in loops; add explicit checks that num_variables >= 0 and
num_constraints >= 0 at the start of the constructor/validation functions
(before any array accesses or vector allocations) and return
CUOPT_INVALID_ARGUMENT if not, then change loops that currently use "for (int j
= 0; j < num_variables; j++)" to use the original cuopt_int_t (or an unsigned
size_t derived only after a signed non-negative check) when indexing
variable_types and calling detail::is_valid_public_var_type_code, and apply the
same pattern to the other mentioned ranges (the blocks around lines 300-303,
331-344, 367-376) so no signed-to-int narrowing or out-of-bounds accesses can
occur.
In `@cpp/tests/linear_programming/c_api_tests/c_api_test.c`:
- Around line 1337-1375: Current quadratic test uses already-sorted, unique
diagonal triplets so the triplet-to-CSR merge/sort path isn't exercised; modify
the test data passed to cuOptAddQuadraticObjective (Q_row_index, Q_col_index,
Q_coeff) to include out-of-order entries and at least one duplicated (row,col)
pair whose coefficients sum to the same final Q value (e.g., split a diagonal
coefficient into two entries and place them non-sequentially), leaving the rest
of the problem identical so the expected optimum remains unchanged; ensure the
duplicated entries collapse correctly by keeping the same expected solution and
verifying numerical correctness after calling cuOptAddQuadraticObjective.
---
Nitpick comments:
In `@cpp/include/cuopt/linear_programming/cuopt_c.h`:
- Around line 443-458: Update the cuOptAddQuadraticConstraint docblock to state
that quadratic matrix entries provided in triplet/COO form (row_index,
col_index, coeff) are accumulated/summed for duplicate (row_index, col_index)
pairs before storage (same behavior as cuOptAddQuadraticObjective), and confirm
the parameter descriptions reflect actual types and semantics used by the
implementation (e.g., 0-based indices, lengths are quad_num_entries and
num_lin_entries, and linear term uses parallel arrays
linear_index/linear_coeff); adjust wording to match the implementation’s
accumulation behavior and indexing conventions so the public contract is
precise.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 3d07538f-7159-49e1-8b16-79c0a2ee5e4f
📒 Files selected for processing (4)
cpp/include/cuopt/linear_programming/cuopt_c.hcpp/src/pdlp/cuopt_c.cppcpp/tests/linear_programming/c_api_tests/c_api_test.cdocs/cuopt/source/cuopt-c/lp-qp-milp/lp-qp-milp-c-api.rst
✅ Files skipped from review due to trivial changes (1)
- docs/cuopt/source/cuopt-c/lp-qp-milp/lp-qp-milp-c-api.rst
|
|
||
| /** @brief Create an optimization problem of the form | ||
| * | ||
| * @deprecated Use ``cuOptCreateProblem`` to set up the linear problem, then |
There was a problem hiding this comment.
Are we allowed to use [[deprecated]]? It's a C23 feature.
There was a problem hiding this comment.
This is customer facing API. Not sure if we want to add this restriction on the version of C.
| using quadratic_constraint_t = | ||
| optimization_problem_interface_t<cuopt_int_t, cuopt_float_t>::quadratic_constraint_t; | ||
|
|
||
| std::vector<quadratic_constraint_t> constraints(op_problem->get_quadratic_constraints()); |
There was a problem hiding this comment.
I think this is making a copy of all the quadratic constraints each time we add a new constraint.
There was a problem hiding this comment.
You are right, I will implement a new C++ API for adding constraints
|
We should have test coverage for |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cpp/src/pdlp/cpu_optimization_problem.cpp`:
- Around line 189-193: The vector::assign calls on qc
(quadratic_values/quadratic_indices/quadratic_offsets/linear_values/linear_indices)
perform ptr and ptr+size pointer arithmetic even when the incoming pointer may
be nullptr for a zero size; guard each assignment with a size check (e.g., if
size_* > 0) and only call assign(ptr, ptr + size) in that case, otherwise clear
or assign an empty range to the corresponding qc container to avoid undefined
behavior from null-pointer arithmetic.
In `@cpp/src/pdlp/optimization_problem.cu`:
- Around line 261-265: The five unconditional vector assigns
(qc.quadratic_values.assign(quadratic_values, quadratic_values +
size_quadratic_values), qc.quadratic_indices.assign(...),
qc.quadratic_offsets.assign(...), qc.linear_values.assign(...),
qc.linear_indices.assign(...)) may pass null pointers when their corresponding
size_* is zero; guard each assign with an if (size_X > 0) check (e.g., if
(size_quadratic_values > 0) { qc.quadratic_values.assign(quadratic_values,
quadratic_values + size_quadratic_values); }) matching the existing pattern used
elsewhere so assign() is only called with valid non-null ranges.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: f1a45c67-dc86-4fd7-8fc5-bae4fd1f6c89
📒 Files selected for processing (6)
cpp/include/cuopt/linear_programming/cpu_optimization_problem.hppcpp/include/cuopt/linear_programming/optimization_problem.hppcpp/include/cuopt/linear_programming/optimization_problem_interface.hppcpp/src/pdlp/cpu_optimization_problem.cppcpp/src/pdlp/cuopt_c.cppcpp/src/pdlp/optimization_problem.cu
We support >= for quadratic constraints. We should also support general convex quadratic constraints. |
| if (row_a != row_b) { return row_a < row_b; } | ||
| return col_index[a] < col_index[b]; | ||
| }; | ||
| std::sort(perm.begin(), perm.end(), triplet_less); |
There was a problem hiding this comment.
This is O(nnz log nnz). That can be quite expensive. You can do a linear bucket sort here.
chris-maes
left a comment
There was a problem hiding this comment.
Let's get the complexity of COO to CSR down to O(n + nnz) before merging.
Can the barrier handle >= for quadratic constraints? The constraints become non-convex right? |
| perm[static_cast<size_t>(row_cursor[row]++)] = k; | ||
| } | ||
|
|
||
| // Per row: sort by column, merge duplicates, emit CSR. Row grouping is O(nnz + num_rows); |
There was a problem hiding this comment.
Do we need sorted columns in the CSR downstream?
If not, let's skip the sort. If so, the most efficient sort is to do a double transpose. Convert the CSR to CSC and then convert back to CSR.
There was a problem hiding this comment.
If we don't sort, then we can't handle the duplicates.
| std::sort(row_begin, row_end, col_less); | ||
|
|
||
| cuopt_int_t last_col = -1; | ||
| for (auto it = row_begin; it != row_end; ++it) { |
There was a problem hiding this comment.
I think this could be simplified to just
cuopt_int_t last_col = -1
for (cuopt_int idx = start; idx < end; idx++) {
const cuopt_int_t col = col_index[idx];
// ...
| for (auto it = row_begin; it != row_end; ++it) { | ||
| const cuopt_int_t idx = *it; | ||
| const cuopt_int_t col = col_index[idx]; | ||
| if (it != row_begin && col == last_col) { |
There was a problem hiding this comment.
if (idx != start && ...
|
|
||
| auto row_begin = perm.begin() + static_cast<ptrdiff_t>(start); | ||
| auto row_end = perm.begin() + static_cast<ptrdiff_t>(end); | ||
| std::sort(row_begin, row_end, col_less); |
There was a problem hiding this comment.
If you can avoid the sort, you can allocate a dense array of size n, then when looping over columns in a row, mark the column in the dense array. This allows you to detect duplicates. If you mark with the row number you do not need to clear the mark.
|
/ok to test 66626a3 |
|
/ok to test fdff245 |
Description
Adds a composable C API for building QP and QCQP models without growing the number of monolithic cuOptCreate* functions. Users create the linear problem with
cuOptCreateProblemorcuOptCreateRangedProblem, then attach quadratic objectives and constraints incrementally.Marks
cuOptCreateQuadraticProblemandcuOptCreateQuadraticRangedProblemas deprecated (runtime warnings + docs) and migrates existing C API QP tests to the new workflow.New APIs
cuOptAddQuadraticObjectiveAddsxT Q xusing coordinate (triplet) format (row_index, col_index, coeff).cuOptAddQuadraticConstraintAppends one constraintxT Q x + dT x <= / >= rhsTriplet input is converted to CSR internally before calling the optimization problem interface.
Deprecation
cuOptCreateQuadraticProblemandcuOptCreateQuadraticRangedProblemlogCUOPT_LOG_WARNon use with migration guidanceIssue
Checklist