Gekko - 最佳调度的不可行解决方案,与 gurobi 的比较

2024-06-19

我对 Gurobi 有点熟悉,但转向 Gekko,因为后者似乎有一些优势。不过,我遇到了一个问题,我将用我想象的苹果园来说明这一问题。 5周的收获期(#horizon: T=5)就在我们身上,我的——非常微薄的——产出将是:[3.0, 7.0, 9.0, 5.0, 4.0]我自己留一些苹果[2.0, 4.0, 2.0, 4.0, 2.0],剩下的农产品我会在农贸市场按以下价格出售:[0.8, 0.9, 0.5, 1.2, 1.5]。我有可容纳 6 个苹果的存储空间,因此我可以提前计划并在最佳时刻出售苹果,从而最大化我的收入。我尝试使用以下模型确定最佳时间表:

m       = GEKKO()
m.time  = np.linspace(0,4,5)
orchard   = m.Param([3.0, 7.0, 9.0, 5.0, 4.0])
demand    = m.Param([2.0, 4.0, 2.0, 4.0, 2.0]) 
price     = m.Param([0.8, 0.9, 0.5, 1.2, 1.5])

### manipulated variables
# selling on the market
sell                = m.MV(lb=0)
sell.DCOST          = 0
sell.STATUS         = 1
# saving apples
storage_out         = m.MV(value=0, lb=0)
storage_out.DCOST   = 0      
storage_out.STATUS  = 1 
storage_in          = m.MV(lb=0)
storage_in.DCOST    = 0
storage_in.STATUS   = 1

### storage space 
storage         = m.Var(lb=0, ub=6)
### constraints
# storage change
m.Equation(storage.dt() == storage_in - storage_out) 

# balance equation
m.Equation(sell + storage_in + demand == storage_out + orchard)

# Objective: argmax sum(sell[t]*price[t]) for t in [0,4]
m.Maximize(sell*price)
m.options.IMODE=6
m.options.NODES=3
m.options.SOLVER=3
m.options.MAX_ITER=1000
m.solve()

由于某种原因这是不可行的(错误代码 = 2)。有趣的是,如果设置demand[0] to 3.0, instead of 2.0(即等于orchard[0],该模型确实产生了成功的解决方案。

  1. 为什么会这样呢?
  2. 即使“成功”的输出值也有点奇怪:存储空间没有被使用一次,并且storage_out在最后一个时间步中没有受到适当的约束。显然,我没有正确地制定约束条件。我应该怎么做才能获得与 gurobi 输出相当的实际结果(参见下面的代码)?
output = {'sell'    : list(sell.VALUE),
        's_out'     : list(storage_out.VALUE),
        's_in'      : list(storage_in.VALUE), 
        'storage'   : list(storage.VALUE)}
df_gekko = pd.DataFrame(output)
df_gekko.head()

>   sell  s_out     s_in        storage
0   0.0   0.000000  0.000000    0.0
1   3.0   0.719311  0.719311    0.0
2   7.0   0.859239  0.859239    0.0
3   1.0   1.095572  1.095572    0.0
4   26.0  24.124924 0.124923    0.0 

Gurobi 模型解决了demand = [3.0, 4.0, 2.0, 4.0, 2.0]。请注意,gurobi 还产生了一个解决方案demand = [2.0, 4.0, 2.0, 4.0, 2.0]。这对结果只有很小的影响:nt=0 时出售的苹果变为1.

T = 5
m = gp.Model()
### horizon (five weeks)

### supply, demand and price data  
orchard   = [3.0, 7.0, 9.0, 5.0, 4.0]
demand    = [3.0, 4.0, 2.0, 4.0, 2.0] 
price     = [0.8, 0.9, 0.5, 1.2, 1.5]

### manipulated variables
# selling on the market
sell = m.addVars(T)

# saving apples
storage_out = m.addVars(T)
m.addConstr(storage_out[0] == 0)
storage_in  = m.addVars(T)

# storage space
storage = m.addVars(T)
m.addConstrs((storage[t]<=6) for t in range(T))
m.addConstrs((storage[t]>=0) for t in range(T))
m.addConstr(storage[0] == 0)

# storage change
#m.addConstr(storage[0] == (0 - storage_out[0]*delta_t + storage_in[0]*delta_t))
m.addConstrs(storage[t] == (storage[t-1] - storage_out[t] + storage_in[t]) for t in range(1, T))

# balance equation
m.addConstrs(sell[t] + demand[t] + storage_in[t] == (storage_out[t] + orchard[t]) for t in range(T))

# Objective: argmax sum(a_sell[t]*a_price[t] - b_buy[t]*b_price[t])
obj = gp.quicksum((price[t]*sell[t]) for t in range(T))
m.setObjective(obj, gp.GRB.MAXIMIZE)
m.optimize()

output:

    sell    storage_out storage_in  storage
0   0.0     0.0         0.0         0.0
1   3.0     0.0         0.0         0.0
2   1.0     0.0         6.0         6.0
3   1.0     0.0         0.0         6.0
4   8.0     6.0         0.0         0.0

您可以通过以下方式获得成功的解决方案:

m.options.NODES=2

问题是它正在求解主节点之间的平衡方程NODES=3。你的微分方程有一个线性解,所以NODES=2应该足够准确。

以下是改进解决方案的其他几种方法:

  • 对将库存移入或移出仓库设置小额处罚。否则,求解器可以找到大的任意值storage_in = storage_out.
  • I used m.Minimize(1e-6*storage_in) and m.Minimize(1e-6*storage_out).
  • 由于初始条件通常是固定的,因此我在开始时使用零值只是为了确保计算第一个点。
  • 如果整数变量以整数单位出售和存储,我也会切换到它们。如果您想要整数解,则需要切换到 APPT 求解器SOLVER=1.
 Successful solution
 
 ---------------------------------------------------
 Solver         :  APOPT (v1.0)
 Solution time  :  0.058899999999999994 sec
 Objective      :  -17.299986
 Successful solution
 ---------------------------------------------------
 

Sell
[0.0, 0.0, 4.0, 1.0, 1.0, 8.0]
Storage Out
[0.0, 0.0, 1.0, 0.0, 0.0, 6.0]
Storage In
[0.0, 1.0, 0.0, 6.0, 0.0, 0.0]
Storage
[0.0, 1.0, 0.0, 6.0, 6.0, 0.0]

这是修改后的脚本。

from gekko import GEKKO
import numpy as np

m       = GEKKO(remote=False)
m.time  = np.linspace(0,5,6)
orchard   = m.Param([0.0, 3.0, 7.0, 9.0, 5.0, 4.0])
demand    = m.Param([0.0, 2.0, 4.0, 2.0, 4.0, 2.0]) 
price     = m.Param([0.0, 0.8, 0.9, 0.5, 1.2, 1.5])

### manipulated variables
# selling on the market
sell                = m.MV(lb=0, integer=True)
sell.DCOST          = 0
sell.STATUS         = 1
# saving apples
storage_out         = m.MV(value=0, lb=0, integer=True)
storage_out.DCOST   = 0      
storage_out.STATUS  = 1 
storage_in          = m.MV(lb=0, integer=True)
storage_in.DCOST    = 0
storage_in.STATUS   = 1

### storage space 
storage         = m.Var(lb=0, ub=6, integer=True)
### constraints
# storage change
m.Equation(storage.dt() == storage_in - storage_out) 

# balance equation
m.Equation(sell + storage_in + demand == storage_out + orchard)

# Objective: argmax sum(sell[t]*price[t]) for t in [0,4]
m.Maximize(sell*price)
m.Minimize(1e-6 * storage_in)
m.Minimize(1e-6 * storage_out)
m.options.IMODE=6
m.options.NODES=2
m.options.SOLVER=1
m.options.MAX_ITER=1000
m.solve()

print('Sell')
print(sell.value)
print('Storage Out')
print(storage_out.value)
print('Storage In')
print(storage_in.value)
print('Storage')
print(storage.value)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Gekko - 最佳调度的不可行解决方案,与 gurobi 的比较 的相关文章

  • 是否有充分的理由不使用 UTC 存储时间?

    我想知道是否有任何充分的理由以 UTC GMT 以外的任何时间存储时间信息 我相信这是所有软件工程的坚实规则 转换为本地时间只是出于显示目的而在 UI 层发生的转换 我还见过需要翻译才能正确实现算法的情况 用于处理午夜日期更改等 一般来说
  • javascript中的快捷方式融合优化

    我听说 lodash 和其他 javascript 库使用一种称为 快捷融合 的技术进行优化 但在任何地方都找不到该技术的详细解释 任何人都可以提供链接或举例解释 快捷方式融合 的含义吗 对于一个非常简短且不清楚的解释 https wiki
  • 如何将完整的日期格式拆分为日期和时间?

    我有很多格式为我的示例所示的字符串 我必须解析它们 我正在尝试确定今天是哪根弦 我的问题是 时间快到了 我只需要比较那个日期 接下来我想检查时间是否在 after 和 before 的两个时间戳 HH mm ss 之间 但存在问题 日期几乎
  • C for 循环索引:新 CPU 中的前向索引更快吗?

    在我订阅的邮件列表上 两位知识渊博的 IMO 程序员正在讨论一些优化的代码 并说了以下内容 在 5 8 年前发布的 CPU 上 向后迭代 for 循环稍微快一些 e g for int i x 1 i gt 0 i 因为比较i归零比将其与其
  • 将 cookie 设置为在当天结束时过期

    我想设置一个 cookie 并让它在一天结束时过期 这有效 但 24 小时后过期 setcookie route upgrade voted true time 86400 这不起作用 setcookie route upgrade vot
  • Java Integer CompareTo() - 为什么使用比较与减法?

    我发现java lang Integer实施compareTo方法如下 public int compareTo Integer anotherInteger int thisVal this value int anotherVal an
  • requestAnimationFrame 垃圾回收

    我正在使用 Chrome 开发工具 v27 中的时间轴分析以下代码的内存使用情况
  • Java - 在特定日期执行方法[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我需要在每年的特定日期执行一个方法 我该如何在java中执行此操作 Thanks Chris 按优先顺序排列 The Quartz htt
  • 调度算法,找到设定长度的所有非重叠区间

    我需要为我的管理应用程序实现一种算法 该算法将告诉我何时可以将任务分配给哪个用户 我实现了一个蛮力解决方案 它似乎有效 但我想知道是否有更有效的方法来做到这一点 为了简单起见 我重写了算法以对数字列表进行操作 而不是数据库查询等 下面我将尝
  • 优化我的表现

    我正在开发一个使用 Zend Framework 1 11 Doctrine 2 一些 Symfony 2 组件以及其他工具和库的项目 我正在尝试使用 Xdebug 和 Webgrind 优化性能 我已经发现了一些瓶颈 例如解析 Ini 配
  • Java 中查看 ArrayList 是否包含对象的最有效方法

    我有一个 Java 对象的 ArrayList 这些对象有四个字段 我用其中两个字段来将对象视为与另一个对象相等 我正在寻找最有效的方法 给定这两个字段 以查看数组是否包含该对象 问题在于这些类是基于 XSD 对象生成的 因此我无法修改类本
  • 同一索引操作上的不同估计行?

    简介和背景 我必须优化一个简单的查询 下面的示例 重写几次后 我认识到同一个索引操作的估计行数会根据查询的编写方式而有所不同 最初 该查询执行了聚集索引扫描 因为生产中的表包含二进制列 该表相当大 大约 100 GB 并且全表扫描执行起来需
  • Gekko - 最佳调度的不可行解决方案,与 gurobi 的比较

    我对 Gurobi 有点熟悉 但转向 Gekko 因为后者似乎有一些优势 不过 我遇到了一个问题 我将用我想象的苹果园来说明这一问题 5周的收获期 horizon T 5 就在我们身上 我的 非常微薄的 产出将是 3 0 7 0 9 0 5
  • 更改计划的开始日期以优化资源

    我有很多工作需要在特定的时间间隔执行 然而 我们每天完成这项工作的资源有限 因此 我正在尝试优化开始时间日期 开始时间日期只能向前移动 不能向后移动 以便每天使用的资源与我们的预算更加不相似 这些函数在下面的示例中使用 Function t
  • 获取一个字节中 4 个最低有效位的最快方法是什么(C++)?

    我正在谈论这个 如果我们有字母 A 十进制为 77 十六进制为 4D 我正在寻找最快获得D的方法 我想了两个办法 给定 x 是一个字节 x lt lt 4 x gt gt 4 x 16 还有其他办法吗 哪一个更快 简洁很好 解释更好 x 0
  • @Schedule 无法注入 EJB

    我正在使用 JBoss AS 7 1 1 我需要一些作业在特定的日期和时间运行 所以我不使用 Quartz 而是尝试使用 Schedule 注释 当我测试时 它运行得很好 但是当我开始实施我的实际业务时 我真正的问题开始了 所以 这就是我的
  • 约束优化 R:另一个例子

    我正在尝试在 R 中执行约束优化 我已经查看了这些帖子和其他一些帖子 R 中的约束优化 https stackoverflow com questions 5436630 constrained optimization in r R 中的
  • 如何查看我在收件箱中收到的短信时间?

    我可以从收件箱中读取消息 Uri uriSMSURI Uri parse content sms inbox Cursor cur getContentResolver query uriSMSURI null null null null
  • LoggerFactory.getLogger(ClassName.class) 与 LoggerFactory.getLogger(this.getClass().getName())

    我正在努力提高我的 Java 优化技能 为了实现这一目标 我制作了一个旧程序 并且正在尽力使其变得更好 在此程序中 我使用 SL4J 进行日志记录 为了获取记录器 我做了 private static final Logger logger
  • 接受 05/05/1999 和 5/5/1999 等的日期时间解析

    有没有一种简单的方法来解析可能为 MM DD yyyy M D yyyy 或某种组合的日期 即 在一位数字的日期或月份之前 零是可选的 要手动执行此操作 可以使用 String dateFields dateString split int

随机推荐