[CP-SAT] fix 2 bugs: scheduling lns, multiple_workers with presolve off

This commit is contained in:
Laurent Perron
2023-02-13 06:45:58 -08:00
parent e3d04ed1be
commit 845c252ab4
2 changed files with 35 additions and 49 deletions

View File

@@ -556,9 +556,14 @@ struct Demand {
return std::tie(start, height, end) <
std::tie(other.start, other.height, other.end);
}
std::string DebugString() const {
return absl::StrCat("{i=", interval_index, " span=[", start, ",", end, "]",
" d=", height, "}");
}
};
void InsertPrecedencesFromSortedListOfDemands(
void InsertPrecedencesFromSortedListOfNonOverlapingIntervals(
const std::vector<Demand>& demands,
absl::flat_hash_set<std::pair<int, int>>* precedences) {
for (int i = 0; i + 1 < demands.size(); ++i) {
@@ -568,6 +573,16 @@ void InsertPrecedencesFromSortedListOfDemands(
}
}
bool IsPresent(const ConstraintProto& interval_ct,
const CpSolverResponse& initial_solution) {
if (interval_ct.enforcement_literal().size() != 1) return true;
const int enforcement_ref = interval_ct.enforcement_literal(0);
const int enforcement_var = PositiveRef(enforcement_ref);
const int64_t value = initial_solution.solution(enforcement_var);
return RefIsPositive(enforcement_ref) == (value == 1);
}
void InsertNoOverlapPrecedences(
const absl::flat_hash_set<int>& ignored_intervals,
const CpSolverResponse& initial_solution, const CpModelProto& model_proto,
@@ -580,27 +595,20 @@ void InsertNoOverlapPrecedences(
if (ignored_intervals.contains(interval_index)) continue;
const ConstraintProto& interval_ct =
model_proto.constraints(interval_index);
// We only look at intervals that are performed in the solution. The
// unperformed intervals should be automatically freed during the generation
// phase.
if (interval_ct.enforcement_literal().size() == 1) {
const int enforcement_ref = interval_ct.enforcement_literal(0);
const int enforcement_var = PositiveRef(enforcement_ref);
const int value = initial_solution.solution(enforcement_var);
if (RefIsPositive(enforcement_ref) == (value == 0)) {
continue;
}
}
if (!IsPresent(interval_ct, initial_solution)) continue;
const int64_t start_value = GetLinearExpressionValue(
interval_ct.interval().start(), initial_solution);
const int64_t end_value = GetLinearExpressionValue(
interval_ct.interval().size(), initial_solution);
interval_ct.interval().end(), initial_solution);
DCHECK_LE(start_value, end_value);
demands.push_back({interval_index, start_value, end_value, 1});
}
// TODO(user): We actually only need interval_index, start.
// No need to fill the other fields here.
std::sort(demands.begin(), demands.end());
InsertPrecedencesFromSortedListOfDemands(demands, precedences);
InsertPrecedencesFromSortedListOfNonOverlapingIntervals(demands, precedences);
}
void ProcessDemandListFromCumulativeConstraint(
@@ -628,7 +636,8 @@ void ProcessDemandListFromCumulativeConstraint(
DCHECK_GT(sum_of_min_two_capacities, 1);
if (sum_of_min_two_capacities > capacity) {
InsertPrecedencesFromSortedListOfDemands(demands, precedences);
InsertPrecedencesFromSortedListOfNonOverlapingIntervals(demands,
precedences);
return;
}
@@ -719,20 +728,9 @@ void InsertCumulativePrecedences(
for (int i = 0; i < cumulative.intervals().size(); ++i) {
const int interval_index = cumulative.intervals(i);
if (ignored_intervals.contains(interval_index)) continue;
const ConstraintProto& interval_ct =
model_proto.constraints(interval_index);
// We only look at intervals that are performed in the solution. The
// unperformed intervals should be automatically freed during the generation
// phase.
if (interval_ct.enforcement_literal().size() == 1) {
const int enforcement_ref = interval_ct.enforcement_literal(0);
const int enforcement_var = PositiveRef(enforcement_ref);
const int value = initial_solution.solution(enforcement_var);
if (RefIsPositive(enforcement_ref) == (value == 0)) {
continue;
}
}
if (!IsPresent(interval_ct, initial_solution)) continue;
const int64_t start_value = GetLinearExpressionValue(
interval_ct.interval().start(), initial_solution);
@@ -779,10 +777,11 @@ void InsertRectanglePredecences(
const std::vector<Rectangle>& rectangles,
absl::flat_hash_set<std::pair<int, int>>* precedences) {
// TODO(user): Refine set of interesting points.
absl::flat_hash_set<int64_t> interesting_points;
std::vector<int64_t> interesting_points;
for (const Rectangle& r : rectangles) {
interesting_points.insert(r.y_end - 1);
interesting_points.push_back(r.y_end - 1);
}
gtl::STLSortAndRemoveDuplicates(&interesting_points);
std::vector<Demand> demands;
for (const int64_t t : interesting_points) {
demands.clear();
@@ -791,7 +790,8 @@ void InsertRectanglePredecences(
demands.push_back({r.interval_index, r.x_start, r.x_end, 1});
}
std::sort(demands.begin(), demands.end());
InsertPrecedencesFromSortedListOfDemands(demands, precedences);
InsertPrecedencesFromSortedListOfNonOverlapingIntervals(demands,
precedences);
}
}
@@ -811,27 +811,13 @@ void InsertNoOverlap2dPrecedences(
if (ignored_intervals.contains(x_interval_index)) continue;
const ConstraintProto& x_interval_ct =
model_proto.constraints(x_interval_index);
if (x_interval_ct.enforcement_literal().size() == 1) {
const int enforcement_ref = x_interval_ct.enforcement_literal(0);
const int enforcement_var = PositiveRef(enforcement_ref);
const int value = initial_solution.solution(enforcement_var);
if (RefIsPositive(enforcement_ref) == (value == 0)) {
continue;
}
}
if (!IsPresent(x_interval_ct, initial_solution)) continue;
const int y_interval_index = no_overlap_2d.y_intervals(i);
if (ignored_intervals.contains(y_interval_index)) continue;
const ConstraintProto& y_interval_ct =
model_proto.constraints(y_interval_index);
if (y_interval_ct.enforcement_literal().size() == 1) {
const int enforcement_ref = y_interval_ct.enforcement_literal(0);
const int enforcement_var = PositiveRef(enforcement_ref);
const int value = initial_solution.solution(enforcement_var);
if (RefIsPositive(enforcement_ref) == (value == 0)) {
continue;
}
}
if (!IsPresent(y_interval_ct, initial_solution)) continue;
const int64_t x_start_value = GetLinearExpressionValue(
x_interval_ct.interval().start(), initial_solution);

View File

@@ -2651,6 +2651,7 @@ class LnsSolver : public SubSolver {
SatParameters local_params(parameters_);
local_params.set_max_deterministic_time(data.deterministic_limit);
local_params.set_stop_after_first_solution(false);
local_params.set_cp_model_presolve(true);
local_params.set_log_search_progress(false);
local_params.set_cp_model_probing_level(0);
local_params.set_symmetry_level(0);
@@ -2756,9 +2757,8 @@ class LnsSolver : public SubSolver {
data.status = local_response.status();
// TODO(user): we actually do not need to postsolve if the solution is
// not going to be used...
if (local_params.cp_model_presolve() &&
(data.status == CpSolverStatus::OPTIMAL ||
data.status == CpSolverStatus::FEASIBLE)) {
if (data.status == CpSolverStatus::OPTIMAL ||
data.status == CpSolverStatus::FEASIBLE) {
PostsolveResponseWrapper(
local_params, helper_->ModelProto().variables_size(), mapping_proto,
postsolve_mapping, &solution_values);