Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #165

Merged
merged 2 commits into from
Mar 12, 2025
Merged

Dev #165

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,18 @@ class AlgorithmFormatter
const Solution& solution,
const std::string& s);

/** Update the knapsack bound. */
void update_knapsack_bound(
Profit profit);

/** Update the bin packing bound. */
void update_bin_packing_bound(
BinPos number_of_bins);

/** Update the bin packing bound. */
void update_variable_sized_bin_packing_bound(
Profit cost);

/** Method to call at the end of the algorithm. */
void end();

Expand Down
91 changes: 90 additions & 1 deletion src/rectangle/dual_feasible_functions.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "rectangle/dual_feasible_functions.hpp"

#include "packingsolver/rectangle/algorithm_formatter.hpp"
#include "packingsolver/rectangle/instance_builder.hpp"

using namespace packingsolver;
using namespace packingsolver::rectangle;
Expand Down Expand Up @@ -92,8 +93,96 @@ DualFeasibleFunctionsOutput packingsolver::rectangle::dual_feasible_functions(
break;
}
}
if (!all_items_oriented)
if (!all_items_oriented) {
// If there are some non-oriented items, we use the strategy from
// clautiaux2007:
// - Build a modified instance containing for each item of the original
// instance, one item for each orientation.
// - Compute the bound on the modified instance.
// - Divide it by 2 to get the bound of the original instance.

BinPos bound = 0;
for (;;) {
// Build modified instance.
InstanceBuilder modified_instance_builder;
modified_instance_builder.set_objective(instance.objective());
modified_instance_builder.set_parameters(instance.parameters());
// Add bins and dummy items.
if (bin_type.rect.x == bin_type.rect.y) {
modified_instance_builder.add_bin_type(
bin_type.rect.x,
bin_type.rect.y,
-1,
2 * instance.number_of_items());
} else if (bin_type.rect.x > bin_type.rect.y) {
modified_instance_builder.add_bin_type(
bin_type.rect.x,
bin_type.rect.x,
-1,
2 * instance.number_of_items() + bound);
modified_instance_builder.add_item_type(
bin_type.rect.x,
bin_type.rect.x - bin_type.rect.y,
-1,
bound);
} else if (bin_type.rect.x < bin_type.rect.y) {
modified_instance_builder.add_bin_type(
bin_type.rect.y,
bin_type.rect.y,
-1,
2 * instance.number_of_items() + bound);
modified_instance_builder.add_item_type(
bin_type.rect.y - bin_type.rect.x,
bin_type.rect.y,
-1,
bound);
}
// Add items.
for (ItemTypeId item_type_id = 0;
item_type_id < instance.number_of_item_types();
++item_type_id) {
ItemType item_type = instance.item_type(item_type_id);
item_type.oriented = true;
if (item_type.rect.x == item_type.rect.y) {
modified_instance_builder.add_item_type(
item_type,
item_type.profit,
2 * item_type.copies);
} else {
modified_instance_builder.add_item_type(
item_type,
item_type.profit,
item_type.copies);
item_type.rect.x = instance.item_type(item_type_id).rect.y;
item_type.rect.y = instance.item_type(item_type_id).rect.x;
modified_instance_builder.add_item_type(
item_type,
item_type.profit,
item_type.copies);
}
}
Instance modified_instance = modified_instance_builder.build();

// Compute the bound on the modified instance.
DualFeasibleFunctionsParameters modified_parameters;
modified_parameters.verbosity_level = 0;
auto modified_output = dual_feasible_functions(
modified_instance,
modified_parameters);

// Retrieve the bound of the original instance.
BinPos bound_cur = (modified_output.bin_packing_bound - 1) / 2 + 1;
if (bound >= bound_cur)
break;
bound = bound_cur;
algorithm_formatter.update_bin_packing_bound(bound);

if (bin_type.rect.x == bin_type.rect.y)
break;
}
algorithm_formatter.end();
return output;
}

// Compute all distinct widths and heights.
std::vector<Length> widths;
Expand Down
3 changes: 3 additions & 0 deletions src/rectangle/dual_feasible_functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
* - "A theoretical and experimental study of fast lower bounds for the
* two-dimensional bin packing problem" (Serairi1 et Haouari, 2018)
* https://doi.org/10.1051/ro/2017019
* - "A new lower bound for the non-oriented two-dimensional bin-packing
* problem☆" (Clautiaux et al., 2007)
* https://doi.org/10.1016/j.orl.2006.07.001
*/

#pragma once
Expand Down
35 changes: 35 additions & 0 deletions src/rectangleguillotine/algorithm_formatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,23 @@ void AlgorithmFormatter::update_solution(
mutex_.unlock();
}

void AlgorithmFormatter::update_knapsack_bound(
Profit profit)
{
mutex_.lock();
if (profit < output_.knapsack_bound) {
output_.knapsack_bound = profit;
output_.json["IntermediaryOutputs"].push_back(output_.to_json());
parameters_.new_solution_callback(output_);

// Check optimality.
if (equal(output_.knapsack_bound, output_.solution_pool.best().profit())) {
end_ = true;
}
}
mutex_.unlock();
}

void AlgorithmFormatter::update_bin_packing_bound(
BinPos number_of_bins)
{
Expand All @@ -250,6 +267,24 @@ void AlgorithmFormatter::update_bin_packing_bound(
mutex_.unlock();
}

void AlgorithmFormatter::update_variable_sized_bin_packing_bound(
Profit cost)
{
mutex_.lock();
if (cost > output_.variable_sized_bin_packing_bound) {
output_.variable_sized_bin_packing_bound = cost;
output_.json["IntermediaryOutputs"].push_back(output_.to_json());
parameters_.new_solution_callback(output_);

// Check optimality.
if (output_.solution_pool.best().full()
&& equal(output_.variable_sized_bin_packing_bound, output_.solution_pool.best().cost())) {
end_ = true;
}
}
mutex_.unlock();
}

void AlgorithmFormatter::end()
{
output_.time = parameters_.timer.elapsed_time();
Expand Down
10 changes: 10 additions & 0 deletions src/rectangleguillotine/column_generation_2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1522,6 +1522,14 @@ void column_generation_2_vertical(
//std::cout << "callback end" << std::endl;
}
};
cgslds_parameters.new_bound_callback = [&instance, &algorithm_formatter](
const columngenerationsolver::Output& cgs_output)
{
const columngenerationsolver::LimitedDiscrepancySearchOutput& cgslds_output
= static_cast<const columngenerationsolver::LimitedDiscrepancySearchOutput&>(cgs_output);
double multiplier_profit = largest_power_of_two_lesser_or_equal(instance.largest_item_profit());
algorithm_formatter.update_knapsack_bound(cgslds_output.bound * multiplier_profit);
};
cgslds_parameters.column_generation_parameters.solver_name
= parameters.linear_programming_solver_name;
columngenerationsolver::limited_discrepancy_search(cgs_model, cgslds_parameters);
Expand Down Expand Up @@ -1551,6 +1559,8 @@ void column_generation_2_horizontal(
algorithm_formatter.update_solution(
solution,
ss.str());
algorithm_formatter.update_knapsack_bound(
flipped_output.knapsack_bound);
};
column_generation_2(
flipped_instance,
Expand Down
24 changes: 23 additions & 1 deletion src/rectangleguillotine/optimize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ void optimize_column_generation_2(
std::stringstream ss;
ss << "CG";
algorithm_formatter.update_solution(pscg_output.solution_pool.best(), ss.str());
algorithm_formatter.update_knapsack_bound(pscg_output.knapsack_bound);
};
column_generation_2(instance, cg_parameters);
}
Expand Down Expand Up @@ -372,6 +373,24 @@ void optimize_column_generation(
algorithm_formatter.update_solution(solution, ss.str());
}
};
cgslds_parameters.new_bound_callback = [&instance, &algorithm_formatter](
const columngenerationsolver::Output& cgs_output)
{
const columngenerationsolver::LimitedDiscrepancySearchOutput& cgslds_output
= static_cast<const columngenerationsolver::LimitedDiscrepancySearchOutput&>(cgs_output);
if (instance.objective() == Objective::VariableSizedBinPacking) {
double multiplier_cost = largest_power_of_two_lesser_or_equal(instance.largest_bin_cost());
algorithm_formatter.update_variable_sized_bin_packing_bound(cgslds_output.bound * multiplier_cost);
} else if (instance.objective() == Objective::Knapsack) {
double multiplier_profit = largest_power_of_two_lesser_or_equal(instance.largest_item_profit());
algorithm_formatter.update_knapsack_bound(cgslds_output.bound * multiplier_profit);
} else if (instance.objective() == Objective::BinPacking) {
double multiplier_cost = largest_power_of_two_lesser_or_equal(instance.largest_bin_cost());
BinPos bin_packing_bound = std::ceil(cgslds_output.bound * multiplier_cost / instance.bin_type(0).space() - 0.001);
std::cout << "bin_packing_bound " << bin_packing_bound << std::endl;
algorithm_formatter.update_bin_packing_bound(bin_packing_bound);
}
};
cgslds_parameters.column_generation_parameters.solver_name
= parameters.linear_programming_solver_name;
columngenerationsolver::limited_discrepancy_search(cgs_model, cgslds_parameters);
Expand Down Expand Up @@ -407,7 +426,10 @@ packingsolver::rectangleguillotine::Output packingsolver::rectangleguillotine::o
if (!use_tree_search
&& !use_column_generation_2) {
use_tree_search = true;
//use_column_generation_2 = true;
//if (instance.number_of_stacks() != instance.number_of_item_types()
// && instance.number_of_defects() == 0) {
// use_column_generation_2 = true;
//}
}
} else if (instance.objective() == Objective::Knapsack) {
// Disable algorithms which are not available for this objective.
Expand Down
Loading