76#include "absl/flags/parse.h"
77#include "absl/flags/usage.h"
78#include "absl/status/status.h"
79#include "absl/status/statusor.h"
88constexpr double kInf = std::numeric_limits<double>::infinity();
93struct CuttingStockInstance {
94 std::vector<int> piece_sizes;
95 std::vector<int> piece_demands;
102struct Configuration {
103 std::vector<int> pieces;
104 std::vector<int> quantity;
112struct CuttingStockSolution {
113 std::vector<Configuration> configurations;
114 std::vector<int> quantity;
115 int objective_value = 0;
123absl::StatusOr<std::pair<Configuration, double>> BestConfiguration(
124 const std::vector<double>& piece_prices,
125 const std::vector<int>& piece_sizes,
const int board_size) {
126 int num_pieces = piece_prices.size();
127 CHECK_EQ(piece_sizes.size(), num_pieces);
129 std::vector<math_opt::Variable> pieces;
130 for (
int i = 0; i < num_pieces; ++i) {
132 model.AddIntegerVariable(0,
kInf, absl::StrCat(
"item_", i)));
140 math_opt::TerminationReason::kOptimal) {
142 <<
"Failed to solve knapsack pricing problem: "
145 Configuration config;
146 for (
int i = 0; i < num_pieces; ++i) {
147 const int use =
static_cast<int>(
150 config.pieces.push_back(i);
151 config.quantity.push_back(use);
158absl::StatusOr<CuttingStockSolution> SolveCuttingStock(
159 const CuttingStockInstance& instance) {
161 model.set_minimize();
162 const int n = instance.piece_sizes.size();
163 std::vector<math_opt::LinearConstraint> demand_met;
164 for (
int i = 0; i < n; ++i) {
165 const int d = instance.piece_demands[i];
166 demand_met.push_back(
model.AddLinearConstraint(d, d));
168 std::vector<std::pair<Configuration, math_opt::Variable>> configs;
169 auto add_config = [&](
const Configuration& config) {
171 model.set_objective_coefficient(v, 1);
172 for (
int i = 0; i < config.pieces.size(); ++i) {
173 const int item = config.pieces[i];
174 const int use = config.quantity[i];
176 model.set_coefficient(demand_met[item], v, use);
179 configs.push_back({config, v});
184 for (
int i = 0; i < n; ++i) {
185 add_config(Configuration{.pieces = {i}, .quantity = {1}});
189 model, math_opt::SolverType::kGlop));
190 int pricing_round = 0;
194 math_opt::TerminationReason::kOptimal) {
196 <<
"Failed to solve leader LP problem at iteration "
197 << pricing_round <<
" termination: " << solve_result.
termination;
201 std::vector<double> prices;
203 prices.push_back(solve_result.
dual_values().at(d));
206 (
const auto [config,
value]),
207 BestConfiguration(prices, instance.piece_sizes, instance.board_length));
208 if (
value <= 1 + 1e-3) {
213 LOG(
INFO) <<
"round: " << pricing_round
217 LOG(
INFO) <<
"Done adding columns, switching to MIP";
218 for (
const auto& [config,
var] : configs) {
224 math_opt::TerminationReason::kOptimal) {
226 <<
"Failed to solve final cutting stock MIP, termination: "
229 CuttingStockSolution solution;
230 for (
const auto& [config,
var] : configs) {
234 solution.configurations.push_back(config);
235 solution.quantity.push_back(use);
236 solution.objective_value += use;
242absl::Status RealMain() {
244 CuttingStockInstance instance;
245 instance.board_length = 5600;
246 instance.piece_sizes = {1380, 1520, 1560, 1710, 1820, 1880, 1930,
247 2000, 2050, 2100, 2140, 2150, 2200};
248 instance.piece_demands = {22, 25, 12, 14, 18, 18, 20, 10, 12, 14, 16, 18, 20};
249 ASSIGN_OR_RETURN(CuttingStockSolution solution, SolveCuttingStock(instance));
250 std::cout <<
"Best known solution uses 73 rolls." << std::endl;
251 std::cout <<
"Total rolls used in actual solution found: "
252 << solution.objective_value << std::endl;
253 return absl::OkStatus();
258int main(
int argc,
char** argv) {
260 absl::ParseCommandLine(argc, argv);
261 absl::Status result = RealMain();
#define CHECK_EQ(val1, val2)
static absl::StatusOr< std::unique_ptr< IncrementalSolver > > New(Model &model, SolverType solver_type, SolverInitArguments arguments={})
int main(int argc, char **argv)
void InitGoogleLogging(const char *argv0)
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()
StatusBuilder InvalidArgumentErrorBuilder()
#define ASSIGN_OR_RETURN(lhs, rexpr)
const LinearConstraintMap< double > & dual_values() const
bool has_dual_feasible_solution() const
double objective_value() const
const VariableMap< double > & variable_values() const