Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions skills/cuopt-numerical-optimization-api-c/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ QP uses the same library, include/lib paths, and build pattern as LP/MILP — on
- **Continuous variables only** — set `CUOPT_CONTINUOUS` for every variable; integer QP is not supported.
- **Q should be PSD** for a convex problem.

## Dual values (LP / QP)

`cuOptGetDualSolution` (shadow prices) and `cuOptGetReducedCosts` (reduced costs) return values
for **LP and QP with linear constraints** — the barrier solver is primal-dual, so a quadratic
objective still yields duals. cuOpt returns **no duals for a problem with quadratic constraints**
(the returned arrays are filled with `NaN`). See [assets/lp_duals](assets/lp_duals/) for the call
sequence — it is an LP, but the same calls apply to a QP whose constraints are all linear.

## Debugging (MPS / C)

**MPS parsing:** Required sections in order: NAME, ROWS, COLUMNS, RHS, (optional) BOUNDS, ENDATA. Integer markers: `'MARKER'`, `'INTORG'`, `'INTEND'`.
Expand Down
5 changes: 5 additions & 0 deletions skills/cuopt-numerical-optimization-api-c/assets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ LP/MILP C API reference implementations. Use as reference when building new appl
| [milp_production_planning](milp_production_planning/) | MILP | Production planning with resource constraints |
| [mps_solver](mps_solver/) | LP/MILP | Solve from MPS file via `cuOptReadProblem` |

> **Duals:** `lp_duals` is an LP, but `cuOptGetDualSolution` / `cuOptGetReducedCosts` also return
> shadow prices and reduced costs for a **QP with linear constraints** (the barrier solver is
> primal-dual). No duals are returned for problems with **quadratic constraints** — the arrays
> come back filled with `NaN`.

## Build and run

Set include and library paths, then build and run.
Expand Down
12 changes: 9 additions & 3 deletions skills/cuopt-numerical-optimization-api-python/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,12 +253,18 @@ settings.set_parameter("log_to_console", 1)
| QP rejected with MAXIMIZE | QP only supports MINIMIZE | Negate the objective: minimize `-f(x)` |
| QP returns non-optimal | Q not PSD or variables badly scaled | Check Q is PSD; rescale variables to similar magnitudes |

## Getting Dual Values (LP only)
## Getting Dual Values (LP / QP)

Shadow prices (`DualValue`) and reduced costs (`ReducedCost`) are returned for **LP and QP** —
cuOpt's barrier solver is primal-dual, so a QP with a quadratic objective and **linear**
constraints returns duals just like an LP. The constraints you read duals from must be linear:
cuOpt returns **no dual variables for a problem that has any quadratic constraint** (every
`DualValue`/`ReducedCost` comes back as `NaN`). MILP returns no duals.

```python
if problem.Status.name == "Optimal":
constraint = problem.getConstraint("resource_a")
shadow_price = constraint.DualValue
constraint = problem.getConstraint("resource_a") # linear constraint
shadow_price = constraint.DualValue # NaN if the model has quadratic constraints
print(f"Shadow price: {shadow_price}")
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,36 @@ if problem.Status.name == "Optimal":
print(f"Objective = {problem.ObjValue:.4f}")
```

## Reading Duals from a QP

A QP with **linear** constraints returns shadow prices and reduced costs just like an LP
(cuOpt's barrier solver is primal-dual). A quadratic *objective* is fine; a quadratic
*constraint* is not — cuOpt returns **no duals for a problem with quadratic constraints**
(every `DualValue`/`ReducedCost` is `NaN`), so read duals only when all constraints are linear.

```python
"""
minimize x² + y² + z²
subject to x + y + z == 10 (linear)
The equality's shadow price is the marginal change in the optimal objective
per unit increase of the right-hand side.
"""
from cuopt.linear_programming.problem import Problem, MINIMIZE

problem = Problem("QPDuals")
x = problem.addVariable(lb=0, name="x")
y = problem.addVariable(lb=0, name="y")
z = problem.addVariable(lb=0, name="z")
problem.setObjective(x*x + y*y + z*z, sense=MINIMIZE)
problem.addConstraint(x + y + z == 10, name="budget")
problem.solve()

if problem.Status.name in ["Optimal", "PrimalFeasible"]:
for c in problem.getConstraints():
# 'budget' dual magnitude ≈ 6.667 (Δobjective per unit of the RHS)
print(f"{c.ConstraintName} DualValue = {c.DualValue}")
```

## Maximization Workaround

```python
Expand Down