working vector bin packing solver with solution display

This commit is contained in:
Laurent Perron
2021-09-30 13:12:07 +02:00
parent 26bbc8856c
commit fc98cba505
2 changed files with 80 additions and 5 deletions

View File

@@ -32,9 +32,10 @@
ABSL_FLAG(std::string, input, "", "Vector Bin Packing (.vpb) data file name.");
ABSL_FLAG(std::string, params, "",
"Parameters in solver specific text format.");
ABSL_FLAG(std::string, solver, "sat", "Solver to use: sat, scip");
ABSL_FLAG(std::string, solver, "sat", "Solver to use: sat, scip, glip");
ABSL_FLAG(double, time_limit, 900.0, "Time limit in seconds");
ABSL_FLAG(int, threads, 1, "Number of threads");
ABSL_FLAG(bool, display_proto, false, "Print the input protobuf");
namespace operations_research {
void ParseAndSolve(const std::string& filename, const std::string& solver,
@@ -65,6 +66,11 @@ void ParseAndSolve(const std::string& filename, const std::string& solver,
LOG(INFO) << "Solving vector packing problem '" << data.name() << "' with "
<< data.item_size() << " item types, and "
<< data.resource_capacity_size() << " dimensions.";
if (absl::GetFlag(FLAGS_display_proto)) {
LOG(INFO) << data.DebugString();
}
// Build optimization model.
MPSolver::OptimizationProblemType solver_type;
MPSolver::ParseSolverType(solver, &solver_type);
packing::vbp::VectorBinPackingSolution solution =
@@ -72,6 +78,17 @@ void ParseAndSolve(const std::string& filename, const std::string& solver,
absl::GetFlag(FLAGS_time_limit),
absl::GetFlag(FLAGS_threads),
/*log_statistics=*/true);
if (!solution.bins().empty()) {
for (int b = 0; b < solution.bins_size(); ++b) {
LOG(INFO) << "Bin " << b;
const packing::vbp::VectorBinPackingOneBinInSolution& bin =
solution.bins(b);
for (int i = 0; i < bin.item_indices_size(); ++i) {
LOG(INFO) << " - item: " << bin.item_indices(i)
<< ", copies: " << bin.item_copies(i);
}
}
}
}
} // namespace operations_research

View File

@@ -18,6 +18,7 @@
#include "ortools/base/file.h"
#include "ortools/base/timer.h"
#include "ortools/packing/arc_flow_builder.h"
#include "ortools/packing/vector_bin_packing.pb.h"
ABSL_FLAG(std::string, arc_flow_dump_model, "",
"File to store the solver specific optimization proto.");
@@ -98,6 +99,7 @@ vbp::VectorBinPackingSolution SolveVectorBinPackingWithArcFlow(
if (arc.item_index != -1) {
item_to_vars[arc.item_index].push_back(var);
}
arc_to_var[v] = var;
}
// Per item demand constraint.
@@ -167,11 +169,9 @@ vbp::VectorBinPackingSolution SolveVectorBinPackingWithArcFlow(
solution.set_status(vbp::INFEASIBLE);
}
// TODO(user): Fill bins in the solution proto.
const bool has_solution =
result_status == MPSolver::OPTIMAL || result_status == MPSolver::FEASIBLE;
if (log_statistics) {
const bool has_solution = result_status == MPSolver::OPTIMAL ||
result_status == MPSolver::FEASIBLE;
absl::PrintF("%-12s: %s\n", "Status",
MPSolverResponseStatus_Name(
static_cast<MPSolverResponseStatus>(result_status))
@@ -185,6 +185,64 @@ vbp::VectorBinPackingSolution SolveVectorBinPackingWithArcFlow(
absl::PrintF("%-12s: %-6.4g\n", "Time", solution.solve_time_in_seconds());
}
if (has_solution) {
// Create the arc flow graph with the flow quantity in each arc.
struct NextCountItem {
int next = -1;
int count = 0;
int item = -1;
};
std::vector<std::vector<NextCountItem>> node_to_next_count_item(
graph.nodes.size());
for (int v = 0; v < graph.arcs.size(); ++v) {
const int count =
static_cast<int>(std::round(arc_to_var[v]->solution_value()));
if (count == 0) continue;
const ArcFlowGraph::Arc& arc = graph.arcs[v];
node_to_next_count_item[arc.source].push_back(
{arc.destination, count, arc.item_index});
}
// Unroll each possible path and rebuild bins.
struct NextItem {
int next = -1;
int item = -1;
};
const auto pop_next_item = [&node_to_next_count_item](int node) {
CHECK(!node_to_next_count_item[node].empty());
NextCountItem& arc = node_to_next_count_item[node].back();
const int next = arc.next;
CHECK_NE(next, -1);
const int item = arc.item;
CHECK_GT(arc.count, 0);
if (--arc.count == 0) {
node_to_next_count_item[node].pop_back();
}
return NextItem({next, item});
};
const int start_node = 0;
const int end_node = graph.nodes.size() - 1;
while (!node_to_next_count_item[start_node].empty()) {
std::map<int, int> item_count;
int current = start_node;
while (current != end_node) {
const NextItem n = pop_next_item(current);
if (n.item != -1) {
item_count[n.item]++;
} else {
CHECK_EQ(n.next, end_node);
}
current = n.next;
}
vbp::VectorBinPackingOneBinInSolution* bin = solution.add_bins();
for (const auto& it : item_count) {
bin->add_item_indices(it.first);
bin->add_item_copies(it.second);
}
}
}
return solution;
}