Search code examples
pythonmathoptimizationpulp

PuLP Module : constraints imposed but not verified by the solution found


I am trying to solve an optimization problem. I use PuLP to solve it. However, the optimal solution given by the solver does not respect the constraints I impose in the code. This is absurd and I don't understand.

Description of the problem : I want to solve the problem given in picture

The optimization problem I want to solve

The optimization problem I want to solve

"sc" means "under constraints" and : f(p, e) = 20 sum_{i=0}^12 s_i + 50 \sum_{i=0}^{11}e[i] {p[i+1]-p[i]}

with s_m = s_0 + sum_{i=1}^m (p_m - d_m)

The sequence u just checks u[i]=sign(p[i+1]-p[i])

d is a sequence of elements that is given.

def q(e, X, p0):
    # Constantes et données de l'énoncé
    mois = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
    mois0 = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
    
    e = {'1': e[0], 
         '2': e[1], 
         '3': e[2], 
         '4': e[3], 
         '5': e[4], 
         '6': e[5],
         '7': e[6],
         '8': e[7],
         '9': e[8],
         '10': e[9],
         '11': e[10],
         '12': e[11]}


    # Définition du problème
    prob = LpProblem("Planification de la production", LpMinimize)

    # Définition des variables
    p = LpVariable.dicts("mois", mois0, 0)

    # Fonction objectif
    def lst_mois(m):
        L=[]
        for i in range(1, m+1):
            L.append(str(i))
        return L
    
    prob += lpSum([20 * (s0 + lpSum([p[i] - d[i] for i in lst_mois(int(m))])) for m in mois0]) + lpSum([50 * e[i] * (p[i] - p[str(int(i)-1)]) for i in mois]), "Coût à constante près"
    
    # Contraintes
    for m in mois:
        prob += (s0 + lpSum([p[i] - d[i] for i in lst_mois(int(m))])) >= 0, m

    for i in mois:
        prob += e[i] * (p[i] - p[str(int(i)-1)]) >= 0, "Contrainte de signe "+i
    
    if X < np.inf:
        for i in mois:
            prob += p[i] <= X, "Coût maximal "+i

    prob += p['0'] == p0
    
    # Résolution
    prob.solve()

    # On renvoie le résultat sous forme d'un tableau (indices = mois, valeur = volume à produire)
    production = [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]
  
    for v in prob.variables():
        production[int(v.name[5])] = v.varValue
    
    print(prob.status)
    return production

Then when I try to use this function with : d = {'0': 0., '1': 120, '2': 220, '3': 120, '4': 620, '5': 650, '6': 650, '7': 650, '8': 100, '9': 150, '10': 520, '11': 510, '12': 500} p0=600 s0=100

a = q([1,1,1,-1,-1,1,-1,1,1,1,1,1], np.inf, p0)

The result is not the good one because the second constraint is not respected. Indeed, the result is :

[600.0, 466.25, 600.0, 600.0, 282.5, 282.5, 282.5, 282.5, 282.5, 282.5, 0.0, 0.0, 0.0]

and it turns out that the second constraint is never respected.

How to solve this ? Thanks


Solution

  • I think you have a typo when you assign the variables to production list. It should be:

        for v in prob.variables():
            production[int(v.name.split("_")[-1])] = v.varValue
    

    Then the result will be:

    [600.0, 600.0, 600.0, 600.0, 282.5, 282.5, 282.5, 282.5, 282.5, 282.5, 282.5, 466.25, 466.25]