76#include "absl/status/status.h"
77#include "absl/status/statusor.h"
87constexpr double kInf = std::numeric_limits<double>::infinity();
92struct CuttingStockInstance {
93 std::vector<int> piece_sizes;
94 std::vector<int> piece_demands;
101struct Configuration {
102 std::vector<int> pieces;
103 std::vector<int> quantity;
111struct CuttingStockSolution {
112 std::vector<Configuration> configurations;
113 std::vector<int> quantity;
122absl::StatusOr<std::pair<Configuration, double>> BestConfiguration(
123 const std::vector<double>& piece_prices,
124 const std::vector<int>& piece_sizes,
const int board_size) {
125 int num_pieces = piece_prices.size();
126 CHECK_EQ(piece_sizes.size(), num_pieces);
128 std::vector<math_opt::Variable> pieces;
129 for (
int i = 0; i < num_pieces; ++i) {
131 model.AddIntegerVariable(0,
kInf, absl::StrCat(
"item_", i)));
139 math_opt::TerminationReason::kOptimal) {
141 <<
"Failed to solve knapsack pricing problem to optimality: "
144 Configuration config;
145 for (
int i = 0; i < num_pieces; ++i) {
146 const int use =
static_cast<int>(
149 config.pieces.push_back(i);
150 config.quantity.push_back(use);
157absl::StatusOr<CuttingStockSolution> SolveCuttingStock(
158 const CuttingStockInstance& instance) {
160 model.set_minimize();
161 const int n = instance.piece_sizes.size();
162 std::vector<math_opt::LinearConstraint> demand_met;
163 for (
int i = 0; i < n; ++i) {
164 const int d = instance.piece_demands[i];
165 demand_met.push_back(
model.AddLinearConstraint(d, d));
167 std::vector<std::pair<Configuration, math_opt::Variable>> configs;
168 auto add_config = [&](
const Configuration& config) {
170 model.set_objective_coefficient(v, 1);
171 for (
int i = 0; i < config.pieces.size(); ++i) {
172 const int item = config.pieces[i];
173 const int use = config.quantity[i];
175 model.set_coefficient(demand_met[item], v, use);
178 configs.push_back({config, v});
183 for (
int i = 0; i < n; ++i) {
184 add_config(Configuration{.pieces = {i}, .quantity = {1}});
188 &
model, math_opt::SolverType::kGlop));
189 int pricing_round = 0;
193 math_opt::TerminationReason::kOptimal) {
195 <<
"Failed to solve leader LP problem to optimality at "
197 << pricing_round <<
" termination: " << solve_result.
termination;
204 <<
"no dual solution was returned with optimal solution at "
208 std::vector<double> prices;
210 prices.push_back(solve_result.
dual_values().at(d));
213 (
const auto [config,
value]),
214 BestConfiguration(prices, instance.piece_sizes, instance.board_length));
215 if (
value <= 1 + 1e-3) {
220 LOG(
INFO) <<
"round: " << pricing_round
224 LOG(
INFO) <<
"Done adding columns, switching to MIP";
225 for (
const auto& [config,
var] : configs) {
231 case math_opt::TerminationReason::kOptimal:
232 case math_opt::TerminationReason::kFeasible:
236 <<
"Failed to solve final cutting stock MIP, termination: "
239 CuttingStockSolution solution;
240 for (
const auto& [config,
var] : configs) {
244 solution.configurations.push_back(config);
245 solution.quantity.push_back(use);
246 solution.objective_value += use;
252absl::Status RealMain() {
254 CuttingStockInstance instance;
255 instance.board_length = 5600;
256 instance.piece_sizes = {1380, 1520, 1560, 1710, 1820, 1880, 1930,
257 2000, 2050, 2100, 2140, 2150, 2200};
258 instance.piece_demands = {22, 25, 12, 14, 18, 18, 20, 10, 12, 14, 16, 18, 20};
259 ASSIGN_OR_RETURN(CuttingStockSolution solution, SolveCuttingStock(instance));
260 std::cout <<
"Best known solution uses 73 rolls." << std::endl;
261 std::cout <<
"Total rolls used in actual solution found: "
262 << solution.objective_value << std::endl;
263 return absl::OkStatus();
268int main(
int argc,
char** argv) {
270 absl::Status result = RealMain();
#define CHECK_EQ(val1, val2)
#define ASSIGN_OR_RETURN(lhs, rexpr)
static absl::StatusOr< std::unique_ptr< IncrementalSolver > > New(Model *model, SolverType solver_type, SolverInitArguments arguments={})
int main(int argc, char **argv)
void InitGoogle(const char *usage, int *argc, char ***argv, bool deprecated)
absl::StatusOr< SolveResult > Solve(const Model &model, const SolverType solver_type, const SolveArguments &solve_args, const SolverInitArguments &init_args)
LinearExpression InnerProduct(const LeftIterable &left, const RightIterable &right)
StatusBuilder InternalErrorBuilder()
const LinearConstraintMap< double > & dual_values() const
bool has_dual_feasible_solution() const
double objective_value() const
const VariableMap< double > & variable_values() const