Произведение непрерывной переменной и целого числа - PullRequest
0 голосов
/ 28 апреля 2020

В настоящее время я пишу код на python для решения проблемы планирования рабочей силы. Теперь у меня есть некоторые проблемы с реализацией концепции производительности труда в этой проблеме. I express вероятность в числе от одного до 100 (так что это целое число, а не непрерывная переменная). Тем не менее, когда я пытаюсь запустить мою программу, появляется следующее сообщение об ошибке: «GurobiError: Невозможно получить атрибут« X »». На мой взгляд, проблема имеет место в первом ограничении. Ниже вы найдете код.

#define sets
periods = ("Period1", "Period2", "Period3", "Period4", "Period5", "Period6", "Period7")
skillPositions = ("SP1", "SP2", "SP3", "SP4", "SP5", "SP6", "SP7", "SP8")
tasks = ("T1", "T2", "T3", "T4", "T5", "T6", "T7", "T8", "T9", "T10", "T11", "T12", "T13", "T14", "T15")

#define parameters
initialProductivity = {"SP1": {"T1":0, "T2":80,"T3":0, "T4":0, "T5":0, "T6":0, "T7":70, "T8":0, "T9":0, "T10":0, "T11":0, "T12":0, "T13":0, "T14":0, "T15":0}, 
                       "SP2": {"T1":0, "T2":0,"T3":0, "T4":0, "T5":80, "T6":0, "T7":0, "T8":0, "T9":70, "T10":0, "T11":0, "T12":0, "T13":0, "T14":0, "T15":0}, 
                       "SP3": {"T1":90, "T2":0,"T3":0, "T4":0, "T5":0, "T6":0, "T7":0, "T8":0, "T9":0, "T10":0, "T11":0, "T12":0, "T13":60, "T14":0, "T15":0},
                       "SP4": {"T1":0, "T2":0,"T3":0, "T4":0, "T5":0, "T6":90, "T7":0, "T8":0, "T9":0, "T10":0, "T11":0, "T12":0, "T13":0, "T14":0, "T15":0},
                       "SP5": {"T1":0, "T2":0,"T3":60, "T4":0, "T5":0, "T6":0, "T7":0, "T8":70, "T9":0, "T10":0, "T11":0, "T12":0, "T13":0, "T14":0, "T15":0},
                       "SP6": {"T1":0, "T2":0,"T3":0, "T4":0, "T5":0, "T6":0, "T7":0, "T8":0, "T9":0, "T10":80, "T11":0, "T12":0, "T13":0, "T14":0, "T15":80},
                       "SP7": {"T1":0, "T2":0,"T3":0, "T4":70, "T5":0, "T6":0, "T7":0, "T8":0, "T9":0, "T10":0, "T11":0, "T12":0, "T13":0, "T14":80, "T15":0},
                       "SP8": {"T1":0, "T2":0,"T3":0, "T4":0, "T5":0, "T6":0, "T7":0, "T8":0, "T9":0, "T10":0, "T11":70, "T12":60, "T13":0, "T14":0, "T15":0}}

learningParameter = {"SP1": {"T1":0, "T2":5,"T3":0, "T4":0, "T5":0, "T6":0, "T7":4, "T8":0, "T9":0, "T10":0, "T11":0, "T12":0, "T13":0, "T14":0, "T15":0}, 
                     "SP2": {"T1":0, "T2":0,"T3":0, "T4":0, "T5":7, "T6":0, "T7":0, "T8":0, "T9":5, "T10":0, "T11":0, "T12":0, "T13":0, "T14":0, "T15":0}, 
                     "SP3": {"T1":1, "T2":0,"T3":0, "T4":0, "T5":0, "T6":0, "T7":0, "T8":0, "T9":0, "T10":0, "T11":0, "T12":0, "T13":2, "T14":0, "T15":0},
                     "SP4": {"T1":0, "T2":0,"T3":0, "T4":0, "T5":0, "T6":6, "T7":0, "T8":0, "T9":0, "T10":0, "T11":0, "T12":0, "T13":0, "T14":0, "T15":0},
                     "SP5": {"T1":0, "T2":0,"T3":6, "T4":0, "T5":0, "T6":0, "T7":0, "T8":7, "T9":0, "T10":0, "T11":0, "T12":0, "T13":0, "T14":0, "T15":0},
                     "SP6": {"T1":0, "T2":0,"T3":0, "T4":0, "T5":0, "T6":0, "T7":0, "T8":0, "T9":0, "T10":5, "T11":0, "T12":0, "T13":0, "T14":0, "T15":5},
                     "SP7": {"T1":0, "T2":0,"T3":0, "T4":6, "T5":0, "T6":0, "T7":0, "T8":0, "T9":0, "T10":0, "T11":0, "T12":0, "T13":0, "T14":6, "T15":0},
                     "SP8": {"T1":0, "T2":0,"T3":0, "T4":0, "T5":0, "T6":0, "T7":0, "T8":0, "T9":0, "T10":0, "T11":2, "T12":2, "T13":0, "T14":0, "T15":0}}

demand = {"Period1": {"T1":3, "T2":1386,"T3":1169, "T4":650, "T5":2923, "T6":693, "T7":4482, "T8":130, "T9":346, "T10":87, "T11":346, "T12":346, "T13":693, "T14":173, "T15":1}, 
       "Period2": {"T1":1, "T2":1252,"T3":1120, "T4":645, "T5":2788, "T6":670, "T7":4348, "T8":80, "T9":212, "T10":69, "T11":325, "T12":325, "T13":687, "T14":168, "T15":1}, 
       "Period3": {"T1":1, "T2":1302,"T3":1095, "T4":650, "T5":2838, "T6":650, "T7":4398, "T8":55, "T9":262, "T10":39, "T11":330, "T12":330, "T13":689, "T14":173, "T15":1}, 
       "Period4": {"T1":1, "T2":1297,"T3":1169, "T4":645, "T5":2788, "T6":693, "T7":4393, "T8":130, "T9":212, "T10":77, "T11":335, "T12":335, "T13":669, "T14":168, "T15":1}, 
       "Period5": {"T1":1, "T2":1452,"T3":1170, "T4":650, "T5":3038, "T6":700, "T7":4548, "T8":130, "T9":462, "T10":87, "T11":340, "T12":340, "T13":689, "T14":173, "T15":1}, 
       "Period6": {"T1":1, "T2":1502,"T3":1220, "T4":660, "T5":3088, "T6":700, "T7":4598, "T8":180, "T9":512, "T10":89, "T11":345, "T12":344, "T13":689, "T14":183, "T15":1}, 
       "Period7": {"T1":1, "T2":1602,"T3":1270, "T4":670, "T5":3188, "T6":700, "T7":4698, "T8":230, "T9":612, "T10":99, "T11":349, "T12":350, "T13":689, "T14":193, "T15":1}}


salaryCost = {"Period1": {"SP1":2296, "SP2":2207, "SP3":1900, "SP4":2199, "SP5":2586, "SP6":2276, "SP7":2390, "SP8":2200},
           "Period2": {"SP1":2296, "SP2":2207, "SP3":1900, "SP4":2199, "SP5":2586, "SP6":2276, "SP7":2390, "SP8":2200},
           "Period3": {"SP1":2296, "SP2":2207, "SP3":1900, "SP4":2199, "SP5":2586, "SP6":2276, "SP7":2390, "SP8":2200},
           "Period4": {"SP1":2296, "SP2":2207, "SP3":1900, "SP4":2199, "SP5":2586, "SP6":2276, "SP7":2390, "SP8":2200},
           "Period5": {"SP1":2296, "SP2":2207, "SP3":1900, "SP4":2199, "SP5":2586, "SP6":2276, "SP7":2390, "SP8":2200},
           "Period6": {"SP1":2296, "SP2":2207, "SP3":1900, "SP4":2199, "SP5":2586, "SP6":2276, "SP7":2390, "SP8":2200},
           "Period7": {"SP1":2296, "SP2":2207, "SP3":1900, "SP4":2199, "SP5":2586, "SP6":2276, "SP7":2390, "SP8":2200}}

#define decision variables
numberRequired = model.addVars(periods, skillPositions, tasks, vtype=GRB.INTEGER, name = "numberRequired")
productivity = model.addVars(periods, skillPositions, tasks, vtype=GRB.INTEGER, lb=0, ub=100, name= "productivity")
differenceProductivity = model.addVars(periods, skillPositions, tasks, vtype= GRB.INTEGER, lb=0, ub=100, name= "differenceProductivity")

#define constraints
#THIS FIRST CONSTRAINT IS WHERE THE ERROR MESSAGE COMES FROM
model.addConstrs(demand[period][taskx] <= quicksum(math.floor((numberRequired[period, skillPositionJ, taskx]*availableRegularHours*productivity[period, skillPositionJ, taskx])/100) for skillPositionJ in skillPositions) for period in periods for taskx in tasks)
model.addConstrs(productivity[period, skillPosition, task] == initialProductivity[period][skillPosition][task] + differenceProductivity[period, skillPosition, task] * (1-math.exp(-(sum(possibleCombinations[currentP][skillPosition][task] for currentP in periods[:int(period[-1])])/learningParameter[period][skillPosition][task])) if learningParameter[period][skillPosition][task] > 0 else 0) for period in periods for skillPosition in skillPositions for task in tasks) 
model.addConstrs(differenceProductivity[period, skillPosition, task] == 100-initialProductivity[period][skillPosition][task] for period in periods for skillPosition in skillPositions for task in tasks)

#define objective
obj = (quicksum(salaryCost[period][skillPositionJ]*numberRequired[periods[period_index-1], skillPositionJ, taskx] for period_index, period in enumerate(periods) for skillPositionJ in skillPositions for taskx in tasks)
model.setObjective(obj, GRB.MINIMIZE)

#solving the model
model.optimize()
model.printAttr('X')

Кто-нибудь может найти мою ошибку в этом коде? Это как-то связано с переменной производительности, так как работает без этого. Заранее спасибо!

С уважением

Ответы [ 2 ]

1 голос
/ 28 апреля 2020

Одна вещь, которую я вижу, это использование math.floor . Во-первых, Гуроби не знает об этой функции. Но также: это сделает модель нелинейной и неприятной (недифференцируемой).

Конструкция y=floor(x) может быть линеаризована как:

  y <= x
  y >= x-1+0.0001
  y integer

Есть еще квадратичные значения c условия в модели. Gurobi может работать с выпуклыми и невыпуклыми квадратичными c моделями, но обычно лучше по возможности придерживаться линейных моделей.

Также важно сохранять как можно более простые ограничения. Это означает, что я хотел бы заранее вычислить такие вещи, как:

(1-math.exp(-(sum(possibleCombinations[currentP][skillPosition][task] for currentP in periods[:int(period[-1])])/learningParameter[period] [skillPosition][task])) if learningParameter[period][skillPosition][task] > 0 else 0) 

Если я прав, ограничение просто:

productivity=initialProductivity+differenceProductivity*coefficient

, но мы погружаемся в сложность, делая ограничение нечитаемым.

Наконец, мой совет - сначала разработать математическую модель и обсудить ее с вашим руководителем, прежде чем начинать кодировать в Python. Гораздо эффективнее рассуждать о переформулировках для компактной математической модели, чем для связки сложного Python кода.

0 голосов
/ 28 апреля 2020

Этот код ошибки предполагает, что вы пытаетесь получить значения решения для недопустимой модели. Пожалуйста, внимательно проверьте вывод решателя и всегда проверяйте состояние решения, прежде чем запрашивать значения решения:

if model.status == GRB.OPTIMAL:
    print('Optimal objective: %g' % model.objVal)
    model.printAttr('X')
elif model.status != GRB.INFEASIBLE:
    print('Optimization was stopped with status %d' % model.status)
...