Cuopt Numerical Optimization API
NVIDIAOfficialCreated by NVIDIA cuOpt Team
- Skill
- Tool integration
- Software development
- Apache-2.0
- Medium risk
- Has scripts
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The cuOpt Numerical Optimization API provides interfaces to model and solve Linear Programming (LP), Mixed-Integer Linear Programming (MILP), and Quadratic Programming (QP) problems. It supports integration through Python, C, and a command-line interface. The tool is designed to work as a standalone solver or as a backend for third-party modeling languages such as AMPL, GAMS, PuLP, JuMP, Pyomo, and CVXPY. It includes features for setting solver parameters like time limits and tolerances, and provides access to primal solutions, objective values, and dual solutions for supported problem types.
What it does
- Solves LP, MILP, and QP problems using a GPU-accelerated solver.
- Provides C and Python APIs for programmatic model definition and solving.
- Offers a command-line interface for solving problems from MPS, QPS, and LP files.
- Supports integration with third-party modeling tools like Pyomo, PuLP, and JuMP.
- Allows configuration of solver settings including time limits and gap tolerances.
- Retrieves primal solutions, objective values, and dual values for LP and QP models.
When to use it
- When you need to solve linear or quadratic optimization problems.
- When you are working with discrete entities or yes/no decisions requiring MILP.
- When you have an existing model in a third-party tool and need a solver backend.
- When you need to solve optimization problems from standard MPS or LP files via CLI.
Advantages
- Supports multiple interfaces including Python, C, and CLI.
- Compatible with common third-party modeling languages.
- Provides granular control over solver parameters and settings.
- Allows for programmatic export and import of standard optimization file formats.
Usage examples
- “How do I solve a linear programming problem using the C API?”
- The agent provides a code example using cuOptCreateRangedProblem and cuOptSolve, demonstrating how to define constraints and variables in C.
- “Can I use cuOpt with Pyomo?”
- The agent explains that cuOpt works as a solver backend for Pyomo and provides guidance on pointing the model's solver to cuOpt.
- “How do I run a solver on an MPS file?”
- The agent instructs the user to use the cuopt_cli command followed by the file path and any necessary flags for solver settings.
- “What is the difference between LP and MILP in cuOpt?”
- The agent clarifies that LP is for continuous variables while MILP is for discrete or binary variables, and explains the implications for dual values.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/nvidia/cuopt-numerical-optimization-api/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip cuopt-numerical-optimization-api.zip -d .agents/skills
Documentation by NVIDIA cuOpt Team
cuOpt Numerical Optimization API
Model and solve LP, MILP, and QP problems using NVIDIA cuOpt's GPU-accelerated solver.
Interface Selection
Choose the reference for the user's interface:
| Interface | When to use | Reference |
|---|---|---|
| Python | User is writing Python code | references/python_api.md |
| C / C++ | User is embedding in a C/C++ application | references/c_api.md |
| CLI | User is solving from MPS files on the command line | references/cli_api.md |
If the interface is not yet clear, ask before writing any code.
Already using a modeling language? cuOpt also works as a solver backend for third-party modeling tools — AMPL, GAMS / GAMSPy, PuLP, JuMP, Pyomo, and CVXPY — with near-zero code changes (point the model's solver at cuOpt). CVXPY additionally covers convex QP and, in beta, QCQP / SOCP. Prefer this when the user already has a model in one of these tools rather than porting it to the cuOpt API. See Third-Party Modeling Languages.
Choosing LP vs MILP vs QP
Decide from the objective and variables:
| If the objective is... | And variables are... | Use |
|---|---|---|
Linear (sum of c_i * x_i) | All continuous | LP |
| Linear | Some integer or binary | MILP |
Has squared (x*x) or cross (x*y) terms | Continuous (integer QP not supported) | QP (beta) |
Prefer LP when the problem allows it. LP solves faster and has stronger optimality guarantees. Use MILP only when the problem logically requires whole numbers or yes/no decisions. Use QP only when the objective is genuinely quadratic (variance, squared error, kinetic energy).
Use LP when every quantity can meaningfully be fractional: flows, proportions, rates, dollars, hours, tonnes of material, etc.
Use MILP when the problem mentions counts of discrete entities, yes/no choices, or either/or decisions (e.g. open a facility or not, assign a person to a shift, number of trucks).
Use QP when the objective minimizes variance, squared error, or any expression with
x*xorx*yterms (portfolio optimization, least squares, regularized regression).
Integer vs Continuous from Wording
| Problem wording / concept | Variable type | Examples |
|---|---|---|
| Discrete entities (counts) | INTEGER | Workers, cars, trucks, machines, pilots, facilities, units to manufacture |
| Yes/no or on/off | INTEGER (binary, lb=0 ub=1) | Open a facility, run a machine, assign a person to a shift |
| Amounts that can be fractional | CONTINUOUS | Tonnes, litres, dollars, hours, kWh, proportion of capacity |
| Rates or fractions | CONTINUOUS | Utilization, percentage, share of budget |
Rule of thumb: "How many things" → INTEGER. "How much" → CONTINUOUS.
QP Rules (all interfaces)
MINIMIZE only — the solver rejects MAXIMIZE for quadratic objectives. To maximize
f(x), minimize-f(x)and negate the reported objective value.Continuous variables only — integer QP is not supported.
Q should be positive semi-definite for a convex, well-posed problem.
Beta — API may evolve; treat as production-capable for typical convex QP.
Dual Values
Duals and reduced costs are available for LP and QP only:
MILP — no duals (integer optima are not continuous).
Quadratic constraints — duals unavailable even for LP/QP; all values return
NaN.PDLP warmstart — LP only; MILP solves do not accept a PDLP warmstart.
Common Issues (all interfaces)
| Problem | Likely cause | Fix |
|---|---|---|
| Infeasible | Conflicting constraints | Check constraint logic and bounds |
| Unbounded | Missing bounds | Add variable bounds |
| Slow solve | Large problem | Set time limit; increase gap tolerance |
| QP rejected with MAXIMIZE | QP only supports MINIMIZE | Negate the objective; negate the result |
| QP returns non-optimal | Q not PSD or badly scaled | Check Q is PSD; rescale variables |
Solver Settings (concepts)
| Setting | Purpose |
|---|---|
time_limit | Stop after N seconds |
mip_relative_gap | Stop MILP when within X% of optimal |
mip_absolute_tolerance | Absolute MIP gap stop |
log_to_console | Enable solver logging |
Syntax varies by interface — see the interface reference file.
Files
- ATTRIBUTION.mdAdded by AutoGineer965 B
- BENCHMARK.md4.8 KiB
- LICENSELicence file added by AutoGineer11.2 KiB
- SKILL.md4.8 KiB
- assets/c/README.md1.7 KiB
- assets/c/lp_basic/README.md466 B
- assets/c/lp_basic/lp_simple.c3.6 KiB
- assets/c/lp_duals/README.md500 B
- assets/c/lp_duals/lp_duals.c4.0 KiB
- assets/c/lp_warmstart/README.md289 B
- assets/c/milp_basic/README.md405 B
- assets/c/milp_basic/milp_simple.c3.4 KiB
- assets/c/milp_production_planning/README.md459 B
- assets/c/milp_production_planning/milp_production.c3.5 KiB
- assets/c/mps_solver/README.md590 B
- assets/c/mps_solver/data/sample.mps490 B
- assets/c/mps_solver/mps_solver.c3.4 KiB
- assets/cli/README.md856 B
- assets/cli/lp_production/README.md192 B
- assets/cli/lp_production/production.mps375 B
- assets/cli/lp_simple/README.md191 B
- assets/cli/lp_simple/sample.mps490 B
- assets/cli/milp_facility/README.md199 B
- assets/cli/milp_facility/facility.mps694 B
- assets/python/README.md581 B
- assets/python/least_squares/README.md136 B
- assets/python/least_squares/model.pyScript831 B
- assets/python/lp_basic/README.md207 B
- assets/python/lp_basic/model.pyScript1.1 KiB
- assets/python/lp_duals/README.md227 B
- assets/python/lp_duals/model.pyScript1.2 KiB
- assets/python/lp_warmstart/README.md140 B
- assets/python/lp_warmstart/model.pyScript1.8 KiB
- assets/python/maximization_workaround/README.md152 B
- assets/python/maximization_workaround/model.pyScript736 B
- assets/python/milp_basic/README.md433 B
- assets/python/milp_basic/incumbent_callback.pyScript1.8 KiB
- assets/python/milp_basic/model.pyScript1.2 KiB
- assets/python/milp_production_planning/README.md165 B
- assets/python/milp_production_planning/model.pyScript1.2 KiB
- assets/python/mps_solver/README.md2.2 KiB
- assets/python/mps_solver/data/README.md2.0 KiB
- assets/python/mps_solver/data/sample.mps490 B
- assets/python/mps_solver/model.pyScript8.2 KiB
- assets/python/mps_solver/results.md2.5 KiB
- assets/python/portfolio/README.md232 B
- assets/python/portfolio/model.pyScript1.6 KiB
- evals/evals.json13.7 KiB
- references/c_api.md4.7 KiB
- references/cli_api.md5.5 KiB
- references/python_api.md4.7 KiB
- references/qp_examples.md5.7 KiB
- skill-card.md4.3 KiB
- skill.oms.sig15.9 KiB
assets/python/mps_solver/model.py
# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
"""
MPS File Solver using cuOpt Python API
Read and solve LP/MILP problems from standard MPS files using
cuOpt's built-in readMPS method.
Default benchmark: air05.mps (airline crew scheduling from MIPLIB)
- Best known optimal: 26,374
"""
import os
import gzip
import urllib.request
from typing import Optional
from cuopt.linear_programming.problem import Problem
from cuopt.linear_programming.solver_settings import SolverSettings
# MIPLIB benchmark URL
AIR05_URL = "https://miplib.zib.de/WebData/instances/air05.mps.gz"
AIR05_OPTIMAL = 26374 # Best known optimal solution
def download_air05(data_dir: str) -> str:
"""Download air05.mps from MIPLIB if not present."""
mps_file = os.path.join(data_dir, "air05.mps")
if os.path.exists(mps_file):
return mps_file
os.makedirs(data_dir, exist_ok=True)
gz_file = os.path.join(data_dir, "air05.mps.gz")
print("Downloading air05.mps from MIPLIB...")
urllib.request.urlretrieve(AIR05_URL, gz_file)
# Decompress
print("Decompressing...")
with gzip.open(gz_file, "rb") as f_in:
with open(mps_file, "wb") as f_out:
f_out.write(f_in.read())
# Clean up
os.remove(gz_file)
print(f"Downloaded: {mps_file}")
return mps_file
def solve_mps(
filepath: str,
time_limit: float = 60.0,
mip_gap: float = 0.01,
verbose: bool = True,
) -> tuple:
"""
Solve an LP/MILP problem from an MPS file.
Parameters
----------
filepath : str
Path to the MPS file
time_limit : float
Solver time limit in seconds
mip_gap : float
MIP relative gap tolerance
verbose : bool
Print solver output
Returns
-------
tuple
(problem, solution_dict) or (problem, None) if no solution
"""
# Read MPS file directly (static method returns Problem object)
problem = Problem.readMPS(filepath)
print(f"Loaded MPS file: {filepath}")
print(f"Variables: {problem.NumVariables}")
print(f"Constraints: {problem.NumConstraints}")
print(f"Is MIP: {problem.IsMIP}")
# Solver settings
settings = SolverSettings()
settings.set_parameter("time_limit", time_limit)
settings.set_parameter("log_to_console", verbose)
settings.set_parameter("mip_relative_gap", mip_gap)
# Solve
print("\nSolving...")
problem.solve(settings)
# Extract solution
status = problem.Status.name
print(f"\nStatus: {status}")
if status in ["Optimal", "FeasibleFound", "PrimalFeasible"]:
solution = {
"status": status,
"objective": problem.ObjValue,
"num_variables": problem.NumVariables,
"num_constraints": problem.NumConstraints,
"is_mip": problem.IsMIP,
"mip_gap": mip_gap,
}
# Get variable values (use getVariables() for MPS-loaded problems)
var_values = {}
try:
variables = problem.getVariables()
for var in variables:
val = var.getValue()
if abs(val) > 1e-6: # Only include non-zero values
var_values[var.Name] = val
except (AttributeError, Exception):
# For MPS problems, variable access may be limited
pass
solution["variables"] = var_values
return problem, solution
else:
return problem, None
def compare_gaps(
filepath: str,
time_limit: float = 120.0,
known_optimal: Optional[float] = None,
) -> dict:
"""
Compare solutions at different MIP gap tolerances.
Parameters
----------
filepath : str
Path to the MPS file
time_limit : float
Solver time limit per run
known_optimal : float, optional
Known optimal objective value. If provided, results include
"gap_to_optimal" (percent above optimal). Omit for generic MPS files.
Returns
-------
dict
Results for each gap tolerance
"""
gaps = [0.01, 0.001] # 1% and 0.1%
results = {}
for gap in gaps:
print(f"\n{'=' * 60}")
print(f"Solving with MIP gap = {gap * 100}%")
print(f"{'=' * 60}")
problem, solution = solve_mps(
filepath=filepath, time_limit=time_limit, mip_gap=gap, verbose=True
)
if solution:
results[gap] = {
"objective": solution["objective"],
"status": solution["status"],
}
if known_optimal is not None:
results[gap]["gap_to_optimal"] = (
(solution["objective"] - known_optimal)
/ known_optimal
* 100
)
else:
results[gap] = {"objective": None, "status": "No solution"}
return results
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Solve LP/MILP from MPS file")
parser.add_argument(
"--file", type=str, default=None, help="Path to MPS file"
)
parser.add_argument(
"--time-limit", type=float, default=60.0, help="Solver time limit"
)
parser.add_argument(
"--mip-gap", type=float, default=0.01, help="MIP gap tolerance"
)
parser.add_argument(
"--compare", action="store_true", help="Compare 1%% vs 0.1%% gap"
)
parser.add_argument(
"--known-optimal",
type=float,
default=None,
help="Known optimal objective value (enables gap-to-optimal reporting)",
)
args = parser.parse_args()
print("=" * 60)
print("MPS File Solver using cuOpt")
print("=" * 60)
# Determine MPS file to use
script_dir = os.path.dirname(os.path.abspath(__file__))
data_dir = os.path.join(script_dir, "data")
if args.file:
mps_file = args.file
else:
# Download air05.mps if not present
mps_file = download_air05(data_dir)
# Use known optimal only when explicitly set or when using default air05
known_optimal = args.known_optimal
if known_optimal is None and mps_file.endswith("air05.mps"):
known_optimal = AIR05_OPTIMAL
if args.compare:
# Compare different gap tolerances
print(f"\nComparing MIP gap tolerances on: {mps_file}")
if known_optimal is not None:
print(f"Best known optimal: {known_optimal}")
results = compare_gaps(
mps_file, time_limit=args.time_limit, known_optimal=known_optimal
)
print()
print("=" * 60)
print("COMPARISON SUMMARY")
print("=" * 60)
if known_optimal is not None:
print(f"Best known optimal: {known_optimal}")
print()
header = f"{'Gap Tolerance':<15} {'Objective':<15}"
if known_optimal is not None:
header += f" {'Gap to Optimal':<15}"
print(header)
print("-" * (45 if known_optimal is None else 60))
for gap, result in sorted(results.items()):
if result["objective"] is not None:
line = f"{gap * 100:.1f}%{'':<12} {result['objective']:<15.0f}"
if known_optimal is not None:
line += f" {result['gap_to_optimal']:.2f}%"
print(line)
else:
print(f"{gap * 100:.1f}%{'':<12} {'No solution':<15}")
else:
# Single solve
print(f"\nMPS File: {mps_file}")
print(f"Time Limit: {args.time_limit}s")
print(f"MIP Gap: {args.mip_gap * 100}%")
print()
problem, solution = solve_mps(
filepath=mps_file,
time_limit=args.time_limit,
mip_gap=args.mip_gap,
verbose=True,
)
if solution:
print()
print("=" * 60)
print("SOLUTION")
print("=" * 60)
print(f"Status: {solution['status']}")
print(f"Objective Value: {solution['objective']:.0f}")
if known_optimal is not None:
print(f"Best Known Optimal: {known_optimal}")
print(
f"Gap to Optimal: {(solution['objective'] - known_optimal) / known_optimal * 100:.2f}%"
)
else:
print("\nNo feasible solution found.")
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs Python
Security
What our scanner noticed· Medium risk
- Large base64-encoded blobs
- Scripts that your agent may run
This skill includes scripts that your agent may run. Read them before you use it.
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- NVIDIA cuOpt Team
- Publisher
- NVIDIA (Official)
- Source
- NVIDIA/skills · skills/cuopt-numerical-optimization-api · commit fce3cca
- Licence
- Apache License 2.0 (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE-APACHE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by NVIDIA cuOpt Team or NVIDIA.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download cuopt-numerical-optimization-api.zip