【问题标题】:How to translate this binary optimization problem into a Python program?如何将这个二进制优化问题转化为 Python 程序?
【发布时间】:2023-02-09 05:30:35
【问题描述】:

我正在尝试为我的网站优化二进制问题。

数据包含大约 75 个项目,每个项目都有重量(50 到 1000 之间)和一个价格附加到它。这是一个数据 sn-p:

{"weighting":{
      "0":500,
      "1":50,
      "2":50,
      "3":50,
      "4":250,
      "5":1000
   },
   "price":{
      "0":4,
      "1":78,
      "2":75,
      "3":170,
      "4":5,
      "5":4
   }
}

我计算整个数据集的期望值

exp_val = (w1个p1个+ w2个p2个+ ... + wnpn) / 总和 (w1个+ w2个+ ... wn)

总和(w1个+ w2个+ ... wn) = 23665(考虑所有项目)

到目前为止一切顺利,但现在是棘手的部分。并非所有项目都是需要的,也就是说,它们的价值较低和/或权重较高,这会稀释我可以从中提取的资金池。

通过“阻止”或最多删除 3 个项目我只能从剩余的项目中提取,并通过这样做最大化加速价值函数。问题是:要删除哪些项目?由于价格随时间变化,我必须定期检查要移除的物品。

我从简单地删除权重最高和价格最低的项目开始,但我确信这只代表局部最优,并且会有更优化的策略。

在检查了一些网站之后,似乎混合整数线性规划 (MILP) 或特别是 BILP(二进制 ...) 可以解决我的问题,我找到了 https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.milp.html 但无法使其工作,因为我'我坚持将我的问题转化为代码。谁能帮我吗?

【问题讨论】:

  • 在编写代码之前,您应该在纸上正确地表述您的优化问题。入门:引入一个二进制变量 x_i,如果项目 i 被选中则为 1,否则为 0。然后,您想在约束 1/sum(x_i * w_i) = y 的情况下最大化 sum(y * x_i * w_i * p_i)。请注意,第二个约束等效于 1 = sum(y * x_i * w_i) 并且您可以线性化乘积 y * x_i,有关详细信息,请参阅this post

标签: python-3.x optimization scipy-optimize mixed-integer-programming


【解决方案1】:

利用@joni 的 cmets,我已将其翻译成代码。决策变量的乘积不是线性的,您必须通过添加另一个中间连续决策变量来使乘积线性化。

但是,如果您使用 Google-ortool 的 CP-SAT 求解器(我已经使用过),它可以处理一些非线性运算,例如决策变量的乘法、除法等,这是纯线性求解器不支持的。

代码清单

from ortools.sat.python import cp_model as cp

model = cp.CpModel()

data = {"weighting":{
      "0":500,
      "1":50,
      "2":50,
      "3":50,
      "4":250,
      "5":1000
   },
   "price":{
      "0":4,
      "1":78,
      "2":75,
      "3":170,
      "4":5,
      "5":4
   }
}

num_items = len(data["weighting"])

dv_select_items = {i : model.NewBoolVar("item_" + i) for i in data["weighting"]}

# constraint : keep only 3 items
model.Add(sum(dv_select_items[i] for i in dv_select_items) == 3)


y = model.NewIntVar(0, 1000000, "")

x_i_w_i_p_i = model.NewIntVar(0, 1000000, "") # x_i * w_i * p_i
model.Add(x_i_w_i_p_i == sum(dv_select_items[i] * data["weighting"][i] * data["price"][i] for i in dv_select_items))

y_x_i_w_i_p_i = model.NewIntVar(0, 1000000, "") # y * x_i * w_i * p_i
model.AddMultiplicationEquality(y_x_i_w_i_p_i, [x_i_w_i_p_i, y])

# 1 = sum(y * x_i * w_i)  # constraint
x_i_w_i = model.NewIntVar(0, 1000000, "")
model.Add(x_i_w_i == sum(dv_select_items[i] * data["weighting"][i] for i in dv_select_items))

y_x_i_w_i = model.NewIntVar(0, 1000000, "")
model.AddMultiplicationEquality(y_x_i_w_i, [y_x_i_w_i, y])

model.Add(1 == y_x_i_w_i)

model.Maximize(y_x_i_w_i_p_i)

solver = cp.CpSolver()
solver.Solve(model) 

# inspect the solution
objective_function_value = solver.ObjectiveValue()

[(i, solver.Value(dv_select_items[i])) for i in dv_select_items]
# 2st, 4th and 6th item gets selected

【讨论】:

  • 感谢您付出的努力。不过,这会删除最有利可图的项目。对于示例数据,预期值为 0.18。如果删除第 2、4 和 6 项,则预期值会下降到 0.11。我将进一步研究以找到解决方案!
【解决方案2】:

我试过以下方法:

data = {"w_default": {
    "0": 500,
    "1": 250,
    "2": 500,
    "3": 1000,
    "4": 1000,
    "5": 500
},
    "chaos": {
        "0": 8,
        "1": 5,
        "2": 5,
        "3": 4,
        "4": 4,
        "5": 2
    }
}

UB = 10000000
model = cp.CpModel()

num_items = len(data["w_default"])

# create boolean coefficients
dv_select_items = {i: model.NewBoolVar("item_" + str(i)) for i in data["w_default"]}

# constraint: remove exactly 3 items
# TODO: remove exactly 3 items
model.Add(sum(dv_select_items[i] for i in dv_select_items) == num_items)

##### numerator equation #####
# x_i * w_i * p_i
xi_wi_pi = model.NewIntVar(0, UB, "xi_wi_pi")
model.Add(xi_wi_pi == sum(dv_select_items[i] * data["w_default"][i] * data["chaos"][i] for i in dv_select_items))

##### denominator equation #####
xi_wi = model.NewIntVar(0, UB, "xi_wi")
model.Add(xi_wi == sum(dv_select_items[i] * data["w_default"][i] for i in dv_select_items))

y_xi_wi_pi = model.NewIntVar(0, UB, "y_xi_wi_pi")
model.AddDivisionEquality(y_xi_wi_pi, xi_wi_pi, xi_wi)

# set target
model.Maximize(xi_wi_pi)

solver = cp.CpSolver()
solver.Solve(model)

# inspect the solution
objective_function_value = solver.ObjectiveValue()
solution_info = solver.SolutionInfo()

result = [(i, solver.Value(dv_select_items[i])) for i in dv_select_items]

看来问题出在这部分:

##### denominator equation #####
xi_wi = model.NewIntVar(0, UB, "xi_wi")
model.Add(xi_wi == sum(dv_select_items[i] * data["w_default"][i] for i in dv_select_items))

y_xi_wi_pi = model.NewIntVar(0, UB, "y_xi_wi_pi")
model.AddDivisionEquality(y_xi_wi_pi, xi_wi_pi, xi_wi)

不管我怎么改写这个(尝试@Bhartendu Awasthi 提案

model.AddMultiplicationEquality(y_x_i_w_i, [y_x_i_w_i, y])

首先,但目标函数总是返回 0,尽管它应该

【讨论】:

    猜你喜欢
    • 2011-11-24
    • 2017-04-10
    • 1970-01-01
    • 2011-03-02
    • 2013-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多