Как ограничить оптимизацию на основе количества отрицательных значений переменной в pyomo - PullRequest
0 голосов
/ 28 мая 2020

Я работаю с моделью pyomo (в основном написанной кем-то другим, чтобы быть обновленной мной), которая оптимизирует электрическую c зарядку автомобиля (ie, сколько энергии будет импортировать или экспортировать автомобиль в заданный временной интервал ). Переменная оптимизации (u) - это мощность, и цель состоит в том, чтобы минимизировать общую стоимость зарядки с учетом стоимости зарядки на каждом временном шаге.

Я пытаюсь написать новую функцию оптимизации, чтобы ограничить количество раз, когда модель позволит каждому транспортному средству экспортировать мощность (ie, чтобы установить u <0). Я написал ограничение max_call_rule, которое подсчитывает количество раз u <0 и ограничивает его, чтобы оно было меньше заданного значения (max_calls) для каждого транспортного средства. (max_calls - словарь с меткой для каждого транспортного средства в паре с целым числом разрешенных вызовов.) </p>

Код очень длинный, но я поместил основные части ниже:

model.u = Var(model.t, model.v, domain=Integers, doc='Power used')
model.max_calls = Param(model.v, initialize = max_calls)

def max_call_rule(model, v):
      return len([x for x in [model.u[t, v] for t in model.t] if x < 0]) <= model.max_calls[v]
model.max_call_rule = Constraint(model.v, rule=max_call_rule, doc='Max call rule')

Этот подход не работает - я получаю следующую ошибку, когда пытаюсь запустить код.

ОШИБКА: правило не выполнено при создании выражения для ограничения max_call_rule с индексом 16: ValueError: невозможно создать InequalityExpression с более чем 3 членами.

ОШИБКА: создание компонента max_call_rule из данных = None failed: ValueError: Невозможно создать InequalityExpression с более чем 3 членами.

Я новичок в работе с pyomo и подозреваю, что эта ошибка означает, что я пытаюсь сделать что-то, что принципиально выиграло Не работаю с программой оптимизации. Итак - есть ли лучший способ ограничить количество раз, когда моя переменная u может быть меньше 0?

1 Ответ

0 голосов
/ 27 июня 2020

Если вы пытаетесь минимизировать количество раз, когда транспортные средства экспортируют энергию , вы можете ввести двоичную переменную, которая разрешает / запрещает разряд транспортных средств. Вы хотите, чтобы эта переменная индексировалась с течением времени и транспортных средств.

Обратите внимание, что если остальная часть вашей модели является LP (линейной, без каких-либо целочисленных переменных), это превратит ее в MIP / MILP. Существует значительная разница в объемах вычислений, необходимых для решения, и в типах решателей, которые вы можете использовать. Чем больше проблем, тем больше будет разница. Я не уверен, почему u в настоящее время установлен как Integers, что кажется довольно странным, учитывая, что он представляет мощность.

model.allowed_to_discharge = Var(model.t, model.v, within=Boolean)

def enforce_vehicle_discharging_logic_rule(model, t, v):
    """
    When `allowed_to_discharge[t,v]` is 1, 
    this constraint doesn't have any effect.
    When `allowed_to_discharge[t,v]` is 1, u[t,v] >= 0.
    Note that 1e9 is just a "big M", i.e. any big number
    that you're sure exceeds the maximum value of `model.u`.
    """
    return model.u[t,v] >= 0 - model.allowed_to_discharge[t,v] * 1e9

model.enforce_vehicle_discharging_logic = Constraint(
    model.t, model.v, rule=enforce_vehicle_discharging_logic_rule
)

Теперь, когда у вас есть двоичная переменная, вы можете подсчитывать события и в частности, вы можете назначить стоимость таким событиям и добавить ее в свою целевую функцию (на всякий случай у вас может быть только одна целевая функция, поэтому вы просто добавляете к ней «компонент», а не добавляете вторая целевая функция).

def objective_rule(model):
    return ( 
        ... # the same objective function as before
        + sum(model.u[t, v] for t in model.t for v in model.v) * model.cost_of_discharge_event
    )
model.objective = Objective(rule=objective_rule)

Если то, что вы вместо того, что вы добавляете к своей целевой функции, является стоимостью, связанной с полной энергией, выделяемой транспортными средствами (вместо числа событий), вы хотите ввести две отдельные переменные для зарядки и разрядки - обе неотрицательные, а затем определить «net разряд» (который сейчас вы называете u) как Expression, что является разницей между разрядкой и зарядкой.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...