polish examples
This commit is contained in:
@@ -170,6 +170,22 @@ absl::btree_set<int> FindFixedItems(
|
||||
return fixed_items;
|
||||
}
|
||||
|
||||
// Solves a subset sum problem to find the maximum reachable max size.
|
||||
int64_t MaxSubsetSumSize(const std::vector<int64_t>& sizes, int64_t max_size) {
|
||||
CpModelBuilder builder;
|
||||
LinearExpr weighed_sum;
|
||||
for (const int size : sizes) {
|
||||
BoolVar var = builder.NewBoolVar();
|
||||
weighed_sum += size * var;
|
||||
}
|
||||
|
||||
builder.AddLessOrEqual(weighed_sum, max_size);
|
||||
builder.Maximize(weighed_sum);
|
||||
|
||||
const CpSolverResponse response = Solve(builder.Build());
|
||||
return static_cast<int64_t>(response.objective_value());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Load a 2D bin packing problem and solve it.
|
||||
@@ -184,8 +200,8 @@ void LoadAndSolve(const std::string& file_name, int instance) {
|
||||
<< file_name << "'";
|
||||
LOG(INFO) << "Instance has " << problem.items_size() << " items";
|
||||
|
||||
const auto bin_sizes = problem.box_shape().dimensions();
|
||||
const int num_dimensions = bin_sizes.size();
|
||||
const auto original_bin_sizes = problem.box_shape().dimensions();
|
||||
const int num_dimensions = original_bin_sizes.size();
|
||||
const int num_items = problem.items_size();
|
||||
|
||||
// Non overlapping.
|
||||
@@ -195,14 +211,23 @@ void LoadAndSolve(const std::string& file_name, int instance) {
|
||||
LOG(FATAL) << num_dimensions << " dimensions not supported.";
|
||||
}
|
||||
|
||||
const int64_t area_of_one_bin = bin_sizes[0] * bin_sizes[1];
|
||||
// Reduce the size of the box with subset-sum.
|
||||
std::vector<int64_t> x_sizes;
|
||||
std::vector<int64_t> y_sizes;
|
||||
int64_t sum_of_items_area = 0;
|
||||
for (const auto& item : problem.items()) {
|
||||
CHECK_EQ(1, item.shapes_size());
|
||||
const auto& shape = item.shapes(0);
|
||||
CHECK_EQ(2, shape.dimensions_size());
|
||||
sum_of_items_area += shape.dimensions(0) * shape.dimensions(1);
|
||||
x_sizes.push_back(shape.dimensions(0));
|
||||
y_sizes.push_back(shape.dimensions(1));
|
||||
}
|
||||
std::vector<int64_t> bin_sizes(2);
|
||||
bin_sizes[0] = MaxSubsetSumSize(x_sizes, original_bin_sizes[0]);
|
||||
bin_sizes[1] = MaxSubsetSumSize(y_sizes, original_bin_sizes[1]);
|
||||
|
||||
const int64_t area_of_one_bin = bin_sizes[0] * bin_sizes[1];
|
||||
|
||||
const int64_t trivial_lb = CeilOfRatio(sum_of_items_area, area_of_one_bin);
|
||||
LOG(INFO) << "Trivial lower bound of the number of bins = " << trivial_lb;
|
||||
@@ -270,8 +295,7 @@ void LoadAndSolve(const std::string& file_name, int instance) {
|
||||
}
|
||||
|
||||
// Compute the min size of all items in each dimension.
|
||||
std::vector<int64_t> min_sizes_per_dimension = {bin_sizes.begin(),
|
||||
bin_sizes.end()};
|
||||
std::vector<int64_t> min_sizes_per_dimension = bin_sizes;
|
||||
for (int item = 0; item < num_items; ++item) {
|
||||
for (int dim = 0; dim < num_dimensions; ++dim) {
|
||||
min_sizes_per_dimension[dim] =
|
||||
@@ -295,14 +319,12 @@ void LoadAndSolve(const std::string& file_name, int instance) {
|
||||
const int64_t size = problem.items(item).shapes(0).dimensions(dim);
|
||||
IntVar start;
|
||||
if (b == 0) {
|
||||
// For item fixed to a given bin, by symmetry of rotation we can also
|
||||
// assume it is in the lower left corner.
|
||||
// Note that the data defines the global size, so the range of the
|
||||
// interval is [0, bin_size - 1].
|
||||
// For item fixed to a given bin, by symmetry, we can also assume it
|
||||
// is in the lower left corner.
|
||||
const int64_t start_max = fixed_items.contains(item)
|
||||
? (bin_size - size) / 2
|
||||
: bin_size - 1 - size;
|
||||
start = cp_model.NewIntVar({0, start_max});
|
||||
? (bin_size - size + 1) / 2
|
||||
: bin_size - size;
|
||||
start = cp_model.NewIntVar({0, start_max});
|
||||
starts_by_dimension[item][dim] = start;
|
||||
|
||||
if (size + min_sizes_per_dimension[dim] > bin_size) {
|
||||
@@ -351,7 +373,14 @@ void LoadAndSolve(const std::string& file_name, int instance) {
|
||||
}
|
||||
|
||||
// Non overlapping.
|
||||
LOG(INFO) << "Box size: " << bin_sizes[0] << "*" << bin_sizes[1];
|
||||
if (bin_sizes[0] == original_bin_sizes[0] &&
|
||||
bin_sizes[1] == original_bin_sizes[1]) {
|
||||
LOG(INFO) << "Box size: [" << bin_sizes[0] << " * " << bin_sizes[1] << "]";
|
||||
} else {
|
||||
LOG(INFO) << "Box size: [" << bin_sizes[0] << " * " << bin_sizes[1]
|
||||
<< "] reduced from [" << original_bin_sizes[0] << " * "
|
||||
<< original_bin_sizes[1] << "]";
|
||||
}
|
||||
for (int b = 0; b < max_bins; ++b) {
|
||||
NoOverlap2DConstraint no_overlap_2d = cp_model.AddNoOverlap2D();
|
||||
for (int item = 0; item < num_items; ++item) {
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "absl/flags/flag.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/types/span.h"
|
||||
#include "ortools/base/init_google.h"
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/base/types.h"
|
||||
@@ -48,7 +49,7 @@ namespace operations_research {
|
||||
namespace sat {
|
||||
|
||||
// Checks that all pairwise distances are unique and returns all violators
|
||||
void CheckConstraintViolators(const std::vector<int64_t>& vars,
|
||||
void CheckConstraintViolators(absl::Span<const int64_t> vars,
|
||||
std::vector<int>* const violators) {
|
||||
int dim = vars.size();
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ class AllSolutionCollector(cp_model.CpSolverSolutionCallback):
|
||||
return self.__collect
|
||||
|
||||
|
||||
def EnumerateAllKnapsacksWithRepetition(
|
||||
def enumerate_all_knapsacks_with_repetition(
|
||||
item_sizes: list[int], total_size_min: int, total_size_max: int
|
||||
) -> list[list[int]]:
|
||||
"""Enumerate all possible knapsacks with total size in the given range.
|
||||
@@ -85,7 +85,7 @@ def EnumerateAllKnapsacksWithRepetition(
|
||||
return solution_collector.combinations()
|
||||
|
||||
|
||||
def AggregateItemCollectionsOptimally(
|
||||
def aggregate_item_collections_optimally(
|
||||
item_collections: list[list[int]],
|
||||
max_num_collections: int,
|
||||
ideal_item_ratios: list[float],
|
||||
@@ -179,7 +179,7 @@ def AggregateItemCollectionsOptimally(
|
||||
return []
|
||||
|
||||
|
||||
def GetOptimalSchedule(
|
||||
def get_optimal_schedule(
|
||||
demand: list[tuple[float, str, int]]
|
||||
) -> list[tuple[int, list[tuple[int, str]]]]:
|
||||
"""Computes the optimal schedule for the installation input.
|
||||
@@ -193,7 +193,7 @@ def GetOptimalSchedule(
|
||||
Returns:
|
||||
The same output type as EnumerateAllKnapsacksWithRepetition.
|
||||
"""
|
||||
combinations = EnumerateAllKnapsacksWithRepetition(
|
||||
combinations = enumerate_all_knapsacks_with_repetition(
|
||||
[a[2] + _COMMUTE_TIME.value for a in demand],
|
||||
_LOAD_MIN.value,
|
||||
_LOAD_MAX.value,
|
||||
@@ -205,7 +205,7 @@ def GetOptimalSchedule(
|
||||
)
|
||||
)
|
||||
|
||||
selection = AggregateItemCollectionsOptimally(
|
||||
selection = aggregate_item_collections_optimally(
|
||||
combinations, _NUM_WORKERS.value, [a[0] / 100.0 for a in demand]
|
||||
)
|
||||
output = []
|
||||
@@ -237,7 +237,7 @@ def main(_):
|
||||
% (_LOAD_MIN.value, _LOAD_MAX.value)
|
||||
)
|
||||
print("%d workers" % _NUM_WORKERS.value)
|
||||
selection = GetOptimalSchedule(demand)
|
||||
selection = get_optimal_schedule(demand)
|
||||
print()
|
||||
installed = 0
|
||||
installed_per_type = {}
|
||||
|
||||
Reference in New Issue
Block a user