cuopt-numerical-optimization-api-python
cuopt-numerical-optimization-api-python について
NVIDIA cuOptでLP、MILP、QPをモデリングして解くPythonスキルです。問題と変数の種類の選択、APIの利用、ソルバー状態の確認、一般的なモデリングパターンを案内します。
主な機能
- 01LP、MILP、QPのモデリング
- 02問題と変数の種類の選択
- 03ソルバー設定の構成
- 04ソルバー状態と双対値の確認
- 05一般的なモデリングパターンの利用
活用シーン
- 01生産計画や施設選択のモデリング
- 02ポートフォリオや最小二乗QPの求解
- 03実行不可能または非有界なモデルの診断
- 04大規模な線形式の構築
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ promptingcompany/ nv-skills --skill cuopt-numerical-optimization-api-pythonインストール後、Claude Code で/cuopt-numerical-optimization-api-pythonを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
BENCHMARK.mdskill-card.mdskill.oms.sigassets/README.mdassets/least_squares/model.pyREADME.mdassets/lp_basic/model.pyREADME.mdassets/lp_duals/model.pyREADME.mdassets/lp_warmstart/model.pyREADME.mdassets/maximization_workaround/model.pyREADME.mdassets/milp_basic/incumbent_callback.pymodel.pyREADME.mdassets/milp_production_planning/model.pyREADME.mdassets/mps_solver/model.pyREADME.mdresults.mdassets/mps_solver/data/README.mdsample.mpsassets/portfolio/model.pyREADME.mdbenchmark/evals.jsonSOURCES.mdevals/evals.jsonreferences/qp_examples.md詳細
cuOpt 数値最適化スキル(Python)
NVIDIA cuOpt の GPU アクセラレーション対応ソルバーを使用して、LP、MILP、QP の問題をモデル化して解きます。Python API の構成(Problem、SolverSettings、solve)は3種類の問題クラスで共通であり、異なるのは目的関数の形式といくつかのルールだけです。
開始する前に
利用可能であれば定式化の概要(パラメーター、制約、決定変数、目的関数)を使用してください。ない場合は、決定変数、目的関数、制約を尋ねてください。その後、問題の種類(LP/MILP/QP — 以下を参照)と変数の型を確認してください。
LP、MILP、QP の選び方
目的関数と変数から判断します。
| 目的関数が…… | 変数が…… | 使用するもの |
|---|---|---|
線形(c_i * x_i の合計) | すべて連続変数 | LP |
| 線形 | 整数変数またはバイナリ変数を含む | MILP |
二乗(x*x)または交差(x*y)項を含む | 連続変数(整数 QP はサポートされません) | QP(ベータ版) |
問題が許す場合は、LP を優先してください。LP はより速く解け、最適性の保証も強力です。問題の性質上、整数値やはい/いいえの判断が必要な場合に限り、MILP を使用してください。目的関数が真に二次形式(分散、二乗誤差、運動エネルギー)の場合に限り、QP を使用してください。
特に注意が必要な問題の種類: 複数期間の計画と目標計画は、誤解しやすい問題です。レートと制約が適切な期間または優先度に適用されていることを再確認してください(AGENTS.md:コードを書く前に理解を確認してください)。
- LP を使用するのは、すべての量を意味のある形で小数にできる場合です。例:フロー、比率、レート、金額、時間、材料のトン数など。
- MILP を使用するのは、問題に離散的な対象の個数、はい/いいえの選択、またはどちらか一方の判断が含まれる場合です(例:施設を開設するかどうか、人をシフトに割り当てる、トラックの台数)。
- QP を使用するのは、目的関数で分散、二乗誤差、または
x*xやx*y項を含む式を最小化する場合です(ポートフォリオ最適化、最小二乗法、正則化回帰)。
説明から整数変数か連続変数かを判断する
問題で説明されている内容に基づいて、変数の型を選んでください。
| 問題の説明/概念 | 変数の型 | 例 |
|---|---|---|
| 離散的な対象(個数) | INTEGER | 作業員、自動車、トラック、機械、パイロット、施設、製造するユニット(「ユニット」が個別の品目を意味する場合)、研修生、車両 |
| はい/いいえ、またはオン/オフ | INTEGER(バイナリ、lb=0 ub=1) | 施設を開設する、機械を稼働させる、製品ラインを生産する、人をシフトに割り当てる |
| 小数にできる量 | CONTINUOUS | トン、リットル、金額、時間、kWh、容量に対する割合、フロー量、重量 |
| レートまたは割合 | CONTINUOUS | 利用率、パーセンテージ、予算に占める割合 |
| 不明確 | 名詞が数えられるもの(作業員、自動車など)なら INTEGER を優先し、測定量(鋼材の量、労働時間など)なら CONTINUOUS を優先してください。「全体の」「整数の」「個数」と明示されている場合は INTEGER を使用します。 |
目安: 量が「いくつの もの か」(人、車両、品目、場所)を示すなら、INTEGER を使用してください。「どれだけの量か」(質量、体積、金額、時間)を示す場合、またはレートの場合は、問題で整数値が明示的に求められていない限り、CONTINUOUS を使用してください。
クイックリファレンス:Python API
LP の例
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 の例(整数変数を含む)
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 の例(ベータ版 — MINIMIZE のみ)
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 のルール:
- MINIMIZE のみ — 二次目的関数で MAXIMIZE を指定すると、ソルバーは拒否します。
f(x)を最大化するには、-f(x)を最小化してください。 - 連続変数のみ — 整数 QP はサポートされていません。
- 凸問題では Q は PSD(半正定値)である必要があります。そうでない場合、ソルバーが最適ではない停留点を返すことがあります。
- ベータ版 — API は変更される可能性があります。一般的な凸 QP では本番環境で利用できる品質として扱えますが、時折変更があることを想定してください。
最小二乗法、最大化の代替方法、行列形式の例については、references/qp_examples.md を参照してください。
重要:ステータスの確認
ステータス値には PascalCase を使用します。すべて大文字ではありません:
# ✅ 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 のステータス値: 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 が PSD であることと、変数のスケールが適切であることを確認してください。
よくあるモデリングパターン
バイナリ選択
# 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 によるリンク
# 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))
「〜するなら、〜も必ず生産する」という条件
問題文に「X を行うなら Y も必ず行う」とある場合は、(i)バイナリ変数のリンクと(ii)Y が実際に生産されることの両方を制約してください:
# 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
そうしないと、ソルバーは y_Y=1 かつ production_Y=0 に設定できてしまい、バイナリ変数のリンクは満たすものの、本来の意図に沿わない結果になります。
大きな式の構築
多数の項を + で連結すると、API の再帰制限に達することがあります。目的関数と制約の構築には、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)
例については、このスキルの assets/ にある参照モデルを参照してください。
区分線形(SOS2)
# Approximate nonlinear function with breakpoints
# Use lambda variables that sum to 1, at most 2 adjacent non-zero
ソルバーの設定
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)
よくある問題
| 問題 | 考えられる原因 | 解決方法 |
|---|---|---|
| ステータスが常に "OPTIMAL" になる | 大文字・小文字の指定が誤っている | "OPTIMAL" ではなく "Optimal" を使用する |
| 整数変数の値が小数になる | CONTINUOUS として定義されている | vtype=INTEGER を使用する |
| 実行不可能 | 制約が競合している | 制約のロジックを確認する |
| 非有界 | 上下限が設定されていない | 変数の上下限を追加する |
| 解くのに時間がかかる | 問題が大きい | 時間制限を設定し、ギャップ許容値を大きくする |
| 最大再帰深度 | 大きな式を + で連結している | LinearExpression(vars_list, coeffs_list, constant) を使用する |
| MAXIMIZE を指定した QP が拒否される | QP は MINIMIZE のみをサポートしている | 目的関数を反転し、-f(x) を最小化する |
| QP が最適解を返さない | Q が PSD でない、または変数のスケールが適切でない | Q が PSD であることを確認し、変数のスケールを同程度に調整する |
双対値の取得(LP/QP)
双対値と縮約費用は LP と QP で返されます。二次制約を含む問題では返されず(すべての値が NaN になります)、制約がすべて線形の場合にのみ取得してください。MILP では双対値は返されません。
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
参照モデル
すべての参照モデルは、このスキルの assets/ ディレクトリにあります。新しいアプリケーションを構築する際の参考にしてください。参照モデル自体は編集しないでください。
最小/標準的な例(LP、MILP、QP)
| モデル | 種類 | 説明 |
|---|---|---|
| lp_basic | LP | 最小限の LP:変数、制約、目的関数、求解 |
| lp_duals | LP | 双対値と縮約費用 |
| lp_warmstart | LP | 類似問題のための PDLP ウォームスタート |
| milp_basic | MILP | 最小限の MIP。暫定解コールバックの例を含む |
| milp_production_planning | MILP | リソース制約を含む生産計画 |
| portfolio | QP | ポートフォリオの分散を最小化。予算と最小リターンの制約を含む |
| least_squares | QP | (x-3)² + (y-4)² を最小化(最も近い点) |
| maximization_workaround | QP | -f(x) を最小化して二次関数を最大化 |
その他の参照モデル
| モデル | 種類 | 説明 |
|---|---|---|
| mps_solver | LP/MILP | 標準 MPS ファイル形式の任意の問題を解く |
モデルを一覧表示する簡単なコマンド: ls assets/(このスキルのディレクトリから実行)。
エスカレーションする場合
次の場合は、トラブルシューティングと診断のガイダンスを利用してください:
- 実行不可能で、その理由を特定できない
- 数値上の問題がある