CPLEX — Оптимизация — минимизация производственных затрат по периоду: Ошибка: модель невыпуклая

#optimization #cplex #docplex

#оптимизация #cplex #docplex

Вопрос:

Я пытаюсь создать оптимизационную модель с использованием CPLEX.

Моя проблема в том:

У меня есть спрос, производственные мощности (по машинам в день) и производственные затраты (по машинам в день) для производства продуктов. Некоторые машины имеют разную стоимость и производственную мощность для производства одного и того же продукта.

Я пытаюсь построить оптимизационную модель, которая производит востребованные продукты при минимизации затрат на производство.

С помощью приведенного ниже кода я получаю сообщение об ошибке Ошибка: модель невыпуклая

 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)
 

Ответ №1:

Ваша модель содержит ограничения с суммами членов вида x_i * y_ i. Такие ограничения не являются выпуклыми, в основном любое квадратичное произведение двух разных переменных X * Y является невыпуклым. CPLEX еще не решает невыпуклые QCPS, поэтому вам нужно переформулировать вашу проблему без этих продуктов. Я вижу два возможных способа:

  • либо расширьте матрицу переменных X (кстати, вы, вероятно, можете использовать Model.continuous_var_matrix для упрощения) с одним дополнительным измерением на несколько дней, и у вас будет одна переменная на тройку (продукт, машина, день)
  • также проверьте ограничение индикатора: ограничение индикатора динамически связывает значение двоичной переменной и линейное ограничение. Другими словами, если во время поиска решения двоичная переменная становится 1 (или 0), то применяется некоторое линейное ограничение, в противном случае не определено, является ли оно истинным или ложным.

Например, следующий код

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

утверждает, что если конечное значение двоичных переменных dias[0] равно 0 (the active_value ), то ограничение x[1,2]==0 становится истинным.

Обратите внимание, что это работает в одну сторону: значение двоичной переменной влияет на состояние ограничения, но не наоборот.

Дайте мне знать, если у вас есть вопросы по переформулировке модели.

Комментарии:

1. Привет, Филипп, спасибо за ваше время. Я понял, что мне нужно исключить произведение двух разных переменных. Но я не уверен, как я могу построить цель и ограничения без этого. Я опубликую версию, используя ваше предложение, с одним дополнительным измерением в течение нескольких дней. Я буду рассматривать любые комментарии.

2. Пытаясь выполнить предложение от @philippe-couronne, устраните произведение двух разных переменных, используя дополнительное измерение в течение нескольких дней: используя приведенный ниже код, я получаю ответ о невозможности, поскольку модели не удалось найти значение соответствия спроса. Я все делаю правильно?

3. x = {(i, j, d): mdl.continuous_var(name=»PRODUCAO_{0}_{1}_{2}». формат (i, j, d)) для i в продуктах для j в макинах для d в dias} ## ЦЕЛЬ: минимальная стоимостьпроизводства x дней mdl.minimize(mdl.sum([ (df_custo.loc [i, j] * d) * x [(i, j, d)] для i в продуктах для j в макинах для d в dias]) ) ## ОГРАНИЧЕНИЕ: спрос на продукт для iв продуктах: mdl.add_constraint( mdl.sum([x[(i, j, d)] для j в макинах для d в dias]) == df_demanda.loc[i,’TONS_BY_MONTH’])

4. ## ОГРАНИЧЕНИЕ 2: стоимость продукта для i в продуктах: для j в макинах: для d в dias: mdl.add_constraint(mdl.sum([x[(i, j, d)] ]) == df_custo.loc[i,j] * d) mdl.решить (log_output=True)

5. Я предлагаю вам начать с предоставления спецификации проблемы в виде текста, прежде чем обсуждать реализации.