실제 문제에 QIO 적용

완료됨

이제 QIO의 기본 사항을 이해했으므로 광물 배송 문제로 돌아가겠습니다. 우주선은 두 컨테이너 배송 간에 광물 덩어리를 분배하는 방법을 최적화해야 합니다. 즉, 각 덩어리는 무게인 $w$가 연결되어 있으며 해당 무게를 두 개의 세트인 $W_A$ 및 $W_B$로 분할하려고 합니다.

두 세트는 광물 덩어리가 컨테이너 A 또는 컨테이너 B에 적재되는지 여부에 해당하며, 두 컨테이너 간 무게 차이로 $\Delta$를 정의합니다.

이 짧은 애니메이션은 최적화 프로그램이 광물을 분배할 수 있는 한 가지 방법을 보여 줍니다. 최적화 프로그램의 실행 시간은 단계에 따라 측정됩니다. 각 단계에서 애니메이션은 그때까지 찾은 최적의 솔루션을 보여 줍니다.

다음 섹션에서는 문제 해결에 양자 유도 최적화를 사용합니다.

참고

이 문제는 숫자 분할 문제 로도 알려져 있습니다. 해당 문제는 NP 하드로 분류되지만 실제로는 QIO보다 훨씬 더 빠르게 대략적인 솔루션을 제공할 수 있는 다른 효율적인 알고리즘이 있습니다. 그럼에도 불구하고, 친숙하고 이해하기 쉬운 예제이므로 화물 부하 분산 문제를 사용하여 QIO 개념을 설명하고 Azure Quantum 서비스를 사용하는 방법을 설명합니다. 이후 모듈 Azure Quantum을 사용하여 작업 매장 일정 최적화 문제 해결에서는 QIO가 실질적인 이점을 제공할 수 있는 더 어려운 문제를 해결합니다.

문제 표현하기

먼저 지정된 컨테이너의 무게 관련 식을 살펴보겠습니다. 이는 단순히 컨테이너에 포함하는 모든 광물 덩어리 무게의 합계입니다. 합계는 다음 수식으로 표현되며, 여기서 $w_i$는 덩어리 i 의 무게입니다.

광물 무게의 합계를 보여 주는 수식

컨테이너 간 무게 차이인 $\Delta$가 최대한 작은 솔루션이 이상적입니다.

비용 함수를 생성하기 위해 다른 컨테이너의 무게에서 다른 컨테이너 하나의 무게를 빼는 수식입니다.

해당 수식은 컨테이너 A의 무게 합계에서 컨테이너 B의 무게 합계를 뺍니다.

문자 H 는 비용 함수를 나타내는 데 사용됩니다. 해당 표기법은 ‘이징 모델’이라고 알려진 최적화 문제를 정의하는 데 사용하는 모델에서 유래했습니다. 이 모델에서 에너지(비용을 나타냄)는 변수가 +1 또는 -1의 값을 갖는 해밀턴 연산자로 주어집니다. 여기에서 목표는 이 양식에 최적화를 매핑하는 것입니다.

문제 구체화

이제 개별 광물 덩어리인 i 가 컨테이너 A 또는 컨테이너 B에 할당되는지 여부를 나타내는 변수인 $x_i$를 도입합니다.

두 컨테이너 중 하나에 덩어리 i 를 할당하므로 변수 $x_i$는 두 가지 값을 사용할 수 있으므로 이진 변수가 될 수 있습니다. 편의를 위해, 도출될 수 있는 두 값을 1-1 이라고 하겠습니다. 값 1 은 광물 덩어리가 컨테이너 A에, 값 -1 은 광물 덩어리가 컨테이너 B에 배치되는 것에 해당합니다. $x_i$를 1 또는 -1 로 결정하므로 이 최적화 문제를 ‘이징(Ising) 문제’라고 부릅니다.

변수 $x_i$를 도입함으로써 수식을 다음과 같이 단순화할 수 있습니다.

비용 함수 계산을 단순화하기 위해 이진 변수를 도입하는 수식

문제의 재구체화

마지막으로 한 가지를 더 변경해야 이 문제를 해결할 수 있습니다.

비용 함수 H 에는 한 가지 결함이 있습니다. 최소 비용 솔루션은 모든 $x_i$ 변수를 -1과 같게 설정하여 추출된 광물을 전부 컨테이너 B 에 할당하는 것입니다. 하지만 이 방법은 적절하지 않습니다. 이 문제를 해결하려면 수식의 오른쪽을 제곱하여 음수가 될 수 없도록 만듭니다.

비용 함수가 음수가 아닌지 확인하기 위해 이전 계산을 제곱하는 수식

이 최종 모델은 필수 속성이 포함된 비용 함수를 제공해 줍니다.

  • 모든 광물이 한 컨테이너에 적재된 경우 함수 값이 가장 큽니다. 따라서, 가장 적합하지 않은 솔루션입니다.
  • 화물 컨테이너의 부하가 완벽하게 분산될 경우, 사각형 내부 합의 값은 0 이 됩니다. 즉, 함수 값이 가장 작거나 최적화 값입니다.

Azure Quantum을 사용하여 문제 해결

이제 복합적 최적화 문제를 이징 형식으로 강제 변환하는 방법을 알아보았으므로 QIO 해결기를 호출하여 솔루션을 컴퓨팅할 준비가 되었습니다. Python을 사용하여 Azure Quantum 서비스에 연결합니다. 이 섹션의 나머지 부분을 진행하면서 코드 시퀀스를 Jupyter Notebook으로 복사하여 실행합니다. 자유롭게 문제 매개 변수를 사용하여 결과가 어떻게 변경되는지 관찰합니다.

설치 프로그램

먼저 Azure에서 이전에 배포한 작업 영역에 연결할 수 있는 Workspace 개체를 인스턴스화해야 합니다. 작업 영역을 아직 설정하지 않은 경우 Azure Quantum 시작하기 모듈로 돌아갑니다. 웹 인터페이스에서 또는 Azure CLI를 통해 az quantum workspace show를 실행하여 검색할 수 있는 다음 설정을 입력해야 합니다.

from azure.quantum import Workspace

# Copy the following settings for your workspace
workspace = Workspace(
    subscription_id=    "", # add your subscription_id
    resource_group=     "", # add your resource_group
    name=               "", # add your workspace name
    location=           ""  # add your workspace location (for example, "westus")
)

workspace.login()

문제 인스턴스화

Azure Quantum 서비스에 문제를 제출하려면 먼저 Problem 인스턴스를 만들어야 합니다. 해당 인스턴스는 비용 함수 세부 정보 및 모델링할 문제 종류와 같은 필요한 모든 정보를 저장하는 Python 개체입니다.

PUBO, QUBO, 이징(Ising)과 같은 몇 가지 문제 유형을 이미 소개했습니다. 이 예제에서는 ProblemType.ising을 통해 사용할 수 있는 이징 유형을 사용합니다.

비용 함수를 표현하기 위해 Term 개체를 사용하는 수식화를 적용합니다. 궁극적으로 모든 다항식 비용 함수는 단순한 곱의 합계로 작성할 수 있습니다. 즉, 함수는 다음과 같은 형식으로 다시 작성될 수 있습니다. 여기서 $p_k$는 문제 변수 $x_0, x_1, \dots$의 곱을 나타냅니다.

$$ H(x) = \sum_k \alpha_k \cdot p_k(x_0, x_1, \dots) $$

$$ \text{e.g. } H(x) = 5 \cdot (x_0) + 2 \cdot (x_1 \cdot x_2) - 3 \cdot ({x_3}^2) $$

이 형식에서 합계의 모든 항에는 계수 $\alpha_k$ 및 곱 $p_k$가 있습니다. Problem 인스턴스에서 합의 각 항은 계수에 해당하는 c 및 곱에 해당하는 indices 매개 변수가 포함된 Term 개체로 표현됩니다. 특히 indices 매개 변수는 항에 나타나는 모든 변수의 인덱스로 채워집니다. 예를 들어 $2 \cdot (x_1 \cdot x_2)$ 항은 Term(c=2, indices=[1,2]) 개체로 변환됩니다.

앞에서 파생시킨 비용 함수를 사용하여 예제를 실행하겠습니다. $n$ 광물 덩어리의 경우 인덱스 $i$는 $0$에서 $n-1$로 실행됩니다.

$$ H(x) = \left(\sum_{i} w_{i} \cdot x_{i}\right)^2 $$

사각형을 확장한 후 이중 합계를 얻습니다. 여기서 $j$도 $n$개 덩어리를 인덱싱합니다.

$$ H(x) = \sum_i \sum_j (w_i \cdot w_j) \cdot (x_i \cdot x_j) $$

다르게 보일 수 있지만, 이 이중 합계는 $n^2$ 항을 사용하여 큰 합계를 작성하는 또 다른 방법일 뿐입니다. 변환 $k=i \cdot n + j$를 $\alpha_k = w_i \cdot w_j$ 및 $p_k(x_0, \cdots, x_{n-1}) = x_i \cdot x_j$와 함께 사용하면 단일 합 형식을 얻게 됩니다.

$$ H(x) = \sum_{k=0}^{n^2-1} \alpha_k \cdot p_k(x_0, \cdots, x_{n-1}) $$

일부 숫자를 연결해 보겠습니다. 무게가 $w_i \in [2,4,7]$이고, 따라서 인덱스가 $i,j \in \{0,1,2\}$인 광물 덩어리 3개를 사용합니다. 이중 합계 형식은 보다 쉽게 작업할 수 있으므로 해당 형식을 사용하겠습니다. $i$의 모든 값에 대해 $j$의 각 값에 하나씩 세 개 항을 추가합니다.

$$ H(x) = (2 \cdot 2) \cdot (x_0 \cdot x_0) + (2 \cdot 4) \cdot (x_0 \cdot x_1) + (2 \cdot 7) \cdot (x_0 \cdot x_2) $$ $$ \hspace{25pt} +\ (4 \cdot 2) \cdot (x_1 \cdot x_0) + (4 \cdot 4) \cdot (x_1 \cdot x_1) + (4 \cdot 7) \cdot (x_1 \cdot x_2) $$ $$ \hspace{25pt} +\ (7 \cdot 2) \cdot (x_2 \cdot x_0) + (7 \cdot 4) \cdot (x_2 \cdot x_1) + (7 \cdot 7) \cdot (x_2 \cdot x_2) $$

이는 이징 문제이기 때문에 변수 $x_i$는 $1$ 또는 $-1$의 값을 사용할 수 있으며, 이는 $x_i^2$가 항상 $1$와 같음을 의미합니다. $H$의 실제 값에는 관심이 없고 해당 값이 최소화되는 것만 중요하므로 해당 항을 안전하게 제거할 수 있습니다. 이제 9개 항 대신 6개 항을 포함하는 다음과 같은 최종 형식이 제공됩니다.

$$ H(x) = 8 \cdot (x_0 \cdot x_1) + 14 \cdot (x_0 \cdot x_2) + 8 \cdot (x_1 \cdot x_0) + 28 \cdot (x_1 \cdot x_2) + 14 \cdot (x_2 \cdot x_0) + 28 \cdot (x_2 \cdot x_1) $$

Python에서는 다음 Terms를 도입합니다.

  • Term(c =  8, indices = [0, 1])
  • Term(c = 14, indices = [0, 2])
  • Term(c =  8, indices = [1, 0])
  • Term(c = 28, indices = [1, 2])
  • Term(c = 14, indices = [2, 0])
  • Term(c = 28, indices = [2, 1])

다음 함수는 for 루프를 사용하여 많은 무게에 해당하는 Term 만들기를 일반화합니다. 광물 무게의 배열을 사용하고 비용 함수를 포함하는 Problem 개체를 반환합니다.

from typing import List
from azure.quantum.optimization import Problem, ProblemType, Term

def createProblemForMineralWeights(mineralWeights: List[int]) -> Problem:
    terms: List[Term] = []

    # Expand the squared summation
    for i in range(len(mineralWeights)):
        for j in range(len(mineralWeights)):
            if i == j:
                # Skip the terms where i == j as they form constant terms in an Ising problem and can be disregarded.
                continue

            terms.append(
                Term(
                    c = mineralWeights[i] * mineralWeights[j],
                    indices = [i, j]
                )
            )

    # Return an Ising-type problem
    return Problem(name="Freight Balancing Problem", problem_type=ProblemType.ising, terms=terms)

Azure Quantum에 문제를 제출하기 전에 무게를 통해 광물 덩어리 목록을 정의함으로써 문제를 인스턴스화합니다.

# This array contains the weights of all the mineral chunks
mineralWeights = [1, 5, 9, 21, 35, 5, 3, 5, 10, 11]

# Create a problem for the given list of minerals:
problem = createProblemForMineralWeights(mineralWeights)

Azure Quantum에 문제 제출

이제 다음 ParallelTempering 해결기를 사용하여 Azure Quantum에 문제를 제출할 준비가 되었습니다.

참고

여기서는 시간 제한이 100초인 매개 변수 없는 ‘병렬 템퍼링’ 해결기를 사용합니다. 사용할 수 있는 해결기에 관한 자세한 내용은 Microsoft QIO 공급자 설명서 페이지를 참조하세요. 그러나 해결기 선택 및 튜닝은 이 모듈의 범위를 벗어납니다.

from azure.quantum.optimization import ParallelTempering
import time

# Instantiate a solver to solve the problem
solver = ParallelTempering(workspace, timeout=100)

# Optimize the problem
print('Submitting problem...')
start = time.time()
result = solver.optimize(problem)
timeElapsed = time.time() - start
print(f'Result in {timeElapsed} seconds: ', result)
Submitting problem...
.......
Result in 35.41556143760681 seconds:  {'version': '1.0', 'configuration': {'0': 1, '1': -1, '2': 1, '3': 1, '4': -1, '5': -1, '6': -1, '7': -1, '8': 1, '9': 1}, 'cost': -2052.0, 'parameters': {'all_betas': [0.00020408163265306123, 0.0010031845282727856, 0.004931258069052868, 0.024240112818991428, 0.00020408163265306123, 0.00041416312947479666, 0.0008405023793001501, 0.0017057149691356173, 0.0034615768230851457, 0.007024921700835206, 0.014256371424073268, 0.028931870679351317, 0.058714319100389226, 0.00020408163265306123, 0.0003216601955060876, 0.000506979878727771, 0.0007990687098552142, 0.0012594401274306443, 0.001985047612326009, 0.003128702935041415, 0.0049312580690528685, 0.007772328229454337, 0.012250238227336452, 0.019308028713685834, 0.030432059025318557, 0.04796503207311015, 0.07559936381105262, 0.00020408163265306123, 0.0002853639172320586, 0.0003990195697643234, 0.0005579423586529702, 0.000780161423569038, 0.0010908866075247, 0.0015253684103382742, 0.0021328970135012235, 0.0029823940494438134, 0.004170231478526455, 0.0058311645933360684, 0.008153619454858395, 0.011401069057563778, 0.015941923261808107, 0.022291323383991948, 0.031169582869598398, 0.043583903904173556, 0.06094264037716683, 0.08521506986401543, 0.00020408163265306123, 0.0002661133962019146, 0.0003470000642267741, 0.0004524726913109797, 0.0005900043184095882, 0.0007693394594342792, 0.0010031845282727856, 0.001308108124995844, 0.0017057149691356171, 0.002224176656606702, 0.002900227698828882, 0.0037817682692016645, 0.004931258069052867, 0.006430141778288393, 0.0083846196467327, 0.010933172089261346, 0.01425637142407326, 0.018589675944162696, 0.02424011281899142, 0.031608031858238926, 0.04121547145476594, 0.05374314651596505, 0.0700786790855087, 0.09137948893466513], 'replicas': 70, 'sweeps': 600}}

해결기는 일부 메타데이터와 함께 Python 사전 형식으로 결과를 반환했습니다. 보다 사람이 읽기 좋은 형식을 위해 다음 함수를 사용하여 솔루션의 의미에 관한 요약을 출력합니다.

def printResultSummary(result):
    # Print a summary of the result
    containerAWeight = 0
    containerBWeight = 0
    for chunk in result['configuration']:
        chunkAssignment = result['configuration'][chunk]
        chunkWeight = mineralWeights[int(chunk)]
        container = ''
        if chunkAssignment == 1:
            container = 'A'
            containerAWeight += chunkWeight
        else:
            container = 'B'
            containerBWeight += chunkWeight

        print(f'Mineral chunk {chunk} with weight {chunkWeight} was placed on Container {container}')

    print(f'\nTotal weights: \n\tContainer A: {containerAWeight} tons \n\tContainer B: {containerBWeight} tons')

printResultSummary(result)
Chunk 0 with weight 1 was placed on Container A
Chunk 1 with weight 5 was placed on Container B
Chunk 2 with weight 9 was placed on Container A
Chunk 3 with weight 21 was placed on Container A
Chunk 4 with weight 35 was placed on Container B
Chunk 5 with weight 5 was placed on Container B
Chunk 6 with weight 3 was placed on Container B
Chunk 7 with weight 5 was placed on Container B
Chunk 8 with weight 10 was placed on Container A
Chunk 9 with weight 11 was placed on Container A

Total weights:
    Container a: 52 tons
    Container b: 53 tons

좋습니다! 해결기는 컨테이너가 서로 1톤 내에 있도록 하는 파티션을 찾았습니다. 이 문제 인스턴스의 경우 부하가 완벽하게 분산된 솔루션이 존재하지 않으므로 이 결과는 만족스럽니다.

비용 함수 개선

빌드한 비용 함수는 지금까지 잘 작동하지만 생성된 Problem을 더 자세히 살펴보겠습니다.

print(f'The problem has {len(problem.terms)} terms for {len(mineralWeights)} mineral chunks:')
print(problem.terms)
The problem has 90 terms for 10 mineral chunks:
[{'c': 5, 'ids': [0, 1]}, {'c': 9, 'ids': [0, 2]}, {'c': 21, 'ids': [0, 3]}, {'c': 35, 'ids': [0, 4]}, {'c': 5, 'ids': [0, 5]}, {'c': 3, 'ids': [0, 6]}, {'c': 5, 'ids': [0, 7]}, {'c': 10, 'ids': [0, 8]}, {'c': 11, 'ids': [0, 9]}, {'c': 5, 'ids': [1, 0]}, {'c': 45, 'ids': [1, 2]}, {'c': 105, 'ids': [1, 3]}, {'c': 175, 'ids': [1, 4]}, {'c': 25, 'ids': [1, 5]}, {'c': 15, 'ids': [1, 6]}, {'c': 25, 'ids': [1, 7]}, {'c': 50, 'ids': [1, 8]}, {'c': 55, 'ids': [1, 9]}, {'c': 9, 'ids': [2, 0]}, {'c': 45, 'ids': [2, 1]}, {'c': 189, 'ids': [2, 3]}, {'c': 315, 'ids': [2, 4]}, {'c': 45, 'ids': [2, 5]}, {'c': 27, 'ids': [2, 6]}, {'c': 45, 'ids': [2, 7]}, {'c': 90, 'ids': [2, 8]}, {'c': 99, 'ids': [2, 9]}, {'c': 21, 'ids': [3, 0]}, {'c': 105, 'ids': [3, 1]}, {'c': 189, 'ids': [3, 2]}, {'c': 735, 'ids': [3, 4]}, {'c': 105, 'ids': [3, 5]}, {'c': 63, 'ids': [3, 6]}, {'c': 105, 'ids': [3, 7]}, {'c': 210, 'ids': [3, 8]}, {'c': 231, 'ids': [3, 9]}, {'c': 35, 'ids': [4, 0]}, {'c': 175, 'ids': [4, 1]}, {'c': 315, 'ids': [4, 2]}, {'c': 735, 'ids': [4, 3]}, {'c': 175, 'ids': [4, 5]}, {'c': 105, 'ids': [4, 6]}, {'c': 175, 'ids': [4, 7]}, {'c': 350, 'ids': [4, 8]}, {'c': 385, 'ids': [4, 9]}, {'c': 5, 'ids': [5, 0]}, {'c': 25, 'ids': [5, 1]}, {'c': 45, 'ids': [5, 2]}, {'c': 105, 'ids': [5, 3]}, {'c': 175, 'ids': [5, 4]}, {'c': 15, 'ids': [5, 6]}, {'c': 25, 'ids': [5, 7]}, {'c': 50, 'ids': [5, 8]}, {'c': 55, 'ids': [5, 9]}, {'c': 3, 'ids': [6, 0]}, {'c': 15, 'ids': [6, 1]}, {'c': 27, 'ids': [6, 2]}, {'c': 63, 'ids': [6, 3]}, {'c': 105, 'ids': [6, 4]}, {'c': 15, 'ids': [6, 5]}, {'c': 15, 'ids': [6, 7]}, {'c': 30, 'ids': [6, 8]}, {'c': 33, 'ids': [6, 9]}, {'c': 5, 'ids': [7, 0]}, {'c': 25, 'ids': [7, 1]}, {'c': 45, 'ids': [7, 2]}, {'c': 105, 'ids': [7, 3]}, {'c': 175, 'ids': [7, 4]}, {'c': 25, 'ids': [7, 5]}, {'c': 15, 'ids': [7, 6]}, {'c': 50, 'ids': [7, 8]}, {'c': 55, 'ids': [7, 9]}, {'c': 10, 'ids': [8, 0]}, {'c': 50, 'ids': [8, 1]}, {'c': 90, 'ids': [8, 2]}, {'c': 210, 'ids': [8, 3]}, {'c': 350, 'ids': [8, 4]}, {'c': 50, 'ids': [8, 5]}, {'c': 30, 'ids': [8, 6]}, {'c': 50, 'ids': [8, 7]}, {'c': 110, 'ids': [8, 9]}, {'c': 11, 'ids': [9, 0]}, {'c': 55, 'ids': [9, 1]}, {'c': 99, 'ids': [9, 2]}, {'c': 231, 'ids': [9, 3]}, {'c': 385, 'ids': [9, 4]}, {'c': 55, 'ids': [9, 5]}, {'c': 33, 'ids': [9, 6]}, {'c': 55, 'ids': [9, 7]}, {'c': 110, 'ids': [9, 8]}]

해당 개체는 단 10개 덩어리에 해당하는 많은 항입니다. 더 자세히 살펴보면 근본적으로 중복 항이 있음을 알 수 있습니다. 해당 항은 비용 함수를 빌드할 때 수식의 오른쪽을 제곱한 결과입니다. 예를 들어, 마지막 항인 {'w': 110, 'ids': [9, 8]}를 살펴봅니다. 나머지 항을 살펴보면 해당 항의 대칭 복사본인 {'w': 110, 'ids': [8, 9]}를 찾을 수 있습니다.

이 중복 항목은 비용 함수에서 똑같은 정보를 인코딩합니다. 그러나 비용 함수의 값은 실제로 중요하지 않고 오직 모양만 중요하므로 다음과 같이 해당 항을 생략할 수 있습니다.

이전 비용 함수에서 항 수를 줄이는 수식

이전 비용 함수에서 사각형을 두 개의 인덱스 $i$ 및 $j$에 대한 합계로 확장했습니다. 제약 조건 $i<j$를 사용하여 위에 언급된 항의 대칭 복사본을 제외합니다. 이와 함께 솔루션에 도움이 되지 않는 “constant” $i=j$ 항도 제외됩니다.

향상된 비용 함수를 구현하려면 다음과 같이 createProblemForMineralWeights 함수를 수정합니다.

def createSimplifiedProblemForMineralWeights(mineralWeights: List[int]) -> Problem:
    terms: List[Term] = []

    # Expand the squared summation
    for i in range(len(mineralWeights)-1):
        for j in range(i+1, len(mineralWeights)):
            terms.append(
                Term(
                    w = mineralWeights[i] * mineralWeights[j],
                    indices = [i, j]
                )
            )

    # Return an Ising-type problem
    return Problem(name="Freight Balancing Problem (Simplified)", problem_type=ProblemType.ising, terms=terms)

이로 인해 더 작은 문제가 발생하는지 확인해 보겠습니다.

# Create the simplified problem
simplifiedProblem = createSimplifiedProblemForMineralWeights(mineralWeights)
print(f'The simplified problem has {len(simplifiedProblem.terms)} terms')
The simplified problem has 45 terms

성공! 문제는 대부분 항의 절반입니다. 이제 실행하고 결과를 확인하겠습니다.

# Optimize the problem
print('Submitting simplified problem...')
start = time.time()
simplifiedResult = solver.optimize(simplifiedProblem)
timeElapsedSimplified = time.time() - start
print(f'Result in {timeElapsedSimplified} seconds: ', simplifiedResult)
printResultSummary(simplifiedResult)
Submitting simplified problem...
......
Result in 21.3847393989563 seconds:  {'version': '1.0', 'configuration': {'0': 1, '1': -1, '2': 1, '3': 1, '4': -1, '5': -1, '6': -1, '7': -1, '8': 1, '9': 1}, 'cost': -1026.0, 'parameters': {'all_betas': [0.00040816326530612246, 0.002006369056545571, 0.009862516138105735, 0.048480225637982856, 0.00040816326530612246, 0.0008283262589495933, 0.0016810047586003002, 0.0034114299382712347, 0.006923153646170291, 0.014049843401670412, 0.028512742848146536, 0.05786374135870263, 0.11742863820077845, 0.00040816326530612246, 0.0006433203910121752, 0.001013959757455542, 0.0015981374197104284, 0.0025188802548612886, 0.003970095224652018, 0.00625740587008283, 0.009862516138105737, 0.015544656458908674, 0.024500476454672904, 0.03861605742737167, 0.060864118050637114, 0.0959300641462203, 0.15119872762210523, 0.00040816326530612246, 0.0005707278344641172, 0.0007980391395286468, 0.0011158847173059405, 0.001560322847138076, 0.0021817732150494, 0.0030507368206765485, 0.004265794027002447, 0.005964788098887627, 0.00834046295705291, 0.011662329186672137, 0.01630723890971679, 0.022802138115127556, 0.03188384652361621, 0.044582646767983895, 0.062339165739196796, 0.08716780780834711, 0.12188528075433366, 0.17043013972803087, 0.00040816326530612246, 0.0005322267924038292, 0.0006940001284535482, 0.0009049453826219594, 0.0011800086368191764, 0.0015386789188685584, 0.002006369056545571, 0.002616216249991688, 0.0034114299382712343, 0.004448353313213404, 0.005800455397657764, 0.007563536538403329, 0.009862516138105733, 0.012860283556576787, 0.0167692392934654, 0.021866344178522693, 0.02851274284814652, 0.03717935188832539, 0.04848022563798284, 0.06321606371647785, 0.08243094290953187, 0.1074862930319301, 0.1401573581710174, 0.18275897786933026], 'replicas': 70, 'sweeps': 600}}
Chunk 0 with weight 1 was placed on Container A
Chunk 1 with weight 5 was placed on Container B
Chunk 2 with weight 9 was placed on Container A
Chunk 3 with weight 21 was placed on Container A
Chunk 4 with weight 35 was placed on Container B
Chunk 5 with weight 5 was placed on Container B
Chunk 6 with weight 3 was placed on Container B
Chunk 7 with weight 5 was placed on Container B
Chunk 8 with weight 10 was placed on Container A
Chunk 9 with weight 11 was placed on Container A

Total weights:
    Container A: 52 tons
    Container B: 53 tons

여기에서 볼 수 있듯이 솔루션의 품질은 두 비용 함수에 대해 동일합니다. 컨테이너 적재량은 서로 1톤 이내입니다. 이는 QIO 해결기 사용에 관한 중요한 사실을 보여 줍니다. 일반적으로 보다 최적화된 솔루션을 더 빠르게 생성하기 위해 비용 함수를 최적화할 수 있고 최적화해야 합니다.