cuopt-numerical-optimization-api-python

Par nvidia · skills

Résolvez des problèmes de programmation linéaire (LP), de programmation linéaire en nombres entiers mixtes (MILP) et de programmation quadratique (QP, bêta) avec l'API Python. À utiliser lorsque l'utilisateur pose des questions sur l'optimisation avec des objectifs linéaires ou quadratiques, des contraintes linéaires, des variables entières, la planification, l'allocation de ressources, la localisation d'installations, la planification de la production, l'optimisation de portefeuille ou les moindres carrés.

npx skills add https://github.com/nvidia/skills --skill cuopt-numerical-optimization-api-python

Compétence cuOpt Optimisation Numérique (Python)

Modélisez et résolvez des problèmes LP, MILP et QP à l'aide du solveur GPU-accéléré NVIDIA cuOpt. La surface d'API Python (Problem, SolverSettings, solve) est partagée entre les trois classes de problèmes — seule la forme objective et quelques règles changent.

Avant de commencer

Utilisez un résumé de formulation (paramètres, contraintes, décisions, objectif) s'il est disponible ; sinon, demandez les variables de décision, l'objectif et les contraintes. Puis confirmez le type de problème (LP / MILP / QP — voir ci-dessous) et les types de variables.

Choisir entre LP, MILP et QP

Décidez en fonction de l'objectif et des variables :

Si l'objectif est... Et les variables sont... Utilisez
Linéaire (somme de c_i * x_i) Toutes continues LP
Linéaire Certaines entières ou binaires MILP
Contient des termes au carré (x*x) ou croisés (x*y) Continues (QP entier non supporté) QP (bêta)

Préférez LP quand le problème le permet. LP se résout plus rapidement et offre des garanties d'optimalité plus fortes. Utilisez MILP uniquement quand le problème nécessite logiquement des nombres entiers ou des décisions oui/non. Utilisez QP uniquement quand l'objectif est véritablement quadratique (variance, erreur quadratique, énergie cinétique).

Types de problèmes nécessitant une attention particulière : La planification multi-période et la programmation par objectifs sont faciles à mal interpréter. Vérifiez deux fois que les taux et contraintes s'appliquent à la bonne période ou au bon niveau de priorité (AGENTS.md : vérifiez la compréhension avant le code).

  • Utilisez LP quand chaque quantité peut être fractionnaire : flux, proportions, taux, dollars, heures, tonnes de matière, etc.
  • Utilisez MILP quand le problème mentionne des comptes d'entités discrètes, des choix oui/non, ou des décisions soit/soit (par exemple ouvrir une installation ou non, assigner une personne à un quart, nombre de camions).
  • Utilisez QP quand l'objectif minimise la variance, l'erreur quadratique, ou toute expression avec des termes x*x ou x*y (optimisation de portefeuille, moindres carrés, régression régularisée).

Entier vs continu selon le libellé

Choisissez le type de variable en fonction de ce que le problème décrit.

Libellé du problème / concept Type de variable Exemples
Entités discrètes (comptes) INTEGER Travailleurs, voitures, camions, machines, pilotes, installations, unités à fabriquer (quand « unités » signifie des articles entiers), stagiaires, véhicules
Oui/non ou marche/arrêt INTEGER (binaire, lb=0 ub=1) Ouvrir une installation, faire fonctionner une machine, produire une gamme de produits, assigner une personne à un quart
Montants pouvant être fractionnaires CONTINUOUS Tonnes, litres, dollars, heures, kWh, proportion de capacité, volume de flux, poids
Taux ou fractions CONTINUOUS Utilisation, pourcentage, part du budget
Unclear Préférez INTEGER si le nom est une chose dénombrable (un travailleur, une voiture) ; préférez CONTINUOUS s'il s'agit d'une mesure (quantité d'acier, heures travaillées). Si le problème dit « entier » ou « nombre de », utilisez INTEGER.

Règle empirique : Si la quantité est « combien de choses » (personnes, véhicules, articles, sites), utilisez INTEGER. Si c'est « combien » (masse, volume, argent, temps) ou un taux, utilisez CONTINUOUS sauf si le problème exige explicitement des nombres entiers.

Référence rapide : API Python

Exemple LP

from cuopt.linear_programming.problem import Problem, CONTINUOUS, MAXIMIZE
from cuopt.linear_programming.solver_settings import SolverSettings

# Créer un problème
problem = Problem("MyLP")

# Variables de décision
x = problem.addVariable(lb=0, vtype=CONTINUOUS, name="x")
y = problem.addVariable(lb=0, vtype=CONTINUOUS, name="y")

# Contraintes
problem.addConstraint(2*x + 3*y <= 120, name="resource_a")
problem.addConstraint(4*x + 2*y <= 100, name="resource_b")

# Objectif
problem.setObjective(40*x + 30*y, sense=MAXIMIZE)

# Résoudre
settings = SolverSettings()
settings.set_parameter("time_limit", 60)
problem.solve(settings)

# Vérifier le statut (CRITIQUE : utilisez PascalCase !)
if problem.Status.name in ["Optimal", "PrimalFeasible"]:
    print(f"Objective: {problem.ObjValue}")
    print(f"x = {x.getValue()}")
    print(f"y = {y.getValue()}")

Exemple MILP (avec variables entières)

from cuopt.linear_programming.problem import Problem, CONTINUOUS, INTEGER, MINIMIZE

problem = Problem("FacilityLocation")

# Variable binaire (entière avec bornes 0-1)
open_facility = problem.addVariable(lb=0, ub=1, vtype=INTEGER, name="open")

# Variable continue
production = problem.addVariable(lb=0, vtype=CONTINUOUS, name="production")

# Contrainte de liaison : on ne peut produire que si l'installation est ouverte
problem.addConstraint(production <= 1000 * open_facility, name="link")

# Objectif : coût fixe + coût variable
problem.setObjective(500*open_facility + 2*production, sense=MINIMIZE)

# Paramètres spécifiques à MILP
settings = SolverSettings()
settings.set_parameter("time_limit", 120)
settings.set_parameter("mip_relative_gap", 0.01)  # Écart d'optimalité de 1 %

problem.solve(settings)

# Vérifier le statut
if problem.Status.name in ["Optimal", "FeasibleFound"]:
    print(f"Open facility: {open_facility.getValue() > 0.5}")
    print(f"Production: {production.getValue()}")

Exemple QP (bêta — MINIMIZE uniquement)

from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE
from cuopt.linear_programming.solver_settings import SolverSettings

# Minimisation de la variance du portefeuille
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")

# Objectif quadratique (variance) — DOIT être 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,
)

# Contraintes linéaires
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}")

Règles QP :

  • MINIMIZE uniquement — le solveur rejette MAXIMIZE pour les objectifs quadratiques. Pour maximiser f(x), minimisez -f(x).
  • Variables continues uniquement — QP entier n'est pas supporté.
  • Q doit être SDP (semi-défini positif) pour un problème convexe ; sinon le solveur peut retourner un point stationnaire non-optimal.
  • Bêta — l'API peut évoluer ; considérez comme capable en production pour un QP convexe typique mais attendez-vous à des changements occasionnels.

Voir resources/qp_examples.md pour les exemples de moindres carrés, contournement de maximisation et forme matricielle.

CRITIQUE : Vérification du statut

Les valeurs de statut utilisent PascalCase, PAS ALL_CAPS :

# ✅ CORRECT
if problem.Status.name in ["Optimal", "FeasibleFound"]:
    print(problem.ObjValue)

# ❌ FAUX - échouera silencieusement !
if problem.Status.name == "OPTIMAL":  # Ne correspondra jamais !
    print(problem.ObjValue)

Valeurs de statut LP : Optimal, NoTermination, NumericalError, PrimalInfeasible, DualInfeasible, IterationLimit, TimeLimit, PrimalFeasible

Valeurs de statut MILP : Optimal, FeasibleFound, Infeasible, Unbounded, TimeLimit, NoTermination

Valeurs de statut QP : Même ensemble que LP. Pour le débogage QP, imprimez f"Actual status: '{problem.Status.name}'" et vérifiez que Q est SDP et que les variables sont raisonnablement mises à l'échelle.

Modèles de modélisation courants

Sélection binaire

# Sélectionner exactement k éléments parmi n
items = [problem.addVariable(lb=0, ub=1, vtype=INTEGER) for _ in range(n)]
problem.addConstraint(sum(items) == k)

Liaison Big-M

# Si y=1, alors x <= 100 ; si y=0, x peut être n'importe quelle valeur jusqu'à M
M = 10000
problem.addConstraint(x <= 100 + M*(1 - y))

Si-alors « doit aussi produire »

Quand le problème dit si nous faisons X nous devons aussi faire Y, appliquez les deux : (i) la liaison binaire et (ii) que Y est réellement produit :

# y_X <= y_Y (si nous faisons X, nous devons « faire » Y)
problem.addConstraint(y_X <= y_Y)
# Production de Y quand Y est choisi : produire au moins 1 (ou un minimum) quand y_Y=1
problem.addConstraint(production_Y >= 1 * y_Y)  # ou min_amount * y_Y

Sinon le solveur peut définir y_Y=1 mais production_Y=0, satisfaisant la liaison binaire mais pas l'intention.

Construire de grandes expressions

Chaîner + sur beaucoup de termes peut atteindre les limites de récursion dans l'API. Préférez construire les objectifs et contraintes avec LinearExpression :

from cuopt.linear_programming.problem import LinearExpression

# Construire comme liste de (vars, coeffs) au lieu de 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)

Voir les modèles de référence dans le répertoire assets/ de cette compétence pour des exemples.

Linéaire par segments (SOS2)

# Approximer une fonction non-linéaire avec des points de rupture
# Utiliser des variables lambda qui somment à 1, au plus 2 non-zéro adjacentes

Paramètres du solveur

settings = SolverSettings()

# Limite de temps
settings.set_parameter("time_limit", 60)

# Tolérance d'écart MILP (arrêter quand c'est à X % de l'optimum)
settings.set_parameter("mip_relative_gap", 0.01)

# Journalisation
settings.set_parameter("log_to_console", 1)

Problèmes courants

Problème Cause probable Correction
Statut jamais « OPTIMAL » Utilisation de la mauvaise casse Utilisez "Optimal" pas "OPTIMAL"
Variable entière avec valeur fractionnaire Défini comme CONTINUOUS Utilisez vtype=INTEGER
Infaisable Contraintes contradictoires Vérifiez la logique des contraintes
Non borné Bornes manquantes Ajoutez des bornes aux variables
Résolution lente Problème large Définissez une limite de temps, augmentez la tolérance d'écart
Profondeur de récursion maximale Construire une grande expr avec + chaîné Utilisez LinearExpression(vars_list, coeffs_list, constant)
QP rejeté avec MAXIMIZE QP supporte uniquement MINIMIZE Négliez l'objectif : minimisez -f(x)
QP retourne non-optimal Q pas SDP ou variables mal mises à l'échelle Vérifiez que Q est SDP ; remettez à l'échelle les variables à des magnitudes similaires

Obtenir les valeurs duales (LP uniquement)

if problem.Status.name == "Optimal":
    constraint = problem.getConstraint("resource_a")
    shadow_price = constraint.DualValue
    print(f"Shadow price: {shadow_price}")

Modèles de référence

Tous les modèles de référence se trouvent dans le répertoire assets/ de cette compétence. Utilisez-les comme référence lors de la construction de nouvelles applications ; ne les éditez pas sur place.

Exemples minimaux / canoniques (LP, MILP, QP)

Modèle Type Description
lp_basic LP LP minimal : variables, contraintes, objectif, résolution
lp_duals LP Valeurs duales et coûts réduits
lp_warmstart LP Démarrage à chaud PDLP pour problèmes similaires
milp_basic MILP MIP minimal ; inclut exemple de rappel incumbent
milp_production_planning MILP Planification de la production avec contraintes de ressources
portfolio QP Minimiser la variance du portefeuille ; contraintes de budget et rendement minimal
least_squares QP Minimiser (x-3)² + (y-4)² (point le plus proche)
maximization_workaround QP Maximiser quadratique via minimiser -f(x)

Autres références

Modèle Type Description
mps_solver LP/MILP Résoudre n'importe quel problème à partir du format de fichier MPS standard

Commande rapide pour lister les modèles : ls assets/ (depuis le répertoire de cette compétence).

Quand escalader

Utilisez le dépannage et l'aide au diagnostic si :

  • Infaisable et vous ne pouvez pas déterminer pourquoi
  • Problèmes numériques

Skills similaires