🔢cuopt-numerical-optimization-api-python
- プラグイン
- nvidia-skills
- ライセンス
- Apache-2.0
- ソース
- GitHub で見る ↗
説明
cuOptのPython API(プログラミング言語)を使用して、LP(線形計画問題)、MILP(整数計画問題)、QP(二次計画問題・ベータ版)などの最適化問題を解く 次のような場合に使用: 線形または二次の目的関数、整数変数を含む最適化、スケジューリング、ポートフォリオ最適化、最小二乗法などの問題解決
原文を表示
Solve LP, MILP, QP (beta) with cuOpt Python API — linear/quadratic objectives, integer variables, scheduling, portfolio, least squares.
ユースケース
- ✓線形または二次の目的関数の最適化問題を解く
- ✓整数変数を含む最適化問題を解く
- ✓スケジューリング問題を解く
- ✓ポートフォリオ最適化を行う
- ✓最小二乗法の問題を解く
本文(日本語訳)
cuOpt 数値最適化スキル(Python)
GPU加速ソルバーを使用して、NVIDIA cuOptで線形計画法(LP)、混合整数計画法(MILP)、二次計画法(QP)の問題をモデル化して解きます。Python APIの表面(Problem、SolverSettings、solve)は3つの問題タイプ全体で共通です。目的関数の形式と少しのルールだけが異なります。
始める前に
定式化の概要(パラメータ、制約、決定変数、目的関数)がある場合はそれを使用し、ない場合は決定変数、目的関数、制約を確認してください。その後、問題タイプ(LP / MILP / QP — 下記参照)と変数の種類を確認します。
LP vs MILP vs QP の選択
目的関数と変数から決めます:
| 目的関数が... | 変数が... | 使用するもの |
|---|---|---|
線形(c_i * x_i の合計) |
すべて連続 | LP |
| 線形 | 一部が整数またはバイナリ | MILP |
二乗項(x*x)または交差項(x*y)を含む |
連続(整数QPは未対応) | QP(ベータ版) |
問題が許すならLPを優先してください。 LPは高速に解け、より強い最適性保証があります。問題が論理的に整数値または yes/no の決定を必要とする場合のみMILPを使用してください。目的関数が真に二次式(分散、二乗誤差、運動エネルギーなど)の場合のみQPを使用してください。
特に注意が必要な問題タイプ: 複数期間の計画問題と目標計画法は誤解しやすいものです。レートと制約が正しい時間期間または優先度に適用されていることを再度確認してください(AGENTS.md を参照:コード作成前に理解を確認してください)。
- LP を使用 するのは、すべての量が意味のある小数値で表現できる場合:流量、比率、レート、金額、時間、材料のトン数など。
- MILP を使用 するのは、問題が離散的な単位の個数、yes/no選択、またはどちらか一方の決定を述べている場合(例:施設を開くかどうか、人員をシフトに割り当てるか、トラックの台数など)。
- QP を使用 するのは、目的関数が分散、二乗誤差、または
x*xまたはx*y項を含む式を最小化する場合(ポートフォリオ最適化、最小二乗法、正則化回帰など)。
文言から整数型か連続型かを判断
問題が述べている内容から変数の種類を選択してください。
| 問題の文言/概念 | 変数の種類 | 例 |
|---|---|---|
| 離散的な単位(個数) | 整数 | 作業者、車、トラック、機械、パイロット、施設、製造単位(「単位」が個別の品目を意味する場合)、研修生、車両 |
| yes/no またはオン/オフ | 整数(バイナリ、下限=0 上限=1) | 施設を開く、機械を稼動させる、製品ラインを生産する、人員をシフトに割り当てる |
| 小数値に意味がある量 | 連続 | トン、リットル、ドル、時間、kWh、容量に対する比率、流量、重量 |
| レートまたは分数 | 連続 | 稼働率、パーセンテージ、予算シェア |
| 不明確 | 名詞が数えられるもの(1人の作業者、1台の車)なら整数を優先;それが測定値(鋼の量、作業時間)なら連続を優先します。問題が「全数」「整数」「個数」と明記している場合は整数を使用します。 |
経験則: 量が「いくつの もの」(人、車両、品目、拠点など)を表す場合は整数を使用してください。「どのくらいの 量」(質量、体積、金額、時間)またはレートを表す場合は、問題が明確に整数を要求しない限り連続を使用してください。
クイックリファレンス:Python API
LP の例
from cuopt.linear_programming.problem import Problem, CONTINUOUS, MAXIMIZE
from cuopt.linear_programming.solver_settings import SolverSettings
# 問題を作成
problem = Problem("MyLP")
# 決定変数
x = problem.addVariable(lb=0, vtype=CONTINUOUS, name="x")
y = problem.addVariable(lb=0, vtype=CONTINUOUS, name="y")
# 制約
problem.addConstraint(2*x + 3*y <= 120, name="resource_a")
problem.addConstraint(4*x + 2*y <= 100, name="resource_b")
# 目的関数
problem.setObjective(40*x + 30*y, sense=MAXIMIZE)
# 解く
settings = SolverSettings()
settings.set_parameter("time_limit", 60)
problem.solve(settings)
# ステータスを確認(重要:大文字小文字を使い分ける!)
if problem.Status.name in ["Optimal", "PrimalFeasible"]:
print(f"目的関数値: {problem.ObjValue}")
print(f"x = {x.getValue()}")
print(f"y = {y.getValue()}")
MILP の例(整数変数付き)
from cuopt.linear_programming.problem import Problem, CONTINUOUS, INTEGER, MINIMIZE
problem = Problem("FacilityLocation")
# バイナリ変数(上限と下限が0〜1の整数)
open_facility = problem.addVariable(lb=0, ub=1, vtype=INTEGER, name="open")
# 連続変数
production = problem.addVariable(lb=0, vtype=CONTINUOUS, name="production")
# リンク制約:施設を開いた場合のみ生産可能
problem.addConstraint(production <= 1000 * open_facility, name="link")
# 目的関数:固定費 + 変動費
problem.setObjective(500*open_facility + 2*production, sense=MINIMIZE)
# MILP固有の設定
settings = SolverSettings()
settings.set_parameter("time_limit", 120)
settings.set_parameter("mip_relative_gap", 0.01) # 最適性ギャップ1%
problem.solve(settings)
# ステータスを確認
if problem.Status.name in ["Optimal", "FeasibleFound"]:
print(f"施設を開く: {open_facility.getValue() > 0.5}")
print(f"生産量: {production.getValue()}")
QP の例(ベータ版 — 最小化のみ)
from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE
from cuopt.linear_programming.solver_settings import SolverSettings
# ポートフォリオの分散最小化
problem = Problem("Portfolio")
x1 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_a")
x2 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_b")
x3 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_c")
# 二次目的関数(分散) — 最小化のみ
problem.setObjective(
0.04*x1*x1 + 0.02*x2*x2 + 0.01*x3*x3
+ 0.02*x1*x2 + 0.01*x1*x3 + 0.016*x2*x3,
sense=MINIMIZE,
)
# 線形制約
problem.addConstraint(x1 + x2 + x3 == 1, name="budget")
problem.addConstraint(0.12*x1 + 0.08*x2 + 0.05*x3 >= 0.08, name="min_return")
problem.solve(SolverSettings())
if problem.Status.name in ["Optimal", "PrimalFeasible"]:
print(f"分散: {problem.ObjValue}")
QP のルール:
- 最小化のみ — ソルバーは二次目的関数の最大化を拒否します。
f(x)を最大化するには、-f(x)を最小化してください。 - 連続変数のみ — 整数QPは未対応です。
- Q は半正定値 である必要があります(凸問題の場合)。そうでない場合、ソルバーは最適ではない停留点を返す可能性があります。
- ベータ版 — API は進化する可能性があります。典型的な凸QP本番環境では使用可能と見なしていますが、時々変更が予想されます。
詳しくは references/qp_examples.md の最小二乗法、最大化の回避方法、行列形式の例を参照してください。
重要:ステータスの確認
ステータス値は大文字小文字を区別します(すべて大文字ではありません):
# ✅ 正しい
if problem.Status.name in ["Optimal", "FeasibleFound"]:
print(problem.ObjValue)
# ❌ 間違い - 黙って失敗します!
if problem.Status.name == "OPTIMAL": # 合致しません!
print(problem.ObjValue)
LP ステータス値: Optimal、NoTermination、NumericalError、PrimalInfeasible、DualInfeasible、IterationLimit、TimeLimit、PrimalFeasible
MILP ステータス値: Optimal、FeasibleFound、Infeasible、Unbounded、TimeLimit、NoTermination
QP ステータス値: LP と同じセット。QP デバッグの場合は、f"Actual status: '{problem.Status.name}'" を出力して、Q が半正定値であり変数が適切にスケーリングされていることを確認してください。
よくあるモデリングパターン
バイナリ選択
# n個の中から正確にk個を選択
items = [problem.addVariable(lb=0, ub=1, vtype=INTEGER) for _ in range(n)]
problem.addConstraint(sum(items) == k)
ビッグM リンク
# y=1の場合、x <= 100;y=0の場合、xはMまで任意
M = 10000
problem.addConstraint(x <= 100 + M*(1 - y))
if-then「同時に実行する必要がある」
問題が「X をしたら Y も必ずしなければならない」と言っている場合、(i) バイナリリンクと (ii) Y が実際に実行されることの両方を強制してください:
# y_X <= y_Y (X をしたら、Y も「実行」する必要がある)
problem.addConstraint(y_X <= y_Y)
# Y が選択された場合のY生産量:y_Y=1の場合、最低1個(または最小量)を生産
problem.addConstraint(production_Y >= 1 * y_Y) # または min_amount * y_Y
そうしないと、ソルバーは y_Y=1 かつ production_Y=0 を設定でき、バイナリリンクを満たしますが意図を反映しません。
大きな式の構築
多くの項にわたるチェーン + は API の再帰制限に達する可能性があります。LinearExpression を使って目的関数と制約を構築してください:
from cuopt.linear_programming.problem import LinearExpression
# v1*c1 + v2*c2 + ... の代わりに (vars, coeffs) のリストとして構築
vars_list = [x, y, z]
coeffs_list = [
1.0,
2.0,
3.0,
]
expr = LinearExpression(vars_list, coeffs_list, constant=0.0)
problem.addConstraint(expr <= 100)
このスキルの assets/ にある参照モデルで例を確認してください。
区分線形(SOS2)
# 非線形関数をブレークポイントで近似
# 合計が1、隣接する最大2個が非ゼロのラムダ変数を使用
ソルバーの設定
settings = SolverSettings()
# 時間制限
settings.set_parameter("time_limit", 60)
# MILP ギャップ許容値(最適値の X% 以内で停止)
settings.set_parameter("mip_relative_gap", 0.01)
# ログ出力
settings.set_parameter("log_to_console", 1)
よくある問題
| 問題 | 原因の可能性 | 対処法 |
|---|---|---|
| ステータスが「Optimal」にならない | 間違った大文字小文字を使用 | "Optimal" を使用("OPTIMAL" ではない) |
| 整数変数に小数値がある | CONTINUOUS として定義されている | vtype=INTEGER を使用 |
| 実行不可 | 制約が矛盾している | 制約の論理を確認 |
| 無限 | 変数に境界がない | 変数の境界を追加 |
| 解が遅い | 大規模問題 | 時間制限を設定、ギャップ許容値を増加 |
| 最大再帰深度 | チ |
原文(English)を表示
cuOpt Numerical Optimization Skill (Python)
Model and solve LP, MILP, and QP problems using NVIDIA cuOpt's GPU-accelerated solver. The Python API surface (Problem, SolverSettings, solve) is shared across all three problem classes — only the objective form and a few rules change.
Before You Start
Use a formulation summary (parameters, constraints, decisions, objective) if available; otherwise ask for decision variables, objective, and constraints. Then confirm problem type (LP / MILP / QP — see below) and variable types.
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).
Problem types that need extra care: Multi-period planning and goal programming are easy to misinterpret. Double-check that rates and constraints apply to the right time period or priority level (AGENTS.md: verify understanding before code).
- 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
Choose variable type from what the problem describes.
| Problem wording / concept | Variable type | Examples |
|---|---|---|
| Discrete entities (counts) | INTEGER | Workers, cars, trucks, machines, pilots, facilities, units to manufacture (when "units" means whole items), trainees, vehicles |
| Yes/no or on/off | INTEGER (binary, lb=0 ub=1) | Open a facility, run a machine, produce a product line, assign a person to a shift |
| Amounts that can be fractional | CONTINUOUS | Tonnes, litres, dollars, hours, kWh, proportion of capacity, flow volume, weight |
| Rates or fractions | CONTINUOUS | Utilization, percentage, share of budget |
| Unclear | Prefer INTEGER if the noun is a countable thing (a worker, a car); prefer CONTINUOUS if it's a measure (amount of steel, hours worked). If the problem says "whole" or "integer" or "number of", use INTEGER. |
Rule of thumb: If the quantity is "how many things" (people, vehicles, items, sites), use INTEGER. If it's "how much" (mass, volume, money, time) or a rate, use CONTINUOUS unless the problem explicitly requires whole numbers.
Quick Reference: Python API
LP Example
from cuopt.linear_programming.problem import Problem, CONTINUOUS, MAXIMIZE
from cuopt.linear_programming.solver_settings import SolverSettings
# Create problem
problem = Problem("MyLP")
# Decision variables
x = problem.addVariable(lb=0, vtype=CONTINUOUS, name="x")
y = problem.addVariable(lb=0, vtype=CONTINUOUS, name="y")
# Constraints
problem.addConstraint(2*x + 3*y <= 120, name="resource_a")
problem.addConstraint(4*x + 2*y <= 100, name="resource_b")
# Objective
problem.setObjective(40*x + 30*y, sense=MAXIMIZE)
# Solve
settings = SolverSettings()
settings.set_parameter("time_limit", 60)
problem.solve(settings)
# Check status (CRITICAL: use PascalCase!)
if problem.Status.name in ["Optimal", "PrimalFeasible"]:
print(f"Objective: {problem.ObjValue}")
print(f"x = {x.getValue()}")
print(f"y = {y.getValue()}")
MILP Example (with integer variables)
from cuopt.linear_programming.problem import Problem, CONTINUOUS, INTEGER, MINIMIZE
problem = Problem("FacilityLocation")
# Binary variable (integer with bounds 0-1)
open_facility = problem.addVariable(lb=0, ub=1, vtype=INTEGER, name="open")
# Continuous variable
production = problem.addVariable(lb=0, vtype=CONTINUOUS, name="production")
# Linking constraint: can only produce if facility is open
problem.addConstraint(production <= 1000 * open_facility, name="link")
# Objective: fixed cost + variable cost
problem.setObjective(500*open_facility + 2*production, sense=MINIMIZE)
# MILP-specific settings
settings = SolverSettings()
settings.set_parameter("time_limit", 120)
settings.set_parameter("mip_relative_gap", 0.01) # 1% optimality gap
problem.solve(settings)
# Check status
if problem.Status.name in ["Optimal", "FeasibleFound"]:
print(f"Open facility: {open_facility.getValue() > 0.5}")
print(f"Production: {production.getValue()}")
QP Example (beta — MINIMIZE only)
from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE
from cuopt.linear_programming.solver_settings import SolverSettings
# Portfolio variance minimization
problem = Problem("Portfolio")
x1 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_a")
x2 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_b")
x3 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_c")
# Quadratic objective (variance) — MUST be MINIMIZE
problem.setObjective(
0.04*x1*x1 + 0.02*x2*x2 + 0.01*x3*x3
+ 0.02*x1*x2 + 0.01*x1*x3 + 0.016*x2*x3,
sense=MINIMIZE,
)
# Linear constraints
problem.addConstraint(x1 + x2 + x3 == 1, name="budget")
problem.addConstraint(0.12*x1 + 0.08*x2 + 0.05*x3 >= 0.08, name="min_return")
problem.solve(SolverSettings())
if problem.Status.name in ["Optimal", "PrimalFeasible"]:
print(f"Variance: {problem.ObjValue}")
QP rules:
- MINIMIZE only — solver rejects MAXIMIZE for quadratic objectives. To maximize
f(x), minimize-f(x). - Continuous variables only — integer QP is not supported.
- Q should be PSD (positive semi-definite) for a convex problem; otherwise the solver may return a non-optimal stationary point.
- Beta — API may evolve; treat as production-capable for typical convex QP but expect occasional changes.
See references/qp_examples.md for least-squares, maximization-workaround, and matrix-form examples.
CRITICAL: Status Checking
Status values use PascalCase, NOT ALL_CAPS:
# ✅ CORRECT
if problem.Status.name in ["Optimal", "FeasibleFound"]:
print(problem.ObjValue)
# ❌ WRONG - will silently fail!
if problem.Status.name == "OPTIMAL": # Never matches!
print(problem.ObjValue)
LP Status Values: Optimal, NoTermination, NumericalError, PrimalInfeasible, DualInfeasible, IterationLimit, TimeLimit, PrimalFeasible
MILP Status Values: Optimal, FeasibleFound, Infeasible, Unbounded, TimeLimit, NoTermination
QP Status Values: Same set as LP. For QP debugging, print f"Actual status: '{problem.Status.name}'" and check that Q is PSD and variables are reasonably scaled.
Common Modeling Patterns
Binary Selection
# Select exactly k items from n
items = [problem.addVariable(lb=0, ub=1, vtype=INTEGER) for _ in range(n)]
problem.addConstraint(sum(items) == k)
Big-M Linking
# If y=1, then x <= 100; if y=0, x can be anything up to M
M = 10000
problem.addConstraint(x <= 100 + M*(1 - y))
If-then "must also produce"
When the problem says if we do X then we must also do Y, enforce both (i) the binary link and (ii) that Y is actually produced:
# y_X <= y_Y (if we do X, we must "do" Y)
problem.addConstraint(y_X <= y_Y)
# Production of Y when Y is chosen: produce at least 1 (or a minimum) when y_Y=1
problem.addConstraint(production_Y >= 1 * y_Y) # or min_amount * y_Y
Otherwise the solver can set y_Y=1 but production_Y=0, satisfying the binary link but not the intent.
Building large expressions
Chained + over many terms can hit recursion limits in the API. Prefer building objectives and constraints with LinearExpression:
from cuopt.linear_programming.problem import LinearExpression
# Build as list of (vars, coeffs) instead of v1*c1 + v2*c2 + ...
vars_list = [x, y, z]
coeffs_list = [
1.0,
2.0,
3.0,
]
expr = LinearExpression(vars_list, coeffs_list, constant=0.0)
problem.addConstraint(expr <= 100)
See reference models in this skill's assets/ for examples.
Piecewise Linear (SOS2)
# Approximate nonlinear function with breakpoints
# Use lambda variables that sum to 1, at most 2 adjacent non-zero
Solver Settings
settings = SolverSettings()
# Time limit
settings.set_parameter("time_limit", 60)
# MILP gap tolerance (stop when within X% of optimal)
settings.set_parameter("mip_relative_gap", 0.01)
# Logging
settings.set_parameter("log_to_console", 1)
Common Issues
| Problem | Likely Cause | Fix |
|---|---|---|
| Status never "OPTIMAL" | Using wrong case | Use "Optimal" not "OPTIMAL" |
| Integer var has fractional value | Defined as CONTINUOUS | Use vtype=INTEGER |
| Infeasible | Conflicting constraints | Check constraint logic |
| Unbounded | Missing bounds | Add variable bounds |
| Slow solve | Large problem | Set time limit, increase gap tolerance |
| Maximum recursion depth | Building big expr with chained + |
Use LinearExpression(vars_list, coeffs_list, constant) |
| 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 / QP)
Duals and reduced costs are returned for LP and QP. They are not returned for a problem with quadratic constraints (every value comes back as NaN), so read them only when all constraints are linear. MILP returns no duals.
if problem.Status.name == "Optimal":
constraint = problem.getConstraint("resource_a") # linear constraint
print(f"Dual value: {constraint.DualValue}") # NaN if the model has quadratic constraints
Reference Models
All reference models live in this skill's assets/ directory. Use them as reference when building new applications; do not edit them in place.
Minimal / canonical examples (LP, MILP, QP)
| Model | Type | Description |
|---|---|---|
| lp_basic | LP | Minimal LP: variables, constraints, objective, solve |
| lp_duals | LP | Dual values and reduced costs |
| lp_warmstart | LP | PDLP warmstart for similar problems |
| milp_basic | MILP | Minimal MIP; includes incumbent callback example |
| milp_production_planning | MILP | Production planning with resource constraints |
| portfolio | QP | Minimize portfolio variance; budget and min-return constraints |
| least_squares | QP | Minimize (x-3)² + (y-4)² (closest point) |
| maximization_workaround | QP | Maximize quadratic via minimize -f(x) |
Other reference
| Model | Type | Description |
|---|---|---|
| mps_solver | LP/MILP | Solve any problem from standard MPS file format |
Quick command to list models: ls assets/ (from this skill's directory).
When to Escalate
Use troubleshooting and diagnostic guidance if:
- Infeasible and you can't determine why
- Numerical issues
原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。