20 #include "absl/container/btree_map.h"
21 #include "absl/flags/flag.h"
26 #include "ortools/packing/vector_bin_packing.pb.h"
29 "File to store the solver specific optimization proto.");
35 double ConvertVectorBinPackingProblem(
const vbp::VectorBinPackingProblem&
input,
36 ArcFlowGraph* graph) {
39 const int num_items =
input.item_size();
40 const int num_dims =
input.resource_capacity_size();
43 std::vector<std::vector<int>> shapes(num_items);
44 std::vector<int> demands(num_items);
45 std::vector<int> capacities(num_dims);
46 for (
int i = 0; i < num_items; ++i) {
47 shapes[i].assign(
input.item(i).resource_usage().begin(),
48 input.item(i).resource_usage().end());
50 input.item(i).num_copies() +
input.item(i).num_optional_copies();
52 for (
int i = 0; i < num_dims; ++i) {
53 capacities[i] =
input.resource_capacity(i);
57 for (
int i = 0; i < num_items; ++i) {
58 const int max_copies =
input.item(i).max_number_of_copies_per_bin();
59 if (max_copies == 0 || max_copies >= demands[i])
continue;
60 capacities.push_back(max_copies);
61 for (
int j = 0; j < num_items; ++j) {
62 shapes[j].push_back(i == j);
67 const double arc_flow_time = timer.
Get();
69 VLOG(1) <<
"The arc-flow grah has " << graph->nodes.size() <<
" nodes, and "
70 << graph->arcs.size() <<
" arcs. It was created by exploring "
71 << graph->num_dp_states
72 <<
" states in the dynamic programming phase in " << arc_flow_time
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);
147 ct->SetCoefficient(num_bins_var, 1.0);
149 ct->SetCoefficient(
var, -1.0);
155 const int sink_node = graph.
nodes.size() - 1;
157 ct->SetCoefficient(
var, 1.0);
159 ct->SetCoefficient(num_bins_var, -1.0);
162 if (!absl::GetFlag(FLAGS_arc_flow_dump_model).empty()) {
163 MPModelProto output_model;
174 vbp::VectorBinPackingSolution solution;
175 solution.set_solve_time_in_seconds(solver.
wall_time() / 1000.0);
176 solution.set_arc_flow_time_in_seconds(arc_flow_time);
179 solution.set_status(vbp::OPTIMAL);
180 solution.set_objective_value(objective->
Value());
183 solution.set_objective_value(objective->
Value());
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);
245 CHECK_EQ(solution.bins_size(), std::round(num_bins_var->
solution_value()));
246 for (
const auto& next_counts : node_to_next_count_item) {
247 CHECK(next_counts.empty());
ABSL_FLAG(std::string, arc_flow_dump_model, "", "File to store the solver specific optimization proto.")
The class for constraints of a Mathematical Programming (MP) model.
A class to express a linear objective.
void SetCoefficient(const MPVariable *const var, double coeff)
Sets the coefficient of the variable in the objective.
void SetOffset(double value)
Sets the constant term in the objective.
double Value() const
Returns the objective value of the best solution found so far.
double offset() const
Gets the constant term in the objective.
This mathematical programming (MP) solver class is the main class though which users build and solve ...
MPObjective * MutableObjective()
Returns the mutable objective object.
MPConstraint * MakeRowConstraint(double lb, double ub)
Creates a linear constraint with given bounds.
ResultStatus
The status of solving the problem.
@ FEASIBLE
feasible, or stopped by limit.
@ INFEASIBLE
proven infeasible.
int64_t wall_time() const
OptimizationProblemType
The type of problems (LP or MIP) that will be solved and the underlying solver (GLOP,...
bool SetSolverSpecificParametersAsString(const std::string ¶meters)
Advanced usage: pass solver specific parameters in text format.
absl::Status SetNumThreads(int num_threads)
Sets the number of threads to use by the underlying solver.
void ExportModelToProto(MPModelProto *output_model) const
Exports model to protocol buffer.
MPVariable * MakeIntVar(double lb, double ub, const std::string &name)
Creates an integer variable.
ResultStatus Solve()
Solves the problem using the default parameter values.
void EnableOutput()
Enables solver logging.
void SetTimeLimit(absl::Duration time_limit)
The class for variables of a Mathematical Programming (MP) model.
double solution_value() const
Returns the value of the variable in the current solution.
ModelSharedTimeLimit * time_limit
absl::Status SetTextProto(const absl::string_view &filename, const google::protobuf::Message &proto, int flags)
vbp::VectorBinPackingSolution SolveVectorBinPackingWithArcFlow(const vbp::VectorBinPackingProblem &problem, MPSolver::OptimizationProblemType solver_type, const std::string &mip_params, double time_limit, int num_threads, int max_bins)
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.
static int input(yyscan_t yyscanner)
std::vector< std::vector< int > > nodes
#define VLOG(verboselevel)