PYOMO: определение набора данных с использованием наборов и параметров для решения задачи оптимизации

#python #pyomo

#python #pyomo

Вопрос:

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

 materials = ['steel', 'alum', 'carbon', 'cheese']
 

Каждый материал имеет 2 свойства — плотность и проводимость, и их значения определяются следующим образом.

 density =   {   'steel' : 1.2,
            'alum'  : 0.8,
            'carbon': 1.8,
            'cheese': 0.7}

conductivity = {'steel' : 6.4,
               'alum'  : 3.1,
               'carbon': 4.4,
               'cheese': 0.3}
 

Целевая функция вычисляет вес 2 прямоугольных пластин, как указано ниже:

 Objective function = Area_1 * thickness_1 * density_1   Area_2 * thickness_2 * density_2
 

Где Area_1, thickness_1 и density_1 — это площадь, толщина и плотность пластины 1.

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

 (conductivity_1/thickness_1)   (conductivity_2/thickness_2)  => 22
 

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

Я был бы признателен, если кто-нибудь сможет помочь мне с этой проблемой. Я также приветствую, если у вас есть разные идеи для решения этой проблемы. Спасибо.

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

1. Это не так много усилий, чтобы понять это. Вы только что переработали большую часть моего примера из вашего другого вопроса. Взгляните на pyomo dox или несколько других вопросов pyomo на этом сайте для примеров. Я опубликовал несколько статей, в которых используется двойное индексирование, которые могут помочь вам начать работу. Давайте посмотрим на обновление минимального примера функционирования. Прямо сейчас ваш вопрос слишком широк.

2. Хорошим первым шагом было бы определить, как математически представить вашу проблему (каковы ваши переменные решения и как вы можете представить свои ограничения и целевую функцию в терминах переменных и параметров решения?)

3. @AirSquid Спасибо за информацию. Я попробую таким образом.

4. @cookesd Моими переменными для принятия решений являются площадь, толщина, проводимость и плотность. Среди 4 переменных площадь и толщина являются фиксированными значениями для пластин. Но проводимость и плотность определяются решателем для получения наилучшего решения. Поэтому, когда решатель выбирает значение плотности для пластины, он также должен выбрать значение проводимости того же материала. Спасибо.

Ответ №1:

Вот пример модели, которая, я думаю, отвечает всем вашим вопросам.

Как только вы настроите второй индекс как пластины P = {1, 2, 3} , в данном случае для 3 пластин, нам нужно удвоить индекс нашей переменной решения, чтобы представить назначение материала m для пластины p . В этом примере 4 материала, 3 пластины.

Здесь возможны многие другие варианты ограничений, но те, которые я добавил, отвечают на ваш вопрос о проводимости в совокупности. Обратите внимание, что я также добавил ограничение, чтобы гарантировать, что каждой пластине назначен 1 и только 1 материал. Вам может понадобиться / может не понадобиться это в зависимости от других ограничений в вашей модели, но это хорошая страховка от ложных ответов. Это также пример стиля ограничения «для каждого» с использованием комбинации «функция — правило pyomo «.

Результат … сэндвич с алюминием и сыром … 🙂

 # material selection model

import pyomo.environ as pyo

# data
materials = ['steel', 'alum', 'carbon', 'cheese']

density =   {   'steel' : 1.2,
                'alum'  : 0.8,
                'carbon': 1.8,
                'cheese': 0.7}

conductivity = {'steel' : 40.8,
                'alum'  : 30.1,
                'carbon': 42.4,
                'cheese': 15.3}

price =     {   'steel' : 2.3,
                'alum'  : 3.5,
                'carbon': 5.8,
                'cheese': 6.0}

                  # t     area
plate_dims = {  1: (10,   150), 
                2: (12.5, 200),
                3: (8,    125)}

mdl = pyo.ConcreteModel('material selector')

# SETS (used to index the decision variable and the parameters)
mdl.M = pyo.Set(initialize=materials)
mdl.P = pyo.Set(initialize=plate_dims.keys())

# VARIABLES
mdl.x = pyo.Var(mdl.M, mdl.P, domain=pyo.Binary)  # select material M for plate P

# PARAMETERS
mdl.density =       pyo.Param(mdl.M, initialize=density)
mdl.conductivity =  pyo.Param(mdl.M, initialize=conductivity)
mdl.price =         pyo.Param(mdl.M, initialize=price)
mdl.p_thickness =   pyo.Param(mdl.P, initialize= {k:v[0] for k,v in plate_dims.items()})
mdl.p_area =        pyo.Param(mdl.P, initialize= {k:v[1] for k,v in plate_dims.items()})

# OBJ (minimize total density)
mdl.obj = pyo.Objective(expr=sum(mdl.x[m, p] * mdl.p_thickness[p] 
                        * mdl.p_area[p] * mdl.density[m] 
                        for m in mdl.M for p in mdl.P))

# CONSTRAINTS
# minimum conductivity
mdl.c1 = pyo.Constraint(expr=sum(mdl.x[m, p] * mdl.conductivity[m]/mdl.p_thickness[p]
                        for m in mdl.M for p in mdl.P) >= 5.0)

# must populate all plates with 1 material
def c2(model, plate):
    return sum(mdl.x[m, plate] for m in mdl.M) == 1
mdl.c2 = pyo.Constraint(mdl.P, rule=c2)

# solve it
solver = pyo.SolverFactory('glpk')
result = solver.solve(mdl)
mdl.display()
 

Дает:

 Model material selector

  Variables:
    x : Size=12, Index=x_index
        Key           : Lower : Value : Upper : Fixed : Stale : Domain
          ('alum', 1) :     0 :   0.0 :     1 : False : False : Binary
          ('alum', 2) :     0 :   0.0 :     1 : False : False : Binary
          ('alum', 3) :     0 :   1.0 :     1 : False : False : Binary
        ('carbon', 1) :     0 :   0.0 :     1 : False : False : Binary
        ('carbon', 2) :     0 :   0.0 :     1 : False : False : Binary
        ('carbon', 3) :     0 :   0.0 :     1 : False : False : Binary
        ('cheese', 1) :     0 :   1.0 :     1 : False : False : Binary
        ('cheese', 2) :     0 :   1.0 :     1 : False : False : Binary
        ('cheese', 3) :     0 :   0.0 :     1 : False : False : Binary
         ('steel', 1) :     0 :   0.0 :     1 : False : False : Binary
         ('steel', 2) :     0 :   0.0 :     1 : False : False : Binary
         ('steel', 3) :     0 :   0.0 :     1 : False : False : Binary

  Objectives:
    obj : Size=1, Index=None, Active=True
        Key  : Active : Value
        None :   True : 3600.0

  Constraints:
    c1 : Size=1
        Key  : Lower : Body              : Upper
        None :   5.0 : 6.516500000000001 :  None
    c2 : Size=3
        Key : Lower : Body : Upper
          1 :   1.0 :  1.0 :   1.0
          2 :   1.0 :  1.0 :   1.0
          3 :   1.0 :  1.0 :   1.0
 

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

1. У меня есть вопрос об использовании вами наборов и параметров. Видели ли вы какое-либо преимущество в их использовании в конкретных моделях вместо того, чтобы иметь данные модели в других объектах python (списках, массивах numpy, фреймах данных pandas)? Обычно я использую последнее, но я не был уверен, что мне не хватает функциональности

2. @cookesd Я не знаю о том, чтобы упустить слишком много, не помещая параметры и наборы в модель, я просто думаю, что легче устранять неполадки (особенно с наборами) в модели и использовать mdl.pprint() и видеть, что все хорошо, и объявлять подмножества и разреженные наборы within , большие наборы хороши дляобнаружение ошибок тоже.

3. @RuaGoa Я думаю, вам нужно найти какой-нибудь обучающий материал или текст по линейному программированию / целочисленному программированию, поскольку у вас, похоже, нет вопроса pyomo, но основные вопросы по математическому программированию. Вот как это делается, и использование двоичной переменной является правильным. Выпишите математику и проверьте ее. Решатель выберет значения 1/0 для x[m, p] минимизации цели. Если вы хотите увидеть выражение цели, вы можете добавить строку mdl.obj.pprint() в код и увидеть выражение и подключить двоичные значения, чтобы увидеть математику.

4. @AirSquid И, не могли бы вы объяснить, как вывести минимальное значение, полученное для каждой таблицы из целевой функции?

5. @AirSquid Я скептически отношусь к команде «sum ()» в выражении. Означает ли это суммирование всех комбинаций или это просто означает массив?