From d83a02bc9d3b320a78efe91343c4a3c9321a4f29 Mon Sep 17 00:00:00 2001 From: Florian Fontan Date: Sat, 28 Dec 2024 23:29:45 +0100 Subject: [PATCH] Implement trims with column-generation-2 algorithm --- .../tests/knapsack_trims_bins.csv | 2 + .../tests/knapsack_trims_items.csv | 5 +++ .../tests/knapsack_trims_parameters.csv | 5 +++ .../tests/knapsack_trims_solution.csv | 23 +++++++++++ .../column_generation_2.cpp | 38 +++++++++++-------- src/rectangleguillotine/solution_builder.cpp | 18 ++++++--- .../column_generation_2_test.cpp | 6 +++ 7 files changed, 76 insertions(+), 21 deletions(-) create mode 100644 data/rectangleguillotine/tests/knapsack_trims_bins.csv create mode 100644 data/rectangleguillotine/tests/knapsack_trims_items.csv create mode 100644 data/rectangleguillotine/tests/knapsack_trims_parameters.csv create mode 100644 data/rectangleguillotine/tests/knapsack_trims_solution.csv diff --git a/data/rectangleguillotine/tests/knapsack_trims_bins.csv b/data/rectangleguillotine/tests/knapsack_trims_bins.csv new file mode 100644 index 00000000..ef1fce88 --- /dev/null +++ b/data/rectangleguillotine/tests/knapsack_trims_bins.csv @@ -0,0 +1,2 @@ +WIDTH,HEIGHT,LEFT_TRIM,RIGHT_TRIM,BOTTOM_TRIM,TOP_TRIM +20,15,2,3,2,3 diff --git a/data/rectangleguillotine/tests/knapsack_trims_items.csv b/data/rectangleguillotine/tests/knapsack_trims_items.csv new file mode 100644 index 00000000..79559991 --- /dev/null +++ b/data/rectangleguillotine/tests/knapsack_trims_items.csv @@ -0,0 +1,5 @@ +WIDTH,HEIGHT,ORIENTED +10,6,1 +9,4,1 +5,7,2 +4,3,2 diff --git a/data/rectangleguillotine/tests/knapsack_trims_parameters.csv b/data/rectangleguillotine/tests/knapsack_trims_parameters.csv new file mode 100644 index 00000000..9c060abd --- /dev/null +++ b/data/rectangleguillotine/tests/knapsack_trims_parameters.csv @@ -0,0 +1,5 @@ +NAME,VALUE +objective,knapsack +number_of_stages,2 +cut_type,non-exact +first_stage_orientation,vertical diff --git a/data/rectangleguillotine/tests/knapsack_trims_solution.csv b/data/rectangleguillotine/tests/knapsack_trims_solution.csv new file mode 100644 index 00000000..92f1dde7 --- /dev/null +++ b/data/rectangleguillotine/tests/knapsack_trims_solution.csv @@ -0,0 +1,23 @@ +PLATE_ID,NODE_ID,X,Y,WIDTH,HEIGHT,TYPE,CUT,PARENT +0,0,0,0,20,15,0,0, +0,1,0,0,2,2,-1,-1,0 +0,2,0,12,2,3,-1,-1,0 +0,3,17,0,3,2,-1,-1,0 +0,4,17,12,3,3,-1,-1,0 +0,5,0,2,2,10,-1,-1,0 +0,6,2,0,15,2,-1,-1,0 +0,7,17,2,3,10,-1,-1,0 +0,8,2,12,15,3,-1,-1,0 +0,9,2,2,15,10,-2,0,0 +0,10,2,2,5,10,-2,1,9 +0,11,2,2,5,7,-2,2,10 +0,12,2,2,5,7,2,3,11 +0,13,2,9,5,3,-2,2,10 +0,14,2,9,4,3,3,3,13 +0,15,6,9,1,3,-1,3,13 +0,16,7,2,10,10,-2,1,9 +0,17,7,2,10,6,-2,2,16 +0,18,7,2,10,6,0,3,17 +0,19,7,8,10,4,-2,2,16 +0,20,7,8,9,4,1,3,19 +0,21,16,8,1,4,-1,3,19 diff --git a/src/rectangleguillotine/column_generation_2.cpp b/src/rectangleguillotine/column_generation_2.cpp index a5e2ed8b..74a0be2e 100644 --- a/src/rectangleguillotine/column_generation_2.cpp +++ b/src/rectangleguillotine/column_generation_2.cpp @@ -51,6 +51,8 @@ class ColumnGenerationPricingSolver: public columngenerationsolver::PricingSolve columngenerationsolver::Model get_model( const Instance& instance) { + const BinType& bin_type = instance.bin_type(0); + columngenerationsolver::Model model; Profit maximum_bin_type_cost = 0; @@ -99,7 +101,7 @@ columngenerationsolver::Model get_model( columngenerationsolver::Row row; row.lower_bound = 0; - row.upper_bound = instance.bin_type(0).rect.w; + row.upper_bound = bin_type.rect.w - bin_type.left_trim - bin_type.right_trim; row.coefficient_lower_bound = 0; row.coefficient_upper_bound = 1; model.rows.push_back(row); @@ -150,13 +152,16 @@ PricingOutput ColumnGenerationPricingSolver::solve_pricing( const std::vector& duals) { //std::cout << "solve_pricing" << std::endl; + + const BinType& bin_type = instance_.bin_type(0); + PricingOutput output; Value reduced_cost_bound = 0.0; // Generate one-staged exact patterns. { - Length width = instance_.bin_type(0).rect.w - filled_width_; - Length height = instance_.bin_type(0).rect.h; + Length width = bin_type.rect.w - bin_type.left_trim - bin_type.right_trim - filled_width_; + Length height = bin_type.rect.h - bin_type.bottom_trim - bin_type.top_trim; for (;;) { // Build one-dimensional knapsack instance. @@ -211,8 +216,8 @@ PricingOutput ColumnGenerationPricingSolver::solve_pricing( Column column; SolutionBuilder extra_solution_builder(instance_); extra_solution_builder.add_bin(0, 1, CutOrientation::Vertical); - extra_solution_builder.add_node(1, width); - Length cut_position = 0; + extra_solution_builder.add_node(1, bin_type.left_trim + width); + Length cut_position = bin_type.bottom_trim; for (ItemTypeId kp_item_type_id = 0; kp_item_type_id < kp_instance.number_of_item_types(); ++kp_item_type_id) { @@ -295,8 +300,8 @@ PricingOutput ColumnGenerationPricingSolver::solve_pricing( // Generate one-staged non-exact patterns. { - Length width = instance_.bin_type(0).rect.w - filled_width_; - Length height = instance_.bin_type(0).rect.h; + Length width = bin_type.rect.w - bin_type.left_trim - bin_type.right_trim - filled_width_; + Length height = bin_type.rect.h - bin_type.bottom_trim - bin_type.top_trim; for (;;) { // Build one-dimensional knapsack instance. @@ -389,8 +394,8 @@ PricingOutput ColumnGenerationPricingSolver::solve_pricing( // Build extra solution. SolutionBuilder extra_solution_builder(instance_); extra_solution_builder.add_bin(0, 1, CutOrientation::Vertical); - extra_solution_builder.add_node(1, width_max); - Length cut_position = 0; + extra_solution_builder.add_node(1, bin_type.left_trim + width_max); + Length cut_position = bin_type.bottom_trim; for (ItemTypeId kp_item_type_id = 0; kp_item_type_id < kp_instance.number_of_item_types(); ++kp_item_type_id) { @@ -406,7 +411,7 @@ PricingOutput ColumnGenerationPricingSolver::solve_pricing( cut_position += kp_instance.item_type(kp_item_type_id).length; extra_solution_builder.add_node(2, cut_position); if (width_cur < width_max) - extra_solution_builder.add_node(3, width_cur); + extra_solution_builder.add_node(3, bin_type.left_trim + width_cur); extra_solution_builder.set_last_node_item(item_type_id); } } @@ -459,8 +464,8 @@ PricingOutput ColumnGenerationPricingSolver::solve_pricing( // Generate two-staged homogenous patterns. { - Length width = instance_.bin_type(0).rect.w - filled_width_; - Length height = instance_.bin_type(0).rect.h; + Length width = bin_type.rect.w - bin_type.left_trim - bin_type.right_trim - filled_width_; + Length height = bin_type.rect.h - bin_type.bottom_trim - bin_type.top_trim; // TODO } if (instance_.parameters().number_of_stages == 3 @@ -469,8 +474,8 @@ PricingOutput ColumnGenerationPricingSolver::solve_pricing( // Generate other patterns. { - Length width = instance_.bin_type(0).rect.w - filled_width_; - Length height = instance_.bin_type(0).rect.h; + Length width = bin_type.rect.w - bin_type.left_trim - bin_type.right_trim - filled_width_; + Length height = bin_type.rect.h - bin_type.bottom_trim - bin_type.top_trim; // TODO } @@ -511,6 +516,7 @@ void column_generation_2_vertical( cgslds_parameters.new_solution_callback = [&instance, &algorithm_formatter]( const columngenerationsolver::Output& cgs_output) { + const BinType& bin_type = instance.bin_type(0); const columngenerationsolver::LimitedDiscrepancySearchOutput& cgslds_output = static_cast(cgs_output); if (cgslds_output.solution.feasible()) { @@ -525,7 +531,7 @@ void column_generation_2_vertical( bool first = true; Length offset_new = offset; for (const SolutionNode& node: bin.nodes) { - if (node.d == 0) + if (node.d <= 0) continue; if (node.d == 1) { if (!first) @@ -634,7 +640,7 @@ void column_generation_2_horizontal( flipped_bin.copies, CutOrientation::Horizontal); for (const SolutionNode& flipped_node: flipped_bin.nodes) { - if (flipped_node.d == 0) + if (flipped_node.d <= 0) continue; if (flipped_node.d % 2 == 1) { solution_builder.add_node(flipped_node.d, flipped_node.r); diff --git a/src/rectangleguillotine/solution_builder.cpp b/src/rectangleguillotine/solution_builder.cpp index 2c900582..11f9ae4f 100644 --- a/src/rectangleguillotine/solution_builder.cpp +++ b/src/rectangleguillotine/solution_builder.cpp @@ -183,7 +183,15 @@ void SolutionBuilder::set_last_node_item( if (!ok) { throw std::logic_error( "rectangleguillotine::SolutionBuilder::set_last_node_item: " - "wrong item dimensions."); + "wrong item dimensions" + "; item_type_id: " + std::to_string(item_type_id) + + "; item_type.rect.w: " + std::to_string(item_type.rect.w) + + "; item_type.rect.h: " + std::to_string(item_type.rect.h) + + "; node.l: " + std::to_string(node.l) + + "; node.r: " + std::to_string(node.r) + + "; node.b: " + std::to_string(node.b) + + "; node.t: " + std::to_string(node.t) + + "."); } node.item_type_id = item_type_id; @@ -407,16 +415,16 @@ void SolutionBuilder::read( break; } } - std::cout << "bin_type_id " << bin_type_id << std::endl; - std::cout << "first_cut_orientation " << first_cut_orientation << std::endl; + //std::cout << "bin_type_id " << bin_type_id << std::endl; + //std::cout << "first_cut_orientation " << first_cut_orientation << std::endl; add_bin(bin_type_id, 1, first_cut_orientation); for (SolutionNodeId node_id = 0; node_id < (SolutionNodeId)nodes[bin_pos].size(); ++node_id) { const SolutionNode& node = nodes[bin_pos][node_id]; - std::cout << node << std::endl; - if (node.d == 0) + //std::cout << node << std::endl; + if (node.d <= 0) continue; if ((first_cut_orientation == CutOrientation::Vertical && node.d % 2 == 1) diff --git a/test/rectangleguillotine/column_generation_2_test.cpp b/test/rectangleguillotine/column_generation_2_test.cpp index 1742b417..91b6c3f3 100644 --- a/test/rectangleguillotine/column_generation_2_test.cpp +++ b/test/rectangleguillotine/column_generation_2_test.cpp @@ -67,4 +67,10 @@ INSTANTIATE_TEST_SUITE_P( fs::path(""), fs::path("data") / "rectangleguillotine" / "tests" / "knapsack_horizontal_parameters.csv", fs::path("data") / "rectangleguillotine" / "tests" / "knapsack_horizontal_solution.csv", + }, { + fs::path("data") / "rectangleguillotine" / "tests" / "knapsack_trims_items.csv", + fs::path("data") / "rectangleguillotine" / "tests" / "knapsack_trims_bins.csv", + fs::path(""), + fs::path("data") / "rectangleguillotine" / "tests" / "knapsack_trims_parameters.csv", + fs::path("data") / "rectangleguillotine" / "tests" / "knapsack_trims_solution.csv", }}));