PAULO CRISTIANO KLEIN
PAULO CRISTIANO KLEIN

Reputation: 21

CPLEX - Optimization - Minimize production cost by period: Error: Model is non-convex


I'm trying to create an optimization model using CPLEX.

My problem is:

I have demand, production capacity (by machine by day), and production cost (by machine by day) to produce the products. Some machines have diferent cost and production capacity to produce same product.

I am trying to build an optimization model that produces the demand products while minimizing the cost of production.

With the below code, I'm getting the error Error: Model is non-convex

import pandas as pd
dmd =  {
        'TONS_BY_MONTH': {'PRODUCT_A': 27283.781, 'PRODUCT_B': 119.477, 'PRODUCT_C': 4651.003}
    }
df_demanda = pd.DataFrame(dmd)
df_demanda

custo = {
     'MC05': {'PRODUCT_A': 1368, 'PRODUCT_B': 1368, 'PRODUCT_C': 1368},
     'MC06': {'PRODUCT_A': 1435, 'PRODUCT_B': 1435, 'PRODUCT_C': 1427},
     'MC07': {'PRODUCT_A': 1189, 'PRODUCT_B': 1207, 'PRODUCT_C': 0},
     'MC08': {'PRODUCT_A': 1221, 'PRODUCT_B': 1209, 'PRODUCT_C': 0},
     'MC09': {'PRODUCT_A': 1905, 'PRODUCT_B': 1907, 'PRODUCT_C': 1965}
     } 

df_custo = pd.DataFrame(custo)
df_custo

produtos = ['PRODUCT_A', 'PRODUCT_B', 'PRODUCT_C']
maquinas = ['MC05','MC06','MC07','MC08','MC09']
dias = list(range(1,30))

capacidade = {
    'MC05': {'PRODUCT_A': 371, 'PRODUCT_B': 371, 'PRODUCT_C': 427},
    'MC06': {'PRODUCT_A': 396, 'PRODUCT_B': 396, 'PRODUCT_C': 435},
    'MC07': {'PRODUCT_A': 547, 'PRODUCT_B': 571, 'PRODUCT_C': 0},
    'MC08': {'PRODUCT_A': 476, 'PRODUCT_B': 497, 'PRODUCT_C': 0},
    'MC09': {'PRODUCT_A': 657, 'PRODUCT_B': 692, 'PRODUCT_C': 790}
    }
df_capacidade = pd.DataFrame(capacidade)
df_capacidade

from docplex.mp.model import Model
mdl = Model(name="DEMANDA_BY_DAY")



x  = {(i,j):
      mdl.continuous_var(name="PRODUCAO_{0}_{1}".format(i,j)) for i in produtos for j in maquinas }


DIAS  = {(d):
         mdl.binary_var(name="DIA_{0}".format(d)) for d in dias}

mdl.minimize(mdl.sum([ DIAS[d] * (df_custo.loc[i,j] * x[(i,j)]) for d in dias for i in produtos for j in maquinas]))



for i in produtos:
             mdl.add_constraint( mdl.sum([x[(i,j)] * DIAS[d] for d in DIAS  for j in maquinas ]) == df_demanda.loc[i,'TONS_BY_MONTH'])

for i in produtos:
             mdl.add_constraint(  mdl.sum([x[(i,j)] * DIAS[d]  for d in DIAS for j in maquinas ]) <= mdl.sum([df_capacidade.loc[i,s] for s in maquinas]))
        
        
mdl.solve(log_output=True)

Upvotes: 0

Views: 378

Answers (1)

Philippe Couronne
Philippe Couronne

Reputation: 846

Your model contains constraints with sums of terms of the form x_i * y_+i. Such constraints are not convex, basically any quadratic product of two different variables X *Y is non-convex. CPLEX does not yet solve non-convex QCPs, so you need to reformulate your problem without these products. I see two possible ways:

  • either extend the X variable matrix (BTW, you can probably use Model.continuous_var_matrix to simplify) with one extra dimension for days, and you have one variable per triple (product, machine, day)

  • also check indicator constraint: an indicator constraint link dynamically the value of a binary variable and a linear constraint. IN other terms, if during the search for a solution, the binary variable becomes 1 (or 0) then some linear constraint is enforced, otherwise it is undefined whether it is true or false.

For example, the following code

mdl.add_indicator(dias[0], x[1,2] ==0, active_value=0)

states that if the final value of the binary variables dias[0] is 0 (the active_value), then the constraint x[1,2]==0 becomes true.

Note that this works one-way: the value of the binary variable influences the status of the constraint, but not the other way round.

Let me know if you have questions on the reformulation of the model.

Upvotes: 1

Related Questions