19#include "absl/container/flat_hash_map.h"
20#include "absl/strings/str_cat.h"
21#include "absl/strings/str_join.h"
34 ArcFlowBuilder(
const std::vector<int>& bin_dimensions,
35 const std::vector<std::vector<int>>& item_dimensions_by_type,
36 const std::vector<int>& demand_by_type);
43 int64_t NumDpStates()
const;
53 double NormalizedSize(
const std::vector<int>& bin_dimensions)
const;
69 void ForwardCreationPass(DpState* dp_state);
72 void BackwardCompressionPass(
int state_index);
74 void ForwardCompressionPass(
const std::vector<int>& source_node);
77 bool CanFitNewItem(
const std::vector<int>&
used_dimensions,
int item)
const;
83 int LookupOrCreateDpState(
int item,
int quantity,
86 const std::vector<int> bin_dimensions_;
87 std::vector<Item> items_;
89 typedef absl::flat_hash_map<std::vector<int>,
int> VectorIntIntMap;
95 std::vector<DpState*> dp_states_;
96 std::vector<std::vector<VectorIntIntMap>> dp_state_index_;
102 absl::flat_hash_map<std::vector<int>,
int> node_indices_;
103 std::vector<std::vector<int>> nodes_;
105 std::set<ArcFlowGraph::Arc> arcs_;
108double ArcFlowBuilder::Item::NormalizedSize(
109 const std::vector<int>& bin_dimensions)
const {
111 for (
int i = 0; i < bin_dimensions.size(); ++i) {
112 size +=
static_cast<double>(
dimensions[i]) / bin_dimensions[i];
117int64_t ArcFlowBuilder::NumDpStates()
const {
119 for (
const auto& it1 : dp_state_index_) {
120 for (
const auto& it2 : it1) {
127ArcFlowBuilder::ArcFlowBuilder(
128 const std::vector<int>& bin_dimensions,
129 const std::vector<std::vector<int>>& item_dimensions_by_type,
130 const std::vector<int>& demand_by_type)
131 : bin_dimensions_(bin_dimensions) {
133 for (
int i = 0; i < bin_dimensions.size(); ++i) {
137 const int num_items = item_dimensions_by_type.size();
138 items_.resize(num_items);
139 for (
int i = 0; i < num_items; ++i) {
140 items_[i].dimensions = item_dimensions_by_type[i];
141 items_[i].demand = demand_by_type[i];
142 items_[i].original_index = i;
144 std::sort(items_.begin(), items_.end(), [&](
const Item&
a,
const Item&
b) {
145 return a.NormalizedSize(bin_dimensions_) >
146 b.NormalizedSize(bin_dimensions_);
150bool ArcFlowBuilder::CanFitNewItem(
const std::vector<int>&
used_dimensions,
152 for (
int d = 0; d < bin_dimensions_.size(); ++d) {
160std::vector<int> ArcFlowBuilder::AddItem(
164 for (
int d = 0; d < bin_dimensions_.size(); ++d) {
165 result[d] += items_[item].dimensions[d];
170int ArcFlowBuilder::GetOrCreateNode(
const std::vector<int>&
used_dimensions) {
172 if (it != node_indices_.end()) {
175 const int index = node_indices_.size();
181ArcFlowGraph ArcFlowBuilder::BuildVectorBinPackingGraph() {
183 dp_state_index_.resize(items_.size());
184 for (
int i = 0; i < items_.size(); ++i) {
185 dp_state_index_[i].resize(items_[i].
demand + 1);
190 std::vector<int> zero(bin_dimensions_.size(), 0);
191 dp_states_.push_back(
new DpState({0, 0, zero, -1, -1}));
192 for (
int i = 0; i < dp_states_.size(); ++i) {
193 ForwardCreationPass(dp_states_[i]);
199 const int64_t num_dp_states = NumDpStates();
200 dp_state_index_.clear();
203 const int num_states = dp_states_.size();
204 std::vector<std::pair<int, int>> flat_deps;
205 for (
int i = 0; i < dp_states_.size(); ++i) {
206 if (dp_states_[i]->
up_child != -1) {
207 flat_deps.push_back(std::make_pair(dp_states_[i]->
up_child, i));
210 flat_deps.push_back(std::make_pair(dp_states_[i]->
right_child, i));
213 const std::vector<int> sorted_work =
215 for (
const int w : sorted_work) {
216 BackwardCompressionPass(w);
220 const std::vector<int> source_node = dp_states_[0]->used_dimensions;
223 ForwardCompressionPass(source_node);
227 const int sink_node_index = nodes_.size() - 1;
228 for (
int node = 1; node < sink_node_index; ++node) {
229 arcs_.insert({node, sink_node_index, -1});
233 result.arcs.assign(arcs_.begin(), arcs_.end());
234 result.nodes.assign(nodes_.begin(), nodes_.end());
235 result.num_dp_states = num_dp_states;
239int ArcFlowBuilder::LookupOrCreateDpState(
241 VectorIntIntMap& map = dp_state_index_[item][quantity];
244 if (
index == dp_states_.size()) {
245 dp_states_.push_back(
251void ArcFlowBuilder::ForwardCreationPass(DpState* dp_state) {
252 const int item = dp_state->cur_item_index;
253 const int quantity = dp_state->cur_item_quantity;
257 if (item < items_.size() - 1) {
258 dp_state->up_child = LookupOrCreateDpState(item + 1, 0,
used_dimensions);
260 dp_state->up_child = -1;
266 dp_state->right_child = LookupOrCreateDpState(item, quantity + 1, added);
268 dp_state->right_child = -1;
272void ArcFlowBuilder::BackwardCompressionPass(
int state_index) {
274 std::vector<int>& result = dp_states_[state_index]->used_dimensions;
277 const int up_index = dp_states_[state_index]->up_child;
278 const std::vector<int>& result_up =
279 up_index == -1 ? bin_dimensions_ : dp_states_[up_index]->used_dimensions;
283 const int right_index = dp_states_[state_index]->right_child;
284 if (right_index == -1)
return;
285 const std::vector<int>& result_right =
286 dp_states_[right_index]->used_dimensions;
287 const Item& item = items_[dp_states_[state_index]->cur_item_index];
288 for (
int d = 0; d < bin_dimensions_.size(); ++d) {
289 result[d] =
std::min(result[d], result_right[d] - item.dimensions[d]);
293 const int node = GetOrCreateNode(result);
294 const int right_node = GetOrCreateNode(result_right);
296 arcs_.insert({node, right_node, item.original_index});
298 if (result != result_up) {
299 const int up_node = GetOrCreateNode(result_up);
300 arcs_.insert({node, up_node, -1});
308void ArcFlowBuilder::ForwardCompressionPass(
309 const std::vector<int>& source_node) {
310 const int num_nodes = node_indices_.size();
311 const int num_dims = bin_dimensions_.size();
312 std::set<ArcFlowGraph::Arc> new_arcs;
313 std::vector<std::vector<int>> new_nodes;
314 VectorIntIntMap new_node_indices;
315 std::vector<int> node_remap(num_nodes, -1);
317 std::vector<int> reverse_item_index_map(items_.size(), -1);
318 for (
int i = 0; i < items_.size(); ++i) {
319 reverse_item_index_map[items_[i].original_index] = i;
322 std::vector<std::pair<int, int>> forward_deps;
323 std::vector<std::vector<ArcFlowGraph::Arc>> incoming_arcs(num_nodes);
325 forward_deps.push_back(std::make_pair(
arc.source,
arc.destination));
326 incoming_arcs[
arc.destination].push_back(
arc);
329 const std::vector<int> sorted_work =
332 const int old_source_node = GetOrCreateNode(source_node);
333 const int old_sink_node = GetOrCreateNode(bin_dimensions_);
334 CHECK_EQ(sorted_work.front(), old_source_node);
335 CHECK_EQ(sorted_work.back(), old_sink_node);
339 for (
const int w : sorted_work) {
340 std::vector<int> new_used(num_dims, 0);
341 if (w == sorted_work.back()) {
342 new_used = bin_dimensions_;
346 arc.item_index == -1 ? -1 : reverse_item_index_map[
arc.item_index];
347 const int prev_node = node_remap[
arc.source];
348 const std::vector<int>& prev = new_nodes[prev_node];
350 for (
int d = 0; d < num_dims; ++d) {
355 new_used[d] =
std::max(new_used[d], prev[d]);
360 const auto& it = new_node_indices.find(new_used);
361 if (it != new_node_indices.end()) {
362 node_remap[w] = it->second;
364 const int new_index = new_nodes.size();
365 new_nodes.push_back(new_used);
366 new_node_indices[new_used] = new_index;
367 node_remap[w] = new_index;
375 if (
arc.item_index == -1 &&
376 node_remap[
arc.source] == node_remap[
arc.destination])
379 {node_remap[
arc.source], node_remap[
arc.destination],
arc.item_index});
381 VLOG(1) <<
"Reduced nodes from " << num_nodes <<
" to " << new_nodes.size();
382 VLOG(1) <<
"Reduced arcs from " << arcs_.size() <<
" to " << new_arcs.size();
385 CHECK_NE(node_remap[old_source_node], -1);
386 CHECK_EQ(0, node_remap[old_source_node]);
387 CHECK_NE(node_remap[old_sink_node], -1);
388 CHECK_EQ(nodes_.size() - 1, node_remap[old_sink_node]);
394 if (source != other.
source)
return source < other.
source;
400 const std::vector<int>& bin_dimensions,
401 const std::vector<std::vector<int>>& item_dimensions_by_type,
402 const std::vector<int>& demand_by_type) {
403 ArcFlowBuilder afb(bin_dimensions, item_dimensions_by_type, demand_by_type);
404 return afb.BuildVectorBinPackingGraph();
std::vector< int > dimensions
std::vector< int > used_dimensions
#define DCHECK_NE(val1, val2)
#define CHECK_EQ(val1, val2)
#define CHECK_GT(val1, val2)
#define CHECK_NE(val1, val2)
#define DCHECK(condition)
#define VLOG(verboselevel)
void STLDeleteElements(T *container)
ArcFlowGraph BuildArcFlowGraph(const std::vector< int > &bin_dimensions, const std::vector< std::vector< int > > &item_dimensions_by_type, const std::vector< int > &demand_by_type)
Collection of objects used to extend the Constraint Solver library.
std::pair< int64_t, int64_t > Arc
std::vector< int > DenseIntStableTopologicalSortOrDie(int num_nodes, const std::vector< std::pair< int, int > > &arcs)