Skip to content

Commit 73d74cb

Browse files
authored
Improve SOR algorithm (#24)
* Update boxstacks code * Add missing include * Improve boxstacks branching scheme * Improve SOR algorithm * Fix fixed_items in rectangle branching scheme * Improve rectangle branching scheme * Improve SOR algorithm * Fix rectangle branching scheme tests * Clean SOR code * Fix SOR algorithm * Clean SOR code
1 parent 11b7792 commit 73d74cb

23 files changed

+1767
-1715
lines changed

data/box/BUILD

-6
This file was deleted.

extern/CMakeLists.txt

+9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
# Enable FetchContent.
22
include(FetchContent)
33

4+
# Fetch fontanf/optimizationtools.
5+
FetchContent_Declare(
6+
optimizationtools
7+
GIT_REPOSITORY https://github.com/fontanf/optimizationtools.git
8+
GIT_TAG e96ddbe225c006911855a6c1ec31aa44fdacde2b
9+
#SOURCE_DIR "${PROJECT_SOURCE_DIR}/../optimizationtools/"
10+
EXCLUDE_FROM_ALL)
11+
FetchContent_MakeAvailable(optimizationtools)
12+
413
# Fetch boost.
514
set(BOOST_INCLUDE_LIBRARIES thread filesystem system program_options dynamic_bitset)
615
set(BOOST_ENABLE_CMAKE ON)

include/packingsolver/boxstacks/branching_scheme.hpp

+31-28
Original file line numberDiff line numberDiff line change
@@ -341,35 +341,30 @@ class BranchingScheme
341341
{
342342
if (node_1->last_bin_middle_axle_weight > node_2->last_bin_middle_axle_weight)
343343
return false;
344-
345-
ItemPos pos_1 = 0;
346-
ItemPos pos_2 = 0;
347-
ItemPos size_1 = node_1->uncovered_items.size();
348-
ItemPos size_2 = node_2->uncovered_items.size();
349-
for (;;) {
350-
//std::cout << "pos_1 " << pos_1 << " / " << node_1->uncovered_items.size() << std::endl;
351-
//std::cout << "pos_2 " << pos_2 << " / " << node_2->uncovered_items.size() << std::endl;
352-
if (node_1->uncovered_items[pos_1].xe
353-
> node_2->uncovered_items[pos_2].xe)
344+
if (node_1->uncovered_items.size() != node_2->uncovered_items.size())
345+
return false;
346+
for (ItemPos pos = 0; pos < (ItemPos)node_1->uncovered_items.size(); ++pos) {
347+
UncoveredItem& uncovered_item_1 = node_1->uncovered_items[pos];
348+
UncoveredItem& uncovered_item_2 = node_2->uncovered_items[pos];
349+
if (uncovered_item_1.xs != uncovered_item_2.xs
350+
|| uncovered_item_1.ys != uncovered_item_2.ys
351+
|| uncovered_item_1.xe != uncovered_item_2.xe
352+
|| uncovered_item_1.ye != uncovered_item_2.ye) {
353+
return false;
354+
}
355+
if (uncovered_item_1.ze > uncovered_item_2.ze)
354356
return false;
355-
if (node_1->uncovered_items[pos_1].ze
356-
> node_2->uncovered_items[pos_2].ze)
357+
if (uncovered_item_1.remaiing_weight < instance().item_weight()
358+
&& uncovered_item_1.remaiing_weight < uncovered_item_2.remaiing_weight)
359+
return false;
360+
if (uncovered_item_1.maximum_number_of_items < instance().number_of_items()
361+
&& uncovered_item_1.maximum_number_of_items < uncovered_item_2.maximum_number_of_items)
362+
return false;
363+
if (!uncovered_item_1.item_type_ids.empty()
364+
&& !uncovered_item_2.item_type_ids.empty()
365+
&& instance().item_type(uncovered_item_1.item_type_ids.back()).stackability_id
366+
!= instance().item_type(uncovered_item_2.item_type_ids.back()).stackability_id) {
357367
return false;
358-
if (pos_1 == size_1 - 1 && pos_2 == size_2 - 1)
359-
return true;
360-
if (node_1->uncovered_items[pos_1].ye
361-
== node_2->uncovered_items[pos_2].ye) {
362-
pos_1++;
363-
pos_2++;
364-
assert(pos_1 < size_1);
365-
assert(pos_2 < size_2);
366-
} else if (node_1->uncovered_items[pos_1].ye
367-
> node_2->uncovered_items[pos_2].ye) {
368-
pos_2++;
369-
assert(pos_2 < size_2);
370-
} else {
371-
pos_1++;
372-
assert(pos_1 < size_1);
373368
}
374369
}
375370
return true;
@@ -397,7 +392,7 @@ class BranchingScheme
397392
/** Parameters. */
398393
Parameters parameters_;
399394

400-
std::vector<ItemTypeId> predecessors_;
395+
std::vector<std::vector<ItemTypeId>> predecessors_;
401396

402397
ItemPos number_of_selected_items_ = 0;
403398

@@ -470,6 +465,14 @@ class BranchingScheme
470465
ItemPos uncovered_item_pos,
471466
DefectId defect_id) const;
472467

468+
/** Insertion of one item in a new stack. */
469+
void insertion_item_left(
470+
const std::shared_ptr<Node>& father,
471+
std::vector<Insertion>& insertions,
472+
ItemTypeId item_type_id,
473+
int rotation,
474+
ItemPos uncovered_item_pos) const;
475+
473476
};
474477

475478
std::ostream& operator<<(

include/packingsolver/boxstacks/instance.hpp

+11-2
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,11 @@ struct ItemType
146146
/** Get the volume of the item type. */
147147
inline Volume volume() const { return box.volume(); }
148148

149+
inline Area area() const { return box.x * box.y; }
150+
149151
inline Volume space() const { return volume(); }
150152

151-
bool can_rotate(int rotation) const { return ((rotations >> rotation) & 1); }
153+
inline bool can_rotate(int rotation) const { return ((rotations >> rotation) & 1); }
152154
};
153155

154156
std::ostream& operator<<(
@@ -195,7 +197,8 @@ struct BinType
195197
* Computed attributes
196198
*/
197199

198-
Area area() const { return box.x * box.y; }
200+
/** Get the floor area of the bin type. */
201+
inline Area area() const { return box.x * box.y; }
199202

200203
/** Get the volume of the bin type. */
201204
inline Volume volume() const { return box.volume(); }
@@ -273,6 +276,9 @@ class Instance
273276
/** Get the total volume of the bins. */
274277
inline Volume bin_volume() const { return bin_volume_; }
275278

279+
/** Get the total floor area of the bins. */
280+
inline Area bin_area() const { return bin_area_; }
281+
276282
/** Get the total weight of the bins. */
277283
inline Weight bin_weight() const { return bin_weight_; }
278284

@@ -461,6 +467,9 @@ class Instance
461467
/** Total bin volume. */
462468
Volume bin_volume_ = 0;
463469

470+
/** Total bin floor area. */
471+
Area bin_area_ = 0;
472+
464473
/** Total weight of the bins. */
465474
Weight bin_weight_ = 0.0;
466475

include/packingsolver/boxstacks/optimize.hpp

+57-57
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#include "packingsolver/boxstacks/solution.hpp"
44

55
#include "packingsolver/boxstacks/sequential_onedimensional_rectangle.hpp"
6-
#include "packingsolver/algorithms/sequential_value_correction.hpp"
76

87
#include "columngenerationsolver/linear_programming_solver.hpp"
98

@@ -12,62 +11,6 @@ namespace packingsolver
1211
namespace boxstacks
1312
{
1413

15-
struct OptimizeParameters: packingsolver::Parameters<Instance, Solution>
16-
{
17-
/** Optimization mode. */
18-
OptimizationMode optimization_mode = OptimizationMode::Anytime;
19-
20-
21-
/** Parameters of the sequential_onedimensional_rectangle algorithm. */
22-
SequentialOneDimensionalRectangleParameters sequential_onedimensional_rectangle_parameters;
23-
24-
/** Size of the queue in the tree search algorithm. */
25-
NodeId tree_search_queue_size = -1;
26-
27-
/** Guides used in the tree search algorithm. */
28-
std::vector<GuideId> tree_search_guides;
29-
30-
31-
/**
32-
* Time limit for the VbppToBpp bin packing sub-problem of the column
33-
* generation algorithm.
34-
*/
35-
double column_generation_vbpp_to_bpp_time_limit = -1;
36-
37-
/**
38-
* Size of the queue for the VbppToBpp bin packing sub-problem of the
39-
* column generation algorithm.
40-
*/
41-
NodeId column_generation_vbpp_to_bpp_queue_size = 256;
42-
43-
/**
44-
* Size of the queue for the pricing knapsack sub-problem of the column
45-
* generation algorithm.
46-
*/
47-
NodeId column_generation_pricing_queue_size = 256;
48-
49-
/** Linear programming solver. */
50-
columngenerationsolver::LinearProgrammingSolver linear_programming_solver
51-
= columngenerationsolver::LinearProgrammingSolver::CLP;
52-
53-
54-
/**
55-
* Size of the queue for the bin packing sub-problem of the dichotomic
56-
* search algorithm.
57-
*/
58-
NodeId dichotomic_search_queue_size = 32;
59-
60-
61-
/** Parameters for the Sequential Value Correction algorithm. */
62-
SequentialValueCorrectionParameters<Instance, Solution> sequential_value_correction_parameters;
63-
64-
/**
65-
* Size of the queue for the knapsack sub-problem of the sequential value
66-
* correction algorithm.
67-
*/
68-
NodeId sequential_value_correction_queue_size = 1024;
69-
};
70-
7114
struct Output: packingsolver::Output<Instance, Solution>
7215
{
7316
Output(const Instance& instance):
@@ -101,6 +44,8 @@ struct Output: packingsolver::Output<Instance, Solution>
10144
*/
10245
double sequential_onedimensional_rectangle_rectangle_time = 0.0;
10346

47+
bool sequential_onedimensional_rectangle_failed = false;
48+
10449
/** Time spent in the 'boxstacks' branching scheme. */
10550
double tree_search_time = 0.0;
10651

@@ -135,6 +80,61 @@ struct Output: packingsolver::Output<Instance, Solution>
13580
Counter number_of_tree_search_better = 0;
13681
};
13782

83+
using NewSolutionCallback = std::function<void(const Output&)>;
84+
85+
struct OptimizeParameters: packingsolver::Parameters<Instance, Solution>
86+
{
87+
/** Optimization mode. */
88+
OptimizationMode optimization_mode = OptimizationMode::Anytime;
89+
90+
/** New solution callback. */
91+
NewSolutionCallback new_solution_callback = [](const Output&) { };
92+
93+
/** Linear programming solver. */
94+
columngenerationsolver::LinearProgrammingSolver linear_programming_solver
95+
= columngenerationsolver::LinearProgrammingSolver::CLP;
96+
97+
/** Use tree search algorithm. */
98+
bool use_tree_search = false;
99+
100+
/** Use sequential single knapsack algorithm. */
101+
bool use_sequential_single_knapsack = false;
102+
103+
/** Parameters of the sequential_onedimensional_rectangle algorithm. */
104+
SequentialOneDimensionalRectangleParameters sequential_onedimensional_rectangle_parameters;
105+
106+
/** Guides used in the tree search algorithm. */
107+
std::vector<GuideId> tree_search_guides;
108+
109+
/**
110+
* Size of the queue for the pricing knapsack subproblem of the sequential
111+
* value correction algorithm.
112+
*/
113+
NodeId sequential_value_correction_subproblem_queue_size = 512;
114+
115+
/**
116+
* Size of the queue for the pricing knapsack subproblem of the column
117+
* generation algorithm.
118+
*/
119+
NodeId column_generation_subproblem_queue_size = 512;
120+
121+
/*
122+
* Parameters for non-anytime mode
123+
*/
124+
125+
/** Size of the queue in the tree search algorithm. */
126+
NodeId not_anytime_tree_search_queue_size = 512;
127+
128+
/**
129+
* Size of the queue in the single knapsack subproblem of the sequential
130+
* single knapsack algorithm.
131+
*/
132+
NodeId not_anytime_sequential_single_knapsack_subproblem_queue_size = 512;
133+
134+
/** Number of iterations of the sequential value correction algorithm. */
135+
Counter not_anytime_sequential_value_correction_number_of_iterations = 32;
136+
};
137+
138138
const Output optimize(
139139
const Instance& instance,
140140
const OptimizeParameters& parameters = {});

include/packingsolver/boxstacks/sequential_onedimensional_rectangle.hpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
#include "packingsolver/boxstacks/solution.hpp"
1717

1818
#include "packingsolver/onedimensional/optimize.hpp"
19-
#include "packingsolver/rectangle/optimize.hpp"
2019

2120
namespace packingsolver
2221
{
@@ -30,6 +29,12 @@ struct SequentialOneDimensionalRectangleOutput: packingsolver::Output<Instance,
3029
packingsolver::Output<Instance, Solution>(instance) { }
3130

3231

32+
/** Number of iterations. */
33+
Counter number_of_iterations = 0;
34+
35+
/** Number of stack splits. */
36+
Counter number_of_stack_splits = 0;
37+
3338
/**
3439
* Number of items in the solution found by the algorithm, before the
3540
* repair step.

include/packingsolver/boxstacks/solution.hpp

+39-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
#include "packingsolver/boxstacks/instance.hpp"
44

5-
#include <sstream>
6-
75
namespace packingsolver
86
{
97
namespace boxstacks
@@ -165,9 +163,22 @@ class Solution
165163
/** Get the total volume of the bins of the solution. */
166164
inline Volume bin_volume() const { return bin_volume_; }
167165

166+
/** Get the total floor area of the bins of the solution. */
167+
inline Area bin_area() const { return bin_area_; }
168+
168169
/** Get the total weight of the bins of the solution. */
169170
inline Weight bin_weight() const { return bin_weight_; }
170171

172+
/*
173+
* Getters: stacks
174+
*/
175+
176+
/** Get the number of stacks in the solution. */
177+
inline ItemPos number_of_stacks() const { return number_of_stacks_; }
178+
179+
/** Get the total area of the stacks of the solution. */
180+
inline Area stack_area() const { return stack_area_; }
181+
171182
/*
172183
* Getters: items
173184
*/
@@ -210,6 +221,9 @@ class Solution
210221
/** Get the volume load of the solution. */
211222
inline double volume_load() const { return (double)item_volume() / instance().bin_volume(); }
212223

224+
/** Get the area load of the solution. */
225+
inline double area_load() const { return (double)stack_area() / instance().bin_area(); }
226+
213227
/** Get the weight load of the solution. */
214228
inline double weight_load() const { return (double)item_weight() / instance().bin_weight(); }
215229

@@ -241,6 +255,20 @@ class Solution
241255
const std::vector<Weight>& weight,
242256
const std::vector<Weight>& weight_weighted_sum) const;
243257

258+
Weight compute_middle_axle_weight_constraints_violation() const;
259+
260+
Weight compute_middle_axle_weight_constraints_violation(
261+
BinTypeId bin_type_id,
262+
const std::vector<Weight>& weight,
263+
const std::vector<Weight>& weight_weighted_sum) const;
264+
265+
Weight compute_rear_axle_weight_constraints_violation() const;
266+
267+
Weight compute_rear_axle_weight_constraints_violation(
268+
BinTypeId bin_type_id,
269+
const std::vector<Weight>& weight,
270+
const std::vector<Weight>& weight_weighted_sum) const;
271+
244272
/**
245273
* Return 'true' iff the input stack is feasible.
246274
*
@@ -292,6 +320,9 @@ class Solution
292320
/** Number of bins. */
293321
BinPos number_of_bins_ = 0;
294322

323+
/** Number of stacks. */
324+
BinPos number_of_stacks_ = 0;
325+
295326
/** Number of items. */
296327
BinPos number_of_items_ = 0;
297328

@@ -301,6 +332,12 @@ class Solution
301332
/** Total volume of the bins of the solution. */
302333
Volume bin_volume_ = 0;
303334

335+
/** Total floor area of the bins of the solution. */
336+
Area bin_area_ = 0;
337+
338+
/** Total area of the stacks of the solution. */
339+
Area stack_area_ = 0;
340+
304341
/** Total weight of the bins of the solution. */
305342
Volume bin_weight_ = 0;
306343

0 commit comments

Comments
 (0)