PuLP Python - Как линеаризовать неравенство с переменной

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

Можно ли сформулировать ограничение, которое динамически сравнивает переменную с/между двумя константами:

i.e.

lower_bound, operator_1 (>, >=), variable, operator_2(<, <=) up_bound

Описание проблемы

Общая сумма подлежащих оплате тонн, т. е. то, за что покупатель будет платить, зависит от содержания меди в товарном материале.

  1. У каждого клиента есть ряд условий оплаты, выраженных в рабочих границах спецификации меди, согласно приведенному ниже примеру данных:

Данные клиентов

import io
import pandas as pd

customer_payables = """customer, tier, specvalue_1, specoperator_1, specvalue_2, \
specoperator_2, coeff
    'abc', 1, 0, '>=', 20, '<=', 96.0
    'abc', 2, 20, '>', 24, '<=', 96.5 
    'abc', 3, 24, '>', 100, '<=', 96.65
    'def', 1, 0, '>=', 20, '<=', 96.0
    'def', 2, 20, '>=', 22, '<=', 96.66
    'def', 3, 22, '>=', 100', '<=', 97.0
    """

_cust_data = io.StringIO(customer_payables)
cust_df = pd.read_csv(_cust_data, sep=",")
cust_df = cust_df.set_index('customer')
cust_df
  1. У меня есть датафрейм доступного материала в тоннах с конкретным содержанием меди на двух складах с двумя складами. Обратите внимание, что качество этого материала со временем меняется:

## Данные о запасах

stockpile_data_dict = {
    'Warehouse 1':{
        'Stockpile 1': {'cu': 27}, 
        'Stockpile 2': {'cu': 18}
        },
        'Warehouse 2': {
            'Stockpile 1':{'cu': 22}, 
            'Stockpile 2': {'cu': 16}}}
  
stockpile_df = pd.concat({k: pd.DataFrame(v).T for k, v in stockpile_data_dict.items()}, axis=0) 
stockpile_df

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

cu_spec_of_sale_material = pulp.LpVariable.dicts(
    'Copper spec of sale material',
    ((warehouse, stockpile)
      for warehouse, stockpile in stockpile_df.index),
      cat='Continuous')

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

В терминах псевдокода он оценивает что-то вроде следующего:

for customer, effective_tier in effective_payable_coefficient:
  if customer_lower_bound_val < cu_spec_sales_material[warehouse, stockpile] < customer_up_bound_val:
    PULP += effective_payable_coefficient[customer, effective_tier] == 1

Я не очень часто пользуюсь Pulp, поэтому, пожалуйста, потерпите меня.

Вся помощь принята с благодарностью, спасибо.


person cmp    schedule 19.02.2021    source источник
comment
Не могли бы вы дать четкое краткое описание вашей проблемы? Как бы вы сформулировали свое ограничение, если бы линейность не была проблемой?   -  person Christian    schedule 19.02.2021
comment
Мой вопрос заключается именно в том, что я не уверен, какой подход здесь выбрать, учитывая характер проблемы. У меня есть целочисленная переменная, представляющая спецификацию cu материала, которую мне нужно оценить в сравнении с фреймом данных подлежащих оплате условий. Это возможно? Спасибо.   -  person cmp    schedule 19.02.2021


Ответы (1)


Я думаю, вы ищете линейную формулировку для импликации:

a < x < b => y = 1

где a, b — константы, x — непрерывная переменная, а y — двоичная переменная.

Мы можем записать это как:

 x ≤ a + M1 ⋅ δ + M1 ⋅ y
 x ≥ b - M2 ⋅ (1-δ) - M2 ⋅ y
 δ,y ∈ {0,1}
 x ∈ [L,U]
 M1 = U-a
 M2 = b-L

δ — еще одна двоичная переменная, L, U — нижняя/верхняя границы x, M1, M2 — константы.

Интуиция: эти ограничения реализуют смысл:

 y = 0 =>  x ≤ a or x ≥ b

что означает, что если a < x < b у нас должно быть y=1.

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

person Erwin Kalvelagen    schedule 20.02.2021
comment
Это выглядит именно то, что я ищу, большое спасибо. Нельзя ли, пожалуйста, показать, что они могут представлять в содержании задачи? Я вижу, например, что x будет представлять собой концентрацию меди, а a и b представляют собой нижний/верхний предел платежа? благодарю вас - person cmp; 20.02.2021
comment
a < x < b => y = 1 это всего лишь if customer_lower_bound_val < cu_spec_sales_material[warehouse, stockpile] < customer_up_bound_val: PULP += effective_payable_coefficient[customer, effective_tier] == 1 проще говоря. - person Erwin Kalvelagen; 21.02.2021