working vector bin packing solver with solution display
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user