79 const vbp::VectorBinPackingProblem& problem,
81 const std::string& mip_params,
double time_limit,
int num_threads,
84 const double arc_flow_time = ConvertVectorBinPackingProblem(problem, &
graph);
88 max_num_bins = max_bins;
90 for (
const auto& item : problem.item()) {
91 max_num_bins += item.num_copies() + item.num_optional_copies();
94 const int num_types = problem.item_size();
95 std::vector<std::vector<MPVariable*>> incoming_vars(
graph.nodes.size());
96 std::vector<std::vector<MPVariable*>> outgoing_vars(
graph.nodes.size());
97 std::vector<MPVariable*> arc_to_var(
graph.arcs.size());
98 std::vector<std::vector<MPVariable*>> item_to_vars(num_types);
100 MPSolver solver(
"VectorBinPacking", solver_type);
104 for (
int v = 0; v <
graph.arcs.size(); ++v) {
107 solver.
MakeIntVar(0, max_num_bins, absl::StrCat(
"a", v));
108 incoming_vars[
arc.destination].push_back(
var);
109 outgoing_vars[
arc.source].push_back(
var);
110 if (
arc.item_index != -1) {
111 item_to_vars[
arc.item_index].push_back(
var);
117 for (
int i = 0; i < num_types; ++i) {
118 const vbp::Item& item = problem.item(i);
119 int max_copies = item.num_copies() + item.num_optional_copies();
122 objective->
SetOffset(max_copies * item.penalty_per_missing_copy() +
126 ct->SetCoefficient(
var, 1.0);
131 for (
int n = 1; n <
graph.nodes.size() - 1; ++n) {
134 ct->SetCoefficient(
var, 1.0);
137 ct->SetCoefficient(
var, -1.0);
142 solver.
MakeIntVar(0, max_num_bins,
"num_bins_var");
144 num_bins_var, problem.has_cost_per_bin() ? problem.cost_per_bin() : 1.0);
149 ct->SetCoefficient(
var, -1.0);
155 const int sink_node =
graph.nodes.size() - 1;
157 ct->SetCoefficient(
var, 1.0);
162 if (!absl::GetFlag(FLAGS_arc_flow_dump_model).empty()) {
163 MPModelProto output_model;
174 vbp::VectorBinPackingSolution
solution;
176 solution.set_arc_flow_time_in_seconds(arc_flow_time);
185 solution.set_status(vbp::INFEASIBLE);
191 struct NextCountItem {
196 std::vector<std::vector<NextCountItem>> node_to_next_count_item(
198 for (
int v = 0; v <
graph.arcs.size(); ++v) {
200 static_cast<int>(std::round(arc_to_var[v]->solution_value()));
201 if (count == 0)
continue;
203 node_to_next_count_item[
arc.source].push_back(
204 {
arc.destination, count,
arc.item_index});
212 const auto pop_next_item = [&node_to_next_count_item](
int node) {
213 CHECK(!node_to_next_count_item[node].empty());
214 auto& [
next, count, item] = node_to_next_count_item[node].back();
218 const NextItem result{
next, item};
220 node_to_next_count_item[node].pop_back();
227 const int start_node = 0;
228 const int end_node =
graph.nodes.size() - 1;
229 while (!node_to_next_count_item[start_node].empty()) {
230 absl::btree_map<int, int> item_count;
231 int current = start_node;
232 while (current != end_node) {
233 const auto [
next, item] = pop_next_item(current);
239 vbp::VectorBinPackingOneBinInSolution* bin =
solution.add_bins();
240 for (
const auto& [item, count] : item_count) {
241 bin->add_item_indices(item);
242 bin->add_item_copies(count);
246 for (
const auto& next_counts : node_to_next_count_item) {
247 CHECK(next_counts.empty());