Skip to content

Commit

Permalink
[CP-SAT] add packing_precedences_lns
Browse files Browse the repository at this point in the history
  • Loading branch information
lperron committed Aug 9, 2023
1 parent ff8e0d2 commit b3e663d
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 24 deletions.
18 changes: 18 additions & 0 deletions ortools/sat/cp_model_lns.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
#include "ortools/util/saturated_arithmetic.h"
#include "ortools/util/sorted_interval_list.h"
#include "ortools/util/strong_integers.h"
#include "ortools/util/time_limit.h"

namespace operations_research {
namespace sat {
Expand Down Expand Up @@ -2061,6 +2062,23 @@ Neighborhood RandomRectanglesPackingNeighborhoodGenerator::Generate(
return helper_.FixGivenVariables(initial_solution, variables_to_freeze);
}

Neighborhood RandomPrecedencesPackingNeighborhoodGenerator::Generate(
const CpSolverResponse& initial_solution, double difficulty,
absl::BitGenRef random) {
std::vector<std::pair<int, int>> rectangles_to_relax =
helper_.GetActiveRectangles(initial_solution);
GetRandomSubset(difficulty, &rectangles_to_relax, random);
std::vector<int> intervals_to_relax;
for (const auto& [x, y] : rectangles_to_relax) {
intervals_to_relax.push_back(x);
intervals_to_relax.push_back(y);
}
gtl::STLSortAndRemoveDuplicates(&intervals_to_relax);

return GenerateSchedulingNeighborhoodFromRelaxedIntervals(
intervals_to_relax, initial_solution, random, helper_);
}

Neighborhood SlicePackingNeighborhoodGenerator::Generate(
const CpSolverResponse& initial_solution, double difficulty,
absl::BitGenRef random) {
Expand Down
17 changes: 16 additions & 1 deletion ortools/sat/cp_model_lns.h
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ class SchedulingResourceWindowsNeighborhoodGenerator

// Only make sense for problems with no_overlap_2d constraints. This select a
// random set of rectangles (i.e. a pair of intervals) of the problem according
// to the difficulty. Then, fix all variables in the selected intervals.
// to the difficulty. Then fix all variables in the selected intervals.
class RandomRectanglesPackingNeighborhoodGenerator
: public NeighborhoodGenerator {
public:
Expand All @@ -695,6 +695,21 @@ class RandomRectanglesPackingNeighborhoodGenerator
double difficulty, absl::BitGenRef random) final;
};

// Only make sense for problems with no_overlap_2d constraints. This select a
// random set of rectangles (i.e. a pair of intervals) of the problem according
// to the difficulty. Then add all implied precedences from the current
// positions of the rectangles in this
class RandomPrecedencesPackingNeighborhoodGenerator
: public NeighborhoodGenerator {
public:
explicit RandomPrecedencesPackingNeighborhoodGenerator(
NeighborhoodGeneratorHelper const* helper, const std::string& name)
: NeighborhoodGenerator(name, helper) {}

Neighborhood Generate(const CpSolverResponse& initial_solution,
double difficulty, absl::BitGenRef random) final;
};

// Only make sense for problems with no_overlap_2d constraints. This select a
// slice on one dimension, and fix the variables of all rectangles not strictly
// included in this slice.
Expand Down
61 changes: 38 additions & 23 deletions ortools/sat/cp_model_solver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,17 @@
#include <memory>
#include <random>
#include <string>
#include <string_view>
#include <thread>
#include <tuple>
#include <utility>
#include <vector>

#include "absl/container/flat_hash_map.h"
#include "absl/random/distributions.h"
#include "google/protobuf/arena.h"
#include "ortools/base/logging.h"
#include "ortools/base/timer.h"
#include "ortools/sat/intervals.h"
#if !defined(__PORTABLE_PLATFORM__)
#include "ortools/base/file.h"
#include "ortools/base/helpers.h"
Expand Down Expand Up @@ -3669,43 +3672,55 @@ void SolveCpModelParallel(const CpModelProto& model_proto,
params, helper, &shared));
}

// TODO(user): If we have a model with scheduling + routing. We create
// a lot of LNS generators. Investigate if we can reduce this number.
if (!helper->TypeToConstraints(ConstraintProto::kNoOverlap).empty() ||
!helper->TypeToConstraints(ConstraintProto::kNoOverlap2D).empty() ||
!helper->TypeToConstraints(ConstraintProto::kCumulative).empty()) {
const bool has_no_overlap_or_cumulative =
!helper->TypeToConstraints(ConstraintProto::kNoOverlap).empty() ||
!helper->TypeToConstraints(ConstraintProto::kCumulative).empty();
const bool has_no_overlap2d =
!helper->TypeToConstraints(ConstraintProto::kNoOverlap2D).empty();

// Scheduling (no_overlap and cumulative) specific LNS.
const std::vector<std::vector<int>> intervals_in_constraints =
helper->GetUniqueIntervalSets();
if (has_no_overlap_or_cumulative) {
subsolvers.push_back(std::make_unique<LnsSolver>(
std::make_unique<RandomIntervalSchedulingNeighborhoodGenerator>(
helper, "scheduling_intervals_lns"),
params, helper, &shared));
subsolvers.push_back(std::make_unique<LnsSolver>(
std::make_unique<RandomPrecedenceSchedulingNeighborhoodGenerator>(
helper, "scheduling_precedences_lns"),
params, helper, &shared));
subsolvers.push_back(std::make_unique<LnsSolver>(
std::make_unique<SchedulingTimeWindowNeighborhoodGenerator>(
helper, "scheduling_time_window_lns"),
params, helper, &shared));

const std::vector<std::vector<int>> intervals_in_constraints =
helper->GetUniqueIntervalSets();
if (intervals_in_constraints.size() > 2) {
subsolvers.push_back(std::make_unique<LnsSolver>(
std::make_unique<SchedulingResourceWindowsNeighborhoodGenerator>(
helper, intervals_in_constraints,
"scheduling_resource_windows_lns"),
params, helper, &shared));
}
if (!helper->TypeToConstraints(ConstraintProto::kNoOverlap2D).empty()) {
subsolvers.push_back(std::make_unique<LnsSolver>(
std::make_unique<RandomRectanglesPackingNeighborhoodGenerator>(
helper, "packing_rectangles_lns"),
params, helper, &shared));
subsolvers.push_back(std::make_unique<LnsSolver>(
std::make_unique<SlicePackingNeighborhoodGenerator>(
helper, "packing_slice_lns"),
params, helper, &shared));
}
}

// Packing (no_overlap_2d) Specific LNS.
if (has_no_overlap2d) {
subsolvers.push_back(std::make_unique<LnsSolver>(
std::make_unique<RandomRectanglesPackingNeighborhoodGenerator>(
helper, "packing_rectangles_lns"),
params, helper, &shared));
subsolvers.push_back(std::make_unique<LnsSolver>(
std::make_unique<RandomPrecedencesPackingNeighborhoodGenerator>(
helper, "packing_precedences_lns"),
params, helper, &shared));
subsolvers.push_back(std::make_unique<LnsSolver>(
std::make_unique<SlicePackingNeighborhoodGenerator>(
helper, "packing_slice_lns"),
params, helper, &shared));
}

// Generic scheduling/packing LNS.
if (has_no_overlap_or_cumulative || has_no_overlap2d) {
subsolvers.push_back(std::make_unique<LnsSolver>(
std::make_unique<RandomPrecedenceSchedulingNeighborhoodGenerator>(
helper, "scheduling_precedences_lns"),
params, helper, &shared));
}

const int num_circuit = static_cast<int>(
Expand Down

0 comments on commit b3e663d

Please sign in to comment.