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) == 1

x[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 问题?

如何在 Or-tools 中对变量进行排序?

如何在 or-tools 中定义复杂的目标函数?

Google OR-Tools(使用 SCIP 求解器) - 如何访问求解器找到的中间解决方案?

如何获取 Google OR-Tools 的进度日志?