【问题标题】:OR-Tools: 0-1 klapsack with constraint on item sourceOR-Tools:0-1 klapsack,对项目来源有限制
【发布时间】:2021-06-10 10:21:41
【问题描述】:

我正在尝试对物品来源进行 0-1 背包优化。我从 ortools 网站 (ortool example) 中获取了示例,并尝试添加一个约束,以便只能从背包中的每个所有者那里挑选一件物品。

我有一个包含相关权重 (data['weights'])、值 (data['values']) 和源 (data['owns']) 的项目列表。我想找到放入背包的最佳物品组合,因为我知道每个来源只有一件物品可以放入背包。

我不知道如何写约束。

如果您查看下面的代码并且有 1 个背包,那么最佳解决方案应该是从所有者 0 中最多取 1 件物品,从所有者 1 中取一件,从所有者 2 中取一件,这遵循重量约束和物品的唯一性挑选(体重低于 100)。

这是我使用的代码(取自 ortool 多背包示例):

from ortools.linear_solver import pywraplp


def create_data_model():
    """Create the data for the example."""
    data = {}
    data['weights'] = [48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36]
    data['values'] = [10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25]
    data['owns'] = [1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0]
    data['owners'] = list(range(3))
    data['items'] = list(range(len(data['weights'])))
    data['num_items'] = len(data['weights'])
    data['bins'] = []
    data['bin_capacity'] = 100
    return data

def main():
    data = create_data_model()

    # Create the mip solver with the SCIP backend.
    solver = pywraplp.Solver.CreateSolver('SCIP')

    # Variables
    # x[i, j] = 1 if item i is packed in bin j.
    x = {}
    for i in data['items']:
        for j in data['bins']:
            x[(i, j)] = solver.IntVar(0, 1, 'x_%i_%i' % (i, j))

    # y[i, j] = 1 if item i from owner j in bin.
    y = {}
    for i in data['owns']:
        for j in data['owners']:
            y[(i, j)] = solver.IntVar(0, 1, 'y_%i_%i' % (i, j))

    # Constraints
    # Each item can be in at most one bin.
    for i in data['items']:
        solver.Add(sum(x[i, j] for j in data['bins']) <= 1)
    # Each item can be at from one owner.
    # for i in data['items']:
    #     solver.Add(sum(y[i, j] for j in data['owners']) <= 1)
    # The amount packed in each bin cannot exceed its capacity.
    for j in data['bins']:
        solver.Add(
            sum(x[(i, j)] * data['weights'][i]
                for i in data['items']) <= data['bin_capacity'])

    # Objective
    objective = solver.Objective()

    for i in data['items']:
        for j in data['bins']:
            objective.SetCoefficient(x[(i, j)], data['values'][i])
    objective.SetMaximization()

    status = solver.Solve()

    if status == pywraplp.Solver.OPTIMAL:
        print('Total packed value:', objective.Value())
        total_weight = 0
        for j in data['bins']:
            bin_weight = 0
            bin_value = 0
            print('Bin ', j, '\n')
            for i in data['items']:
                if x[i, j].solution_value() > 0:
                    print('Item', i, '- weight:', data['weights'][i], ' value:',
                          data['values'][i])
                    bin_weight += data['weights'][i]
                    bin_value += data['values'][i]
            print('Packed bin weight:', bin_weight)
            print('Packed bin value:', bin_value)
            print()
            total_weight += bin_weight
        print('Total packed weight:', total_weight)
    else:
        print('The problem does not have an optimal solution.')


if __name__ == '__main__':
    main()

【问题讨论】:

  • 你应该使用 CP-SAT 求解器,因为你只有整数
  • 我有可能是浮点数的值。我只是让这个例子更简单。此外,我将如何整合所有者约束?
  • 有什么问题?除了复制粘贴一些示例之外,您的代码中还有其他内容吗?限制所有者只是意味着:get unique values in data['owns'] with their indices (potential 1 to n mapping)for each unique value, indices: add a constraint: sum(indices) &lt;= 1(假定索引链接到决定背包分配的二进制变量)
  • indices 是一个集合。不是标量。使用您的简单示例,第一个约束(3 个中的)看起来像:sum([x[0, :].sum(), x[1, :].sum(), x[2, :].sum(), x[3, :].sum(), x[4, :].sum()]) &lt;= 1: 用于汇总所有垃圾箱。现在求解器如何能够从所有者 1 中进行选择,他多次拥有项目 0、1、2、3、4? (不需要 y 变量!)
  • 如果我只根据项目索引,我怎么知道它是否与其他人在同一组中?例如,我可以选择项目 0 (w:48),将其标记为已选择,这样它就不会被再次选择,但是当我选择它时,我不知道如何强制其他所有者为 1 的人不会被选择也是。我同意它或多或少是示例代码,到目前为止我还没有设法在其中添加所有者约束。我尝试使用 y 变量并注释掉约束声明,但它不起作用。

标签: python optimization constraints knapsack-problem or-tools


【解决方案1】:

首先,我要感谢提供答案的@sascha!

我在代码下方附上(我使用 2 个垃圾箱,3 个不同的所有者):

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from ortools.linear_solver import pywraplp


def create_data_model():
    """Create the data for the example."""
    data = {}
    weights = [48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36]
    values = [10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25]
    owns = [0, 1, 2, 0, 1, 2, 2, 1, 0, 1, 2, 0, 0, 1, 2]
    # owns = [0 for _ in range(len(weights))]
    data['weights'] = weights
    data['values'] = values
    data['owners'] = [0, 1, 2]
    data['owns'] = owns
    data['items'] = list(range(len(weights)))
    data['num_items'] = len(weights)
    data['bins'] = list(range(2))
    data['bin_capacities'] = [150, 100]
    return data

def main():
    data = create_data_model()

    # Create the mip solver with the SCIP backend.
    solver = pywraplp.Solver.CreateSolver('SCIP')

    # Variables
    # x[i, j] = 1 if item i is packed in bin j.
    x = {}
    for i in data['items']:
        for j in data['bins']:
            x[(i, j)] = solver.IntVar(0, 1, 'x_%i_%i' % (i, j))

    # Constraints
    # Each item can be in at most one bin.
    for i in data['items']:
        solver.Add(sum(x[i, j] for j in data['bins']) <= 1)

    # Each item can be at from one owner.
    for o in data['owners']:
        for j in data['bins']:
            owner = []
            for i in data['items']:
                if data['owns'][i] == o:
                    owner.append(x[i, j])
            solver.Add(sum(owner) <= 1)

    # The amount packed in each bin cannot exceed its capacity.
    for j in data['bins']:
        solver.Add(
            sum(x[(i, j)] * data['weights'][i]
                for i in data['items']) <= data['bin_capacities'][j])

    # Objective
    objective = solver.Objective()

    for i in data['items']:
        for j in data['bins']:
            objective.SetCoefficient(x[(i, j)], data['values'][i])
    objective.SetMaximization()

    status = solver.Solve()

    if status == pywraplp.Solver.OPTIMAL:
        print('Total packed value:', objective.Value())
        total_weight = 0
        for j in data['bins']:
            bin_weight = 0
            bin_value = 0
            print('Bin ', j, '\n')
            for i in data['items']:
                if x[i, j].solution_value() > 0:
                    print('Item', i, '- weight:', data['weights'][i],
                          ' value:', data['values'][i],
                          ' owner:', data['owns'][i])
                    bin_weight += data['weights'][i]
                    bin_value += data['values'][i]
            print('Packed bin weight:', bin_weight)
            print('Packed bin value:', bin_value)
            print()
            total_weight += bin_weight
        print('Total packed weight:', total_weight)
    else:
        print('The problem does not have an optimal solution.')


if __name__ == '__main__':
    main()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-19
    • 1970-01-01
    • 1970-01-01
    • 2020-04-17
    • 1970-01-01
    • 2019-06-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多