OR-TOOLS - 如何解决有序分配问题?
Posted
技术标签:
【中文标题】OR-TOOLS - 如何解决有序分配问题?【英文标题】:OR-TOOLS - how to solve ordered allocation problem? 【发布时间】:2021-01-07 18:01:41 【问题描述】:我有 'n' 个表,我有 'm' 个盒子。 工作是将所有的箱子堆放在桌子上。
问题: 有哪些不同的可能组合? 重要提示:所有盒子放在桌子上时都是有序的,就像堆栈一样。我需要知道堆栈中每个框的排名。
如何用 ORTOOL 约束规划/SAT 来解决这个问题? 什么是最好的策略?什么变量/约束?
(我不期望代码,但只是建议......除非你是一个快速的开发人员:) 谢谢
from ortools.sat.python import cp_model
class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback):
def __init__(self, variables):
cp_model.CpSolverSolutionCallback.__init__(self)
self.__variables = variables
self.__solution_count = 0
def on_solution_callback(self):
self.__solution_count += 1
for v in self.__variables:
print('%s=%i' % (v, self.Value(v)))
print("")
def solution_count(self):
return self.__solution_count
def main():
variables = []
model = cp_model.CpModel()
#################################################
nb_tables = 3
nb_boxes = 4
for box in range(nb_boxes):
box_to_table = model.NewIntVar(0, nb_tables - 1, 'box_'+str(box)+'_to_table')
variables.append(box_to_table)
ranking_variables = []
for box in range(nb_boxes):
rank_of_box_on_its_table = model.NewIntVar(0, nb_boxes - 1, 'rank_of_box_'+str(box)+'_on_its_table')
variables.append(rank_of_box_on_its_table)
ranking_variables.append(rank_of_box_on_its_table)
# the next line is not good because the ranking is global
# and not local to each table. how to manage that?
model.AddAllDifferent(ranking_variables)
#################################################
solver = cp_model.CpSolver()
solution_printer = VarArraySolutionPrinter(variables)
status = solver.SearchForAllSolutions(model, solution_printer)
print('Status = %s' % solver.StatusName(status))
print('Number of solutions found: %i' % solution_printer.solution_count())
main()
还有布尔版本:
#################################################
nb_tables = 3
nb_boxes = 4
for box in range(nb_boxes):
this_box_vars = []
for table in range(nb_tables):
box_in_table = model.NewBoolVar('box_'+str(box)+'_in_table_' + str(table))
variables.append(box_in_table)
this_box_vars.append(box_in_table)
model.Add(sum(this_box_vars) == 1)
ranking_variables = []
for box in range(nb_boxes):
rank_of_box_on_its_table = model.NewIntVar(0, nb_boxes - 1, 'rank_of_box_'+str(box)+'_on_its_table')
variables.append(rank_of_box_on_its_table)
ranking_variables.append(rank_of_box_on_its_table)
# the next line is not good because the ranking is global
# and not local to each table. how to manage that?
model.AddAllDifferent(ranking_variables)
#################################################
【问题讨论】:
CP-SAT,还有很多布尔变量。 感谢劳伦特!好吧,布尔值不会给我在堆栈上的排名......或者你在这里有一个技巧? 【参考方案1】:不要使用整数变量。
经验法则:
如果您看到 AllDifferent 约束,请将其删除,并将整数变量替换为布尔变量列表。 加和(bool_vars) == 1x[i][j][k]
是一个布尔变量,表示盒子 i 在表 j 的位置 k。
y[j][k]
表示是否有框在表 j 的位置 k。
每个框只出现一次:
forall i: Sum on j, k box[i][j][k] == 1
每个位置最多被一个盒子占据:
forall j, k: sum on i box[i][k][k] <= 1
如果某个盒子在某处,则表示此某处已被占用:
forall i, j, k: box[i][j][k] implies y[j][k]
如果一个位置被占用了,那么这个位置一定有一个盒子:
forall j, k: bool_or([y[j][k].Not(), box[0][j][k], .., box[n - 1][j][k]])
位置必须在一张桌子上从0开始密集占据:
forall j, k (except last position): y[j][k].Not() implies y[j][k + 1].Not()
如果你想要一个盒子的排名
forall i: rank[i] == sum over j, k box[i][j][k] * k
【讨论】:
我实施了您的建议...但是,如何计算该排名?谢谢洛朗! 数一数你面前的那个? 对不起,我不知道如何以简单的方式做到这一点 请准确描述您的问题以及至少一种解决方案。 哇!谢谢劳伦特!伟大的!问题看起来很简单,但实现的方法并不简单!以上是关于OR-TOOLS - 如何解决有序分配问题?的主要内容,如果未能解决你的问题,请参考以下文章
如何通过 SCIP 求解器获得 Google OR-Tools 和 Python 中的相对 MIP 差距?
OR-Tools / SCIP - 如何使用指标约束来解决 MIP 问题?