2

Je trouve difficile de convertir un modèle Excel Solver en syntaxe python pulp. Dans mon modèle, j'optimise les variables HC et OT pour chaque département, avec un objectif de minimisation de la somme des variables OT. Les contraintes exigent que les variables HC ne totalisent pas plus de 92 et que la production totale (=E2*C2*D2 + F2*C2 dans la feuille de calcul ci-dessous) réponde à une exigence par département (la colonne «Entrée» de la feuille de calcul Excel ci-dessous). La formulation du solveur Excel présentée ci-dessous fonctionne parfaitement.Conversion d'une solution de solveur Excel en pâte Python

Problème

  1. Comment puis-je écrire ma fonction objective dans la pâte (dans Excel F7 = SOMME (F2: F6))?
  2. contraintes E7 < = 92
  3. contraintes G2: G6> = B2: B6
  4. j'ai deux variables de décision HC et OT. Dans le code python ci-dessous, je n'ai créé qu'une seule variable.

Avant

enter image description here

Après Solver

enter image description here

import pulp 
import numpy as np 
import pandas as pd 

idx = [0, 1, 2, 3, 4] 

d = {'Dept': pd.Series(['Receiving', 'Picking', 'PPicking', 'QC', 'Packing'], index=idx), 
    'Target': pd.Series([61,94,32,63,116], index=idx), 
    'Hrs/day': pd.Series([7.75, 7.75, 7.75, 7.75, 7.75], index=idx), 
    'Prod': pd.Series([11733, 13011, 2715, 13682, 14194], index=idx), 
    'HC': pd.Series([24,18,6,28,16], index=idx), 
    'OT': pd.Series([0,0,42,0,0], index=idx)} 

df = pd.DataFrame(d) 

# Create variables and model 
x = pulp.LpVariable.dicts("x", df.index, lowBound=0) 
mod = pulp.LpProblem("OTReduction", pulp.LpMinimize) 

# Objective function 
mod += sum(df['OT']) 


# Lower and upper bounds: 
for idx in df.index: 
    mod += x[idx] <= df['Input'][idx] 


# Total HC value should be less than or equal to 92 
mod += sum([x[idx] for idx in df.index]) <= 92 


# Solve model 
mod.solve() 

# Output solution 
for idx in df.index: 
    print idx, x[idx].value() 


# Expected answer 
# HC, OT 
# 19, 35.795 
# 18, 0 
# 11, 0 
# 28, 0 
# ---------------- 
# 92, 35.795 -> **note:** SUM(HC), SUM(OT) 

Répondre

3

Il y a quelques problèmes avec votre code affiché Pulp .

Vous ne déclarez qu'un ensemble de variables, x, mais vous avez deux ensembles dans votre formulation Excel, HC et OT. Vous devez déclarer deux séries de variables distinctes, et de les nommer de manière appropriée:

HC = pulp.LpVariable.dicts("HC", df.index, lowBound=0) 
OT = pulp.LpVariable.dicts("OT", df.index, lowBound=0) 

Lorsque vous ajoutez l'objectif comme mod += sum(df['OT']), vous essayez d'ajouter une colonne d'une trame de données au modèle, ce qui provoque une erreur. Au lieu de cela que vous voulez ajouter la somme des variables OT, qui peuvent être obtenus avec:

mod += sum([OT[idx] for idx in df.index]) 

Lorsque vous ajoutez les contraintes x[idx] <= df['Input'][idx], vous exigez que vos x variables sont supérieures délimitées par les données d'entrée. Cependant, en réalité, vous avez une contrainte plus compliquée - notez que dans le code Excel vous étiez en limite inférieure E2*C2*D2 + F2*C2 par la colonne Entrée. Votre contrainte ici doit présenter cette même logique:

for idx in df.index: 
    mod += df['Target'][idx] * df['Hrs/day'][idx] * HC[idx] + df['Target'][idx] * OT[idx] >= df['Prod'][idx] 

Mettre tout cela ensemble donne la sortie désirée:

import pulp 
import pandas as pd 

# Problem data 
idx = [0, 1, 2, 3, 4] 
d = {'Dept': pd.Series(['Receiving', 'Picking', 'PPicking', 'QC', 'Packing'], index=idx), 
    'Target': pd.Series([61,94,32,63,116], index=idx), 
    'Hrs/day': pd.Series([7.75, 7.75, 7.75, 7.75, 7.75], index=idx), 
    'Prod': pd.Series([11346, 13011, 2715, 13682, 14194], index=idx)} 
df = pd.DataFrame(d) 

# Create variables and model                         
HC = pulp.LpVariable.dicts("HC", df.index, lowBound=0) 
OT = pulp.LpVariable.dicts("OT", df.index, lowBound=0) 
mod = pulp.LpProblem("OTReduction", pulp.LpMinimize) 

# Objective function                           
mod += sum([OT[idx] for idx in df.index]) 

# Lower and upper bounds:                          
for idx in df.index: 
    mod += df['Target'][idx] * df['Hrs/day'][idx] * HC[idx] + df['Target'][idx] * OT[idx] >= df['Prod'][idx] 

# Total HC value should be less than or equal to 92                   
mod += sum([HC[idx] for idx in df.index]) <= 92 

# Solve model                             
mod.solve() 

# Output solution                            
for idx in df.index: 
    print(idx, HC[idx].value(), OT[idx].value()) 
# 0 24.0 0.0 
# 1 13.241236 35.795316 
# 2 10.947581 0.0 
# 3 28.022529 0.0 
# 4 15.788654 0.0