【问题标题】:How to constrain optimization based on number of negative values of variable in pyomo如何根据pyomo中变量的负值数量限制优化
【发布时间】:2020-09-16 04:30:13
【问题描述】:

我正在使用一个 pyomo 模型(主要由其他人编写,由我更新),该模型可优化电动汽车充电(即,在给定时间步长内,车辆将导入或导出多少电量)。优化变量 (u) 是功率,目标是在给定每个时间步的充电成本的情况下最小化总充电成本。

我正在尝试编写一个新的优化函数来限制模型允许每辆车输出功率的次数(即,设置 u

代码很长,但我把核心部分放在下面:

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 个术语。

错误:从 data=None 构造组件“max_call_rule”失败: ValueError: 无法创建超过 3 个术语的 InequalityExpression。

我是使用 pyomo 的新手,我怀疑这个错误意味着我正在尝试做一些从根本上不适用于优化程序的事情。那么--有没有更好的方法来限制我的变量 u 可以小于 0 的次数?

【问题讨论】:

  • 计数一般需要二进制变量。如果模型是 MIP,请注意所有约束都必须是线性的。
  • 啊,当然是@ErwinKalvelagen。这就说得通了;谢谢。人们通常有什么方法可以将二进制近似为线性约束? (我无法想象我是唯一一个想要这样做的人。)或者我真的需要以不同的方式重新定位我的约束吗?我可以想到一些可以接受的方法,但只是想知道如果我做不到我会有什么选择......
  • 您需要引入二进制变量b[t,v],条件为u[t,v]&lt;=-1 =&gt;b[t,v]=1。然后你可以做sum(t, b[t,v]) &lt;= max_calls[v]。这都是非常标准的mip建模。看起来您对此并不熟悉,因此您可能应该告诉您的主管您缺少这方面的一些专业知识(这没有错:假设每个人都熟悉 MIP 建模是不现实的)。解决方案是进行一些培训,或聘请具有适当专业知识的人员。
  • 谢谢。是的,我绝对不是 MIP 建模方面的专家。如果您有任何培训资源可以推荐,我将不胜感激!
  • 有一些混合整数规划的在线课程。抱歉,我没有建议。

标签: python optimization pyomo


【解决方案1】:

如果您要尽量减少车辆输出功率的次数,您可以引入一个允许/禁止车辆放电的二元变量。您希望这个变量随着时间和车辆被索引。

请注意,如果您的模型的其余部分是 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)

如果您添加到目标函数中的是与车辆排放的总能量(而不是事件数量)相关的成本(而不是添加到目标函数中的成本),您希望引入两个单独的变量用于充电和放电 - 都是非负的,然后将“净放电”(现在您称为 u)定义为 Expression,这是放电和充电之间的区别。

然后,您可以将成本分量添加到您的目标函数,它是所有放电功率的总和,并将其乘以与之相关的成本。

【讨论】:

    猜你喜欢
    • 2019-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-22
    • 2022-09-23
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多