Source code for qlauncher.problems.optimization.knapsack

 1"""This module contains the Knapsack class."""
 2
 3from collections.abc import Sequence
 4from typing import Literal
 5
 6import numpy as np
 7from pyqubo import Array, Binary
 8
 9from qlauncher import models
10from qlauncher.base import Problem
11
12
[docs] 13class Knapsack(Problem): 14 """ 15 Class for 0/1 Knapsack Problem. 16 17 This class represents the 0/1 Knapsack problem: maximize the total value of chosen items 18 subject to a capacity constraint on total weight. The class wraps a concrete instance 19 and can be passed into QLauncher. 20 """ 21 22 def __init__(self, values: Sequence[int], weights: Sequence[int], capacity: int, instance_name: str = 'unnamed'): 23 if len(values) != len(weights) or len(values) == 0: 24 raise ValueError('values and weights must have the same positive length') 25 if capacity < 0: 26 raise ValueError('capacity must be non-negative') 27 super().__init__((values, weights, capacity), instance_name=instance_name) 28 self.values = values 29 self.weights = weights 30 self.capacity = capacity 31
[docs] 32 @staticmethod 33 def from_preset(instance_name: Literal['default', 'small'], **kwargs) -> 'Knapsack': 34 values, weights, capacity = None, None, None 35 match instance_name: 36 case 'default': 37 values = [9, 6, 7, 5] 38 weights = [6, 4, 5, 3] 39 capacity = 9 40 case 'small': 41 values = [4, 3, 2] 42 weights = [3, 2, 2] 43 capacity = 5 44 case _: 45 raise ValueError(f'Preset f{instance_name} not defined') 46 return Knapsack(values, weights, capacity, instance_name)
47
[docs] 48 def to_bqm(self, penalty_weight: float = 2.0, value_weight: float = 1.0) -> models.BQM: 49 """ 50 Returns BQM for Knapsack problem. 51 """ 52 size = len(self.values) 53 54 x = Array.create('a_x', shape=size, vartype='BINARY') 55 56 m = 1 if self.capacity == 0 else int(np.ceil(np.log2(self.capacity + 1))) 57 y = Array.create('z_y', shape=m, vartype='BINARY') 58 slack = sum((2**k) * y[k] for k in range(m)) 59 60 weight_sum = sum(self.weights[i] * x[i] for i in range(size)) 61 penalty = weight_sum + slack - self.capacity 62 penalty *= penalty 63 value_term = sum(self.values[i] * x[i] for i in range(size)) 64 H: Binary = penalty_weight * penalty - value_weight * value_term 65 return models.BQM(H.compile())