Как можно использовать эластичную подзадачу в PuLP в качестве ограничения?

В Python PuLP ограничение линейного программирования можно превратить в эластичную подзадачу.

http://www.coin-or.org/PuLP/pulp.html?highlight=lpsum#elastic-constraints.

Решение подзадачи оптимизирует расстояние от целевого значения.

Конечно, целевое значение является оптимальным решением этой подзадачи, но весь смысл эластичности заключается в том, что мы считаем это решение невозможным.

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

Я не могу найти ничего в документации выше или в примерах, размещенных здесь:

https://code.google.com/p/pulp-or/wiki/OptimisationWithPuLP?tm=6

Вот подзадача, которую я сформулировал:

capacity = LpConstraint(e=lpSum([ x[m][n] * len(n.items) for n in N ]),
    sense=-1, rhs=30, name=str(random.random()))
stretch_proportion = 30/50
elasticCapacity = capacity.makeElasticSubProblem(penalty=50,
    proportionFreeBoundList=[1,stretch_proportion])

Вот что мне кажется наиболее близким к включению этого в Цели LP:

def sub(m):
    capacity = LpConstraint(e=lpSum([ x[m][n] * len(n.items) for n in N ]),
        sense=-1, rhs=30, name=str(random.random()))
    stretch_proportion = 30/50
    elasticCapacity = capacity.makeElasticSubProblem(penalty=50,
        proportionFreeBoundList=[1,stretch_proportion])
    elasticCapacity.solve()
    return elasticCapacity.isViolated()

...

prob += lpSum( [ x[m][n] * reduce(op.add, map(D2, [i.l for i in n.items], [j.l for j in n.items]))\
    for n in N for m in M ] ) + 50 * sub(m)

person Bret Fontecchio    schedule 03.12.2014    source источник


Ответы (1)


Вот краткий ответ в виде наброска рабочего примера:

Создайте проблему и добавьте жесткие ограничения и цель.

prob = LpProblem("My Problem", LpMinimize)
....

После того, как вы это сделаете, определите мягкое (эластичное) ограничение и добавьте его к задаче с помощью pulp.prob.extend(), например:

c_e_LHS = LpAffineExpression([(var1,coeff1), (var2,coeff2)])   # example left-hand-side expression
c_e_RHS = 30   # example right-hand-side value
c_e_pre = LpConstraint(e=el_constr_LHS, sense=-1, name='pre-elastic', rhs=c_e_RHS)   # The constraint LHS = RHS
c_e = c_e_pre.makeElasticSubProblem(penalty=100, proportionFreeBoundList=[.02,.02])   # The definition of the elasticized constraint 
prob.extend(c_e)   # Adding the constraint to the problem

На этом этапе проблема была изменена и теперь включает мягкое (эластичное) ограничение, и вы можете ее решить. $ \ qed $.

Вот более развернутый ответ: на этот вопрос ответят в группе Google Pulp-or-Disc в разделе добавление эластичного ограничения. Я создал следующий пример для своих целей, основываясь на этом обсуждении и на чем дольше формулировка задачи смешивания на сайте документации PuLP.

Сначала вы создаете проблему:

from pulp import *
prob = LpProblem("The Whiskas Problem", LpMinimize)

Составьте список ингредиентов:

Ingredients = ['CHICKEN', 'BEEF', 'MUTTON', 'RICE', 'WHEAT', 'GEL']

Составлен словарь стоимости каждого ингредиента:

costs = {'CHICKEN': 0.013, 
         'BEEF': 0.008, 
         'MUTTON': 0.010, 
         'RICE': 0.002, 
         'WHEAT': 0.005, 
         'GEL': 0.001}

Создается словарь процентного содержания белка в каждом из ингредиентов:

proteinPercent = {'CHICKEN': 0.100, 
                  'BEEF': 0.200, 
                  'MUTTON': 0.150, 
                  'RICE': 0.000, 
                  'WHEAT': 0.040, 
                  'GEL': 0.000}

Создается словарь процентного содержания жира в каждом из ингредиентов:

fatPercent = {'CHICKEN': 0.080, 
              'BEEF': 0.100, 
              'MUTTON': 0.110, 
              'RICE': 0.010, 
              'WHEAT': 0.010, 
              'GEL': 0.000}

Создается словарь процентного содержания клетчатки в каждом из ингредиентов:

fibrePercent = {'CHICKEN': 0.001, 
                'BEEF': 0.005, 
                'MUTTON': 0.003, 
                'RICE': 0.100, 
                'WHEAT': 0.150, 
                'GEL': 0.000}

Создается словарь процента соли в каждом из ингредиентов:

saltPercent = {'CHICKEN': 0.002, 
               'BEEF': 0.005, 
               'MUTTON': 0.007, 
               'RICE': 0.002, 
               'WHEAT': 0.008, 
               'GEL': 0.000}

Создайте переменную 'prob' для хранения данных о проблеме:

prob = LpProblem("The Whiskas Problem", LpMinimize)

Словарь под названием «ингредиент_варс» создается для хранения переменных, на которые имеются ссылки:

ingredient_vars = LpVariable.dicts("Ingr",Ingredients,0)

Добавьте цель:

prob += lpSum([costs[i]*ingredient_vars[i] for i in Ingredients]), "Total Cost of Ingredients per can"

Создайте жесткие ограничения (здесь мой пример начинает отличаться от примера в документации):

c1 = lpSum([ingredient_vars[i] for i in Ingredients]) == 100, "PercentagesSum"
c2 = lpSum([proteinPercent[i] * ingredient_vars[i] for i in Ingredients]) >= 8.0, "ProteinRequirement"
c3 = lpSum([fatPercent[i] * ingredient_vars[i] for i in Ingredients]) >= 6.0, "FatRequirement"
c4 = lpSum([fibrePercent[i] * ingredient_vars[i] for i in Ingredients]) <= 2.0, "FibreRequirement"
c5 = lpSum([saltPercent[i] * ingredient_vars[i] for i in Ingredients]) <= 0.4, "SaltRequirement"

Добавьте жесткие ограничения:

for con in [c1,c2,c3,c4,c5]:
    prob += con

Определите левое выражение ограничения, которое нужно эластизировать:

c6_LHS = LpAffineExpression([(ingredient_vars['GEL'],1), (ingredient_vars['BEEF'],1)])

Определите ограничение, которое необходимо эластизировать: общее количество геля и говядины менее 30%:

c6= LpConstraint(e=c6_LHS, sense=-1, name='GelBeefTotal', rhs=30)

Определите эластичное ограничение:

c6_elastic = c6.makeElasticSubProblem(penalty = 100, proportionFreeBoundList = [.02,.02])

И это способ добавить к проблеме эластичное (то есть мягкое) ограничение:

prob.extend(c6_elastic)

Решать проблему:

prob.writeLP("WhiskasModel.lp")
prob.solve()

Выведите оптимальное решение:

for v in prob.variables():
    print v.name, "=", v.varValue

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

PS, насколько я понимаю, название вопроса может вводить в заблуждение. Добавление эластичной подзадачи равносильно добавлению к цели некоторых стоимостных терминов, соответствующих «мягкому ограничению». Мягкое ограничение - это не ограничение - это сокращение для набора стоимостных терминов в цели.

person GrayOnGray    schedule 17.02.2017
comment
Вы можете ответить на этот вопрос? stackoverflow .com / questions / 55830745 / - person KHAN irfan; 24.04.2019