cuopt-lp-milp-api-python

Par nvidia · skills

Résoudre des problèmes de programmation linéaire (LP) et de programmation linéaire en nombres entiers mixtes (MILP) avec l'API Python. À utiliser lorsque l'utilisateur pose des questions sur l'optimisation avec des contraintes linéaires, des variables entières, la planification, l'allocation de ressources, la localisation d'installations ou la planification de la production.

npx skills add https://github.com/nvidia/skills --skill cuopt-lp-milp-api-python

Compétence cuOpt LP/MILP

Modéliser et résoudre des programmes linéaires et mixtes-entiers à l'aide du solveur GPU-accéléré de NVIDIA cuOpt.

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. Confirmez ensuite les types de variables (voir ci-dessous) et l'interface (API Python recommandée).

Choisir entre LP et MILP

Privilégiez LP (toutes variables continues) quand le problème le permet. LP se résout plus rapidement et offre des garanties d'optimalité plus fortes. Utilisez MILP uniquement si le problème exige logiquement des nombres entiers ou des décisions oui/non.

Types de problèmes nécessitant une attention particulière : La planification multi-période et la programmation d'objectifs sont faciles à mal interpréter. Vérifiez bien que les taux et contraintes s'appliquent à la bonne période de temps 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 comptages 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).

Variable entière ou continue selon le libellé

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

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

Règle pratique : Si la quantité est « combien de choses » (personnes, véhicules, articles, sites), utilisez INTEGER. Si c'est « combien de » (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 le 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 : utiliser 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 peut produire seulement 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()}")

CRITIQUE : Vérification du statut

Les valeurs de statut utilisent PascalCase, NON 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

Motifs de modélisation courants

Sélection binaire

# Sélectionner exactement k articles 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 valoir jusqu'à M
M = 10000
problem.addConstraint(x <= 100 + M*(1 - y))

Si-alors « doit aussi produire »

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

# y_X <= y_Y (si on fait X, on doit « 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 fixer y_Y=1 mais production_Y=0, satisfaisant la liaison binaire mais pas l'intention.

Construire de grandes expressions

Chaîner + sur de nombreux termes peut atteindre les limites de récursion de 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 morceaux (SOS2)

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

Paramètres du solveur

settings = SolverSettings()

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

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

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

Problèmes courants

Problème Cause probable Solution
Statut jamais « OPTIMAL » Mauvaise casse utilisée Utiliser "Optimal" pas "OPTIMAL"
Variable entière avec valeur fractionnaire Définie comme CONTINUOUS Utiliser vtype=INTEGER
Infaisable Contraintes conflictuelles Vérifier la logique des contraintes
Non-borné Bornes manquantes Ajouter des bornes aux variables
Résolution lente Problème volumineux Fixer une limite de temps, augmenter la tolérance d'écart
Profondeur de récursion dépassée Construction d'expression grande avec + chaîné Utiliser LinearExpression(vars_list, coeffs_list, constant)

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 modifiez pas en place.

Exemples minimaux / canoniques (LP & MILP)

Modèle Type Description
lp_basic LP LP minimale : variables, contraintes, objectif, résolution
lp_duals LP Valeurs duales et coûts réduits
lp_warmstart LP PDLP warmstart pour des problèmes similaires
milp_basic MILP MIP minimale ; inclut un exemple de rappel incumbent
milp_production_planning MILP Planification de la production avec contraintes de ressources

Autres références

Modèle Type Description
mps_solver LP/MILP Résoudre n'importe quel problème au format MPS standard

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

Quand escalader

Utilisez les conseils de dépannage et de diagnostic si :

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

Skills similaires