본문 바로가기
  • ̀⁽ᵕ̈⁾ ́
M.S./OR-Tools

[OR-Tools 스터디] Solving a Multiple Knapsacks Problem

by j2j2y 2023. 2. 24.

이 섹션에서는 MIP solver와 CP-SAT solver를 사용하여 multiple knapsack에 대한 knapsack problem을 어떻게 푸는지에 대해 보여준다.

이 경우, knapsack보다는 bin이라고 containter를 지칭하는 것이 더 흔하다.

 

다음의 예제는 다섯개의 bin들에 사물들을 포장하는 최적의 방법을 어떻게 찾는지를 보여준다. 

 

Example

이전의 예제와 마찬가지로, 다양한 무게와 값들에 대한 사물의 집합으로 시작한다. 이 문제에서는 사물들을 부분집합으로 5개의 bin들에 포장하는 문제이며, 이들 각각의 최대 용량은 100이고, 전체 포장된 값은 최대여야한다. 

 

따르는 섹션에서는 이 문제를 푸는 프로그램을 보여준다. 

 

MIP Solution

 

from ortools.linear_solver import pywraplp

def MultipleKnapsacks():
    #create the data
    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

    ]

    assert len(data['weights']) == len(data['values'])
    data['num_items'] = len(data['weights'])
    data['all_items'] = range(data['num_items']) # 0에서 해당 값 사이의 값들을 리스트로

    data['bin_capacities'] = [100, 100, 100, 100, 100]
    data['num_bins'] = len(data['bin_capacities'])
    data['all_bins'] = range(data['num_bins'])

    #declare the MIP solver
    solver = pywraplp.Solver.CreateSolver('SCIP')
    if solver is None:
        print('SCIP solver unavailable.')
        return

    # x[i, b] = 1 if item i is packed in bin b.
    x = {}
    for i in data['all_items']:
        for b in data['all_bins']:
            x[i, b] = solver.BoolVar(f'x_{i}_{b}')
    #사물 i가 bin j에 위치해있으면 x[i, j]는 1이며, 그렇지 않으면 0이다.

    #each item is assigned to at most one bin
    for i in data['all_items']:
        solver.Add(sum(x[i, b] for b in data['all_bins']) <= 1)

    #the amount packed in each bin cannot exceed its capacity
    for b in data['all_bins']:
        solver.Add(
            sum(x[i, b] * data['weights'][i]
                for i in data['all_items']) <= data['bin_capacities'][b]
        )

    #define the objective
    #Maximize total value of packed items
    objective = solver.Objective()
    for i in data['all_items']:
        for b in data['all_bins']:
            objective.SetCoefficient(x[i, b], data['values'][i])
    objective.SetMaximization()

    # x[i, j] * data['values'][i]가 bin j에 들어있다면, 사물 i의 값을 objective에 더하는 것이다.
    #만약 i가 어떠한 bin에도 들어있지 않다면, 그것의 값은 objective에 기여할 수 없다.

    #invoke the solver
    status = solver.Solve()

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

 

CP SAT solution


from ortools.sat.python import cp_model

def CPSAT():
    model = cp_model.CpModel()

    #create the data
    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
    ]
    assert len(data['weights']) == len(data['values'])
    data['num_items'] = len(data['weights'])
    data['all_items'] = range(data['num_items'])

    data['bin_capacities'] = [100, 100, 100, 100, 100]
    data['num_bins'] = len(data['bin_capacities'])
    data['all_bins'] = range(data['num_bins'])

    #create the variables
    #x[i, b] = 1 if item i is packed in bin b.
    x = {}
    for i in data['all_items']:
        for b in data['all_bins']:
            x[i, b] = model.NewBoolVar(f'x_{i}_{b}')
    #each item is assigned to at most one bin
    for i in data['all_items']:
        model.AddAtMostOne(x[i, b] for b in data['all_bins'])
    #the amount packed in each bin cannot exceed its capacity
    for b in data['all_bins']:
        model.Add(
            sum(x[i, b] * data['weights'][i]
                for i in data['all_items']) <= data['bin_capacities'][b]
        )

    #create the objective function
    #maximize total value of packed items
    objective = []
    for i in data['all_items']:
        for b in data['all_bins']:
            objective.append(
                cp_model.LinearExpr.Term(x[i, b], data['values'][i])
            )
    model.Maximize(cp_model.LinearExpr.Sum(objective))

    #invoke the solver
    solver = cp_model.CpSolver()
    status = solver.Solve(model)

    if status == cp_model.OPTIMAL:
        print(f'Total packed value: {solver.ObjectiveValue()}')
        total_weight = 0
        for b in data['all_bins']:
            print(f'Bin {b}')
            bin_weight = 0
            bin_value = 0
            for i in data['all_items']:
                if solver.Value(x[i, b]) > 0:
                    print(f"Item {i} weight: {data['weights'][i]} value : {data['values'][i]}")
                    bin_weight += data['weights'][i]
                    bin_value += data['values'][i]
            print(f'Packed bin weight: {bin_weight}')
            print(f'Packed bin value: {bin_value}\n')
            total_weight += bin_weight
        print(f'Total packed weight: {total_weight}')
    else:
        print('The problem does not have an optimal solution.')

CPSAT()

 

 

 

Reference:

https://developers.google.com/optimization/pack/multiple_knapsack

 

여러 여행 가방 문제 해결하기  |  OR-Tools  |  Google Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. Switch to English 의견 보내기 여러 여행 가방 문제 해결하기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세

developers.google.com

 

댓글