pykp 3.1.2__tar.gz → 3.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pykp
3
- Version: 3.1.2
3
+ Version: 3.2.0
4
4
  Summary: Tooling for sampling and solving instances of the 0-1 Knapsack Problem.
5
5
  Author-email: Hassan Andrabi <hrs.andrabi@gmail.com>
6
6
  License: MIT
@@ -41,19 +41,19 @@ def _initialise_grid(
41
41
  The first array corresponds to normalised capacities, and the second
42
42
  to normalised profits.
43
43
  """
44
- norm_c_step_size = 1 / resolution[0]
45
- norm_p_step_size = 1 / resolution[1]
44
+ norm_c_step_size = 1 / resolution[1]
45
+ norm_p_step_size = 1 / resolution[0]
46
46
 
47
47
  grid = np.meshgrid(
48
- np.linspace(0, 1 - norm_c_step_size, resolution[0]),
49
- np.linspace(1 - norm_p_step_size, 0, resolution[1]),
48
+ np.linspace(0, 1 - norm_c_step_size, resolution[1]),
49
+ np.linspace(1 - norm_p_step_size, 0, resolution[0]),
50
50
  )
51
51
 
52
52
  return grid
53
53
 
54
54
 
55
55
  def _sample_instance(
56
- num_items: int, norm_c: float, norm_p: float
56
+ num_items: int, norm_c: float, norm_p: float, rng: np.random.Generator
57
57
  ) -> tuple[list[Item], float, float]:
58
58
  """
59
59
  Sample a knapsack instance based on normalised capacity and profit targets.
@@ -71,6 +71,8 @@ def _sample_instance(
71
71
  Normalised capacity factor to scale the total weight.
72
72
  norm_p : float
73
73
  Normalised profit factor to scale the total value.
74
+ rng : np.random.Generator
75
+ Random number generator for sampling.
74
76
 
75
77
  Returns
76
78
  -------
@@ -81,8 +83,8 @@ def _sample_instance(
81
83
  target_profit : float
82
84
  The scaled target profit.
83
85
  """
84
- weights = np.random.uniform(0, 1, num_items)
85
- profits = np.random.uniform(0, 1, num_items)
86
+ weights = rng.uniform(0.001, 1, num_items)
87
+ profits = rng.uniform(0.001, 1, num_items)
86
88
 
87
89
  capacity = sum(weights) * norm_c
88
90
  target_profit = sum(profits) * norm_p
@@ -99,6 +101,7 @@ def _simulate_cell_solvability(
99
101
  num_items: int,
100
102
  samples: int,
101
103
  solver: Callable,
104
+ rng: np.random.Generator,
102
105
  progress: tqdm,
103
106
  ) -> float:
104
107
  """Estimate the solvability of a grid cell.
@@ -121,6 +124,8 @@ def _simulate_cell_solvability(
121
124
  solver : Callable
122
125
  A solver function that takes items and capacity as arguments and
123
126
  returns an optimal node or array of optimal nodes.
127
+ rng : np.random.Generator
128
+ Random number generator for sampling.
124
129
  progress : tqdm
125
130
  Progress bar for tracking iterations.
126
131
 
@@ -133,11 +138,14 @@ def _simulate_cell_solvability(
133
138
  """
134
139
  score = 0
135
140
  for _ in range(samples):
136
- norm_c_draw = np.random.uniform(norm_c_range[0], norm_c_range[1])
137
- norm_p_draw = np.random.uniform(norm_p_range[0], norm_p_range[1])
141
+ norm_c_draw = rng.uniform(norm_c_range[0], norm_c_range[1])
142
+ norm_p_draw = rng.uniform(norm_p_range[0], norm_p_range[1])
138
143
 
139
144
  items, capacity, target_profit = _sample_instance(
140
- num_items=num_items, norm_c=norm_c_draw, norm_p=norm_p_draw
145
+ num_items=num_items,
146
+ norm_c=norm_c_draw,
147
+ norm_p=norm_p_draw,
148
+ rng=rng,
141
149
  )
142
150
  result = solver(items=items, capacity=capacity)
143
151
  if isinstance(result, list):
@@ -187,6 +195,7 @@ def phase_transition(
187
195
  samples: int = 100,
188
196
  solver: str = "branch_and_bound",
189
197
  resolution: tuple[int, int] = (41, 41),
198
+ seed: int | None = None,
190
199
  path: str = None,
191
200
  ) -> tuple[np.ndarray, np.ndarray]:
192
201
  """Compute the phase transition matrix for knapsack instances.
@@ -218,9 +227,10 @@ def phase_transition(
218
227
 
219
228
  Returns
220
229
  -------
221
- grid : tuple of np.ndarray
222
- The mesh grid for normalszed capacities (x-axis) and profits
223
- (y-axis).
230
+ coordinate_matrices : tuple of np.ndarray
231
+ The coordinate matrices for normalised capacities and normalised
232
+ profits. The first matrix corresponds to normalised capacities,
233
+ and the second to normalised profits.
224
234
  phase_transition : np.ndarray
225
235
  A 2D matrix of solvability (ranging from 0.0 to 1.0) corresponding
226
236
  to each cell in `grid`.
@@ -233,9 +243,12 @@ def phase_transition(
233
243
  resolution: tuple[int, int], optional
234
244
  Resolution of the normalised capacity-normalised profit grid.
235
245
  The first element corresponds to the resolution of normalised
236
- capacity, and the second to the resolution of normalised profit.
246
+ profit, and the second to the resolution of normalised capacity.
237
247
  Defaults to (41, 41).
238
- path (str, optional): Path to save the phase transition to. Defaults
248
+ seed : int | None, optional
249
+ Seed for sampling. Defaults to None.
250
+ path str, optional:
251
+ Path to save the phase transition to. Defaults
239
252
  to None.
240
253
 
241
254
  Examples
@@ -309,6 +322,7 @@ def phase_transition(
309
322
  [(p, p + 1 / resolution[1]) for p in grid[1].flatten()],
310
323
  )
311
324
  )
325
+ rng = np.random.default_rng(seed)
312
326
 
313
327
  phase_transition = []
314
328
  with tqdm(total=samples * len(points)) as progress:
@@ -320,12 +334,11 @@ def phase_transition(
320
334
  samples=samples,
321
335
  solver=solver,
322
336
  progress=progress,
337
+ rng=rng,
323
338
  )
324
339
  phase_transition.append(solvability)
325
340
 
326
- phase_transition = np.array(phase_transition).reshape(
327
- (resolution[0], resolution[1])
328
- )
341
+ phase_transition = np.array(phase_transition).reshape(resolution)
329
342
 
330
343
  if path:
331
344
  _save_phase_transition(phase_transition, grid, path)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pykp
3
- Version: 3.1.2
3
+ Version: 3.2.0
4
4
  Summary: Tooling for sampling and solving instances of the 0-1 Knapsack Problem.
5
5
  Author-email: Hassan Andrabi <hrs.andrabi@gmail.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pykp"
7
- version = "3.1.2"
7
+ version = "3.2.0"
8
8
  description = "Tooling for sampling and solving instances of the 0-1 Knapsack Problem."
9
9
  authors = [
10
10
  { name = "Hassan Andrabi", email = "hrs.andrabi@gmail.com" }
@@ -22,8 +22,8 @@ def test_phase_transition_returns_correct_shape(resolution):
22
22
  resolution=resolution,
23
23
  path=None,
24
24
  )
25
- assert grid[0].shape == (resolution[1], resolution[0])
26
- assert grid[1].shape == (resolution[1], resolution[0])
25
+ assert grid[0].shape == resolution
26
+ assert grid[1].shape == resolution
27
27
 
28
28
  assert solvability_matrix.shape == resolution
29
29
 
@@ -97,3 +97,34 @@ def test_phase_transition_values_in_range():
97
97
  assert np.all(solvability_matrix >= 0.0) and np.all(
98
98
  solvability_matrix <= 1.0
99
99
  ), "Solvability values are not all within [0, 1]."
100
+
101
+
102
+ @pytest.mark.parametrize("seed", [1, 2, 3])
103
+ def test_phase_transition_reproducibility(seed):
104
+ """Test that the phase transition is reproducible."""
105
+ resolution = (2, 2)
106
+ num_items = 5
107
+ samples = 5
108
+ grid, solvability_matrix = metrics.phase_transition(
109
+ num_items=num_items,
110
+ samples=samples,
111
+ solver="branch_and_bound",
112
+ resolution=resolution,
113
+ path=None,
114
+ seed=seed,
115
+ )
116
+
117
+ grid2, solvability_matrix2 = metrics.phase_transition(
118
+ num_items=num_items,
119
+ samples=samples,
120
+ solver="branch_and_bound",
121
+ resolution=resolution,
122
+ path=None,
123
+ seed=seed,
124
+ )
125
+
126
+ assert np.all(grid[0] == grid2[0]), "Inconsistent grid."
127
+ assert np.all(grid[0] == grid2[0]), "Inconsistent grid."
128
+ assert np.all(solvability_matrix == solvability_matrix2), (
129
+ "Inconsistent solvability matrix."
130
+ )
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes