22#include "absl/container/flat_hash_set.h"
23#include "absl/synchronization/mutex.h"
43 shared_time_limit_(shared_time_limit),
44 shared_bounds_(shared_bounds),
45 shared_response_(shared_response) {
46 CHECK(shared_response_ !=
nullptr);
47 if (shared_bounds_ !=
nullptr) {
50 *model_proto_with_only_variables_.mutable_variables() =
52 InitializeHelperData();
53 RecomputeHelperData();
58 if (shared_bounds_ !=
nullptr) {
59 std::vector<int> model_variables;
60 std::vector<int64_t> new_lower_bounds;
61 std::vector<int64_t> new_upper_bounds;
63 &new_lower_bounds, &new_upper_bounds);
65 bool new_variables_have_been_fixed =
false;
68 absl::MutexLock domain_lock(&domain_mutex_);
70 for (
int i = 0; i < model_variables.size(); ++i) {
71 const int var = model_variables[i];
72 const int64_t new_lb = new_lower_bounds[i];
73 const int64_t new_ub = new_upper_bounds[i];
76 model_proto_with_only_variables_.variables(
var).domain();
77 const int64_t old_lb = domain.Get(0);
78 const int64_t old_ub = domain.Get(domain.size() - 1);
79 VLOG(3) <<
"Variable: " <<
var <<
" old domain: [" << old_lb <<
", "
80 << old_ub <<
"] new domain: [" << new_lb <<
", " << new_ub
84 model_proto_with_only_variables_.variables(
var));
105 model_proto_with_only_variables_.mutable_variables(
var));
106 new_variables_have_been_fixed |= new_domain.
IsFixed();
111 if (new_variables_have_been_fixed) {
112 RecomputeHelperData();
117void NeighborhoodGeneratorHelper::InitializeHelperData() {
118 type_to_constraints_.clear();
120 for (
int c = 0; c < num_constraints; ++c) {
122 if (type >= type_to_constraints_.size()) {
123 type_to_constraints_.resize(type + 1);
125 type_to_constraints_[type].push_back(c);
129void NeighborhoodGeneratorHelper::RecomputeHelperData() {
137 absl::ReaderMutexLock domain_lock(&domain_mutex_);
146 if (IsConstant(
var))
continue;
147 var_to_constraint_[
var].push_back(ct_index);
148 constraint_to_var_[ct_index].push_back(
var);
158 if (IsConstant(
var))
continue;
159 var_to_constraint_[
var].push_back(ct_index);
160 constraint_to_var_[ct_index].push_back(
var);
166 active_variables_.clear();
167 active_variables_set_.assign(model_proto_.
variables_size(),
false);
171 for (
const int var : search_strategy.variables()) {
173 if (!active_variables_set_[pos_var] && !IsConstant(pos_var)) {
174 active_variables_set_[pos_var] =
true;
175 active_variables_.push_back(pos_var);
181 if (!active_variables_.empty())
return;
186 if (!IsConstant(i)) {
187 active_variables_.push_back(i);
188 active_variables_set_[i] =
true;
194 return active_variables_set_[
var];
197bool NeighborhoodGeneratorHelper::IsConstant(
int var)
const {
198 return model_proto_with_only_variables_.variables(
var).domain_size() == 2 &&
199 model_proto_with_only_variables_.variables(
var).domain(0) ==
200 model_proto_with_only_variables_.variables(
var).domain(1);
205 const absl::flat_hash_set<int>& fixed_variables_set,
217 if (fixed_variables_set.contains(i)) {
236 absl::ReaderMutexLock lock(&domain_mutex_);
238 model_proto_with_only_variables_.variables();
251 std::vector<int> active_intervals;
252 absl::ReaderMutexLock lock(&domain_mutex_);
260 const int enforcement_var =
PositiveRef(enforcement_ref);
261 const int value = initial_solution.
solution(enforcement_var);
271 bool is_constant =
true;
273 if (!IsConstant(v)) {
279 if (!IsConstant(v)) {
285 if (!IsConstant(v)) {
290 if (is_constant)
continue;
300 active_intervals.push_back(i);
302 return active_intervals;
307 struct HeadAndArcLiteral {
312 std::vector<std::vector<int>> result;
313 absl::flat_hash_map<int, HeadAndArcLiteral> tail_to_head_and_arc_literal;
320 tail_to_head_and_arc_literal.clear();
321 for (
int i = 0; i <
ct.literals_size(); ++i) {
323 const int head =
ct.heads(i);
324 const int tail =
ct.tails(i);
331 tail_to_head_and_arc_literal[
tail] = {
head, bool_var};
334 if (tail_to_head_and_arc_literal.empty())
continue;
337 int current_node = min_node;
338 std::vector<int> path;
340 auto it = tail_to_head_and_arc_literal.find(current_node);
341 CHECK(it != tail_to_head_and_arc_literal.end());
342 current_node = it->second.head;
343 path.push_back(it->second.literal);
344 }
while (current_node != min_node);
345 result.push_back(std::move(path));
348 std::vector<HeadAndArcLiteral> route_starts;
351 tail_to_head_and_arc_literal.clear();
352 route_starts.clear();
355 for (
int i = 0; i <
ct.literals_size(); ++i) {
357 const int head =
ct.heads(i);
358 const int tail =
ct.tails(i);
366 route_starts.push_back({
head, bool_var});
368 tail_to_head_and_arc_literal[
tail] = {
head, bool_var};
373 for (
const HeadAndArcLiteral& head_var : route_starts) {
374 std::vector<int> path;
375 int current_node = head_var.head;
376 path.push_back(head_var.literal);
378 auto it = tail_to_head_and_arc_literal.find(current_node);
379 CHECK(it != tail_to_head_and_arc_literal.end());
380 current_node = it->second.head;
381 path.push_back(it->second.literal);
382 }
while (current_node != 0);
383 result.push_back(std::move(path));
392 const absl::flat_hash_set<int>& variables_to_fix)
const {
395 bool copy_is_successful =
true;
397 absl::ReaderMutexLock domain_lock(&domain_mutex_);
400 initial_solution, &neighborhood.
delta);
403 if (!copy_is_successful) {
410 neighborhood.
is_reduced = !variables_to_fix.empty();
428 if (is_fixed(
var))
continue;
437 const std::vector<int>& constraints_to_remove)
const {
440 if (constraints_to_remove.empty())
return neighborhood;
448 const std::vector<int>& relaxed_variables)
const {
449 std::vector<bool> relaxed_variables_set(model_proto_.
variables_size(),
false);
450 for (
const int var : relaxed_variables) relaxed_variables_set[
var] =
true;
451 absl::flat_hash_set<int> fixed_variables;
454 for (
const int i : active_variables_) {
455 if (!relaxed_variables_set[i]) {
456 fixed_variables.insert(i);
466 const absl::flat_hash_set<int> fixed_variables(all_variables.begin(),
467 all_variables.end());
478 if (num_calls_ <= 10)
return std::numeric_limits<double>::infinity();
479 return current_average_ + sqrt((2 * log(total_num_calls)) / num_calls_);
487 std::sort(solve_data_.begin(), solve_data_.end());
490 int num_fully_solved_in_batch = 0;
491 int num_not_fully_solved_in_batch = 0;
493 for (
const SolveData& data : solve_data_) {
502 ++num_fully_solved_calls_;
503 ++num_fully_solved_in_batch;
505 ++num_not_fully_solved_in_batch;
514 const IntegerValue best_objective_improvement =
516 ? IntegerValue(
CapSub(data.new_objective_bound.value(),
517 data.initial_best_objective_bound.value()))
518 : IntegerValue(
CapSub(data.initial_best_objective.value(),
519 data.new_objective.value()));
520 if (best_objective_improvement > 0) {
521 num_consecutive_non_improving_calls_ = 0;
523 ++num_consecutive_non_improving_calls_;
528 const double gain_per_time_unit =
529 std::max(0.0,
static_cast<double>(best_objective_improvement.value())) /
530 (1.0 + data.deterministic_time);
531 if (num_calls_ <= 100) {
532 current_average_ += (gain_per_time_unit - current_average_) / num_calls_;
534 current_average_ = 0.9 * current_average_ + 0.1 * gain_per_time_unit;
537 deterministic_time_ += data.deterministic_time;
541 difficulty_.
Update(num_not_fully_solved_in_batch,
542 num_fully_solved_in_batch);
550 if (num_consecutive_non_improving_calls_ > 50) {
551 num_consecutive_non_improving_calls_ = 0;
552 deterministic_limit_ *= 1.02;
556 deterministic_limit_ =
std::min(60.0, deterministic_limit_);
564void GetRandomSubset(
double relative_size, std::vector<int>* base,
565 absl::BitGenRef random) {
566 if (base->empty())
return;
570 std::shuffle(base->begin(), base->end(), random);
571 const int target_size = std::round(relative_size * base->size());
572 base->resize(target_size);
579 absl::BitGenRef random) {
581 GetRandomSubset(1.0 -
difficulty, &fixed_variables, random);
583 initial_solution, {fixed_variables.begin(), fixed_variables.end()});
588 absl::BitGenRef random) {
589 std::vector<int> active_constraints;
595 active_constraints.push_back(
ct);
598 if (active_constraints.empty() ||
603 std::shuffle(active_constraints.begin(), active_constraints.end(), random);
608 std::vector<bool> visited_variables_set(num_model_vars,
false);
609 std::vector<int> relaxed_variables;
613 const int num_active_vars =
615 const int target_size = std::ceil(
difficulty * num_active_vars);
618 for (
const int constraint_index : active_constraints) {
619 CHECK_LT(constraint_index, num_model_constraints);
621 if (visited_variables_set[
var])
continue;
622 visited_variables_set[
var] =
true;
624 relaxed_variables.push_back(
var);
625 if (relaxed_variables.size() == target_size)
break;
628 if (relaxed_variables.size() == target_size)
break;
636 absl::BitGenRef random) {
642 std::vector<bool> visited_variables_set(num_model_vars,
false);
643 std::vector<int> relaxed_variables;
644 std::vector<int> visited_variables;
648 std::vector<bool> scanned_constraints(num_model_constraints,
false);
650 std::vector<int> random_variables;
656 const int num_active_vars =
658 const int target_size = std::ceil(
difficulty * num_active_vars);
661 const int first_var =
663 random, 0, num_active_vars)];
665 visited_variables_set[first_var] =
true;
666 visited_variables.push_back(first_var);
667 relaxed_variables.push_back(first_var);
669 for (
int i = 0; i < visited_variables.size(); ++i) {
670 random_variables.clear();
674 if (scanned_constraints[
ct])
continue;
675 scanned_constraints[
ct] =
true;
677 if (visited_variables_set[
var])
continue;
678 visited_variables_set[
var] =
true;
679 random_variables.push_back(
var);
684 std::shuffle(random_variables.begin(), random_variables.end(), random);
685 for (
const int var : random_variables) {
686 if (relaxed_variables.size() < target_size) {
687 visited_variables.push_back(
var);
689 relaxed_variables.push_back(
var);
695 if (relaxed_variables.size() >= target_size)
break;
703 absl::BitGenRef random) {
705 if (num_model_constraints == 0 ||
711 std::vector<bool> visited_variables_set(num_model_vars,
false);
712 std::vector<int> relaxed_variables;
714 std::vector<bool> added_constraints(num_model_constraints,
false);
715 std::vector<int> next_constraints;
718 next_constraints.push_back(
719 absl::Uniform<int>(random, 0, num_model_constraints));
720 added_constraints[next_constraints.back()] =
true;
722 std::vector<int> random_variables;
725 const int num_active_vars =
727 const int target_size = std::ceil(
difficulty * num_active_vars);
730 while (relaxed_variables.size() < target_size) {
732 if (next_constraints.empty())
break;
735 const int i = absl::Uniform<int>(random, 0, next_constraints.size());
736 const int constraint_index = next_constraints[i];
737 std::swap(next_constraints[i], next_constraints.back());
738 next_constraints.pop_back();
742 CHECK_LT(constraint_index, num_model_constraints);
744 std::shuffle(random_variables.begin(), random_variables.end(), random);
745 for (
const int var : random_variables) {
746 if (visited_variables_set[
var])
continue;
747 visited_variables_set[
var] =
true;
749 relaxed_variables.push_back(
var);
751 if (relaxed_variables.size() == target_size)
break;
754 if (added_constraints[
ct])
continue;
755 added_constraints[
ct] =
true;
756 next_constraints.push_back(
ct);
774LinearExpressionProto GetSize(
const IntervalConstraintProto&
interval) {
776 LinearExpressionProto result;
778 result.add_coeffs(1);
782LinearExpressionProto GetEnd(
const IntervalConstraintProto&
interval) {
784 LinearExpressionProto result;
786 result.add_coeffs(1);
790int64_t GetLinearExpressionValue(
const LinearExpressionProto& expr,
791 const CpSolverResponse& initial_solution) {
792 int64_t result = expr.offset();
793 for (
int i = 0; i < expr.vars_size(); ++i) {
794 result += expr.coeffs(i) * initial_solution.solution(expr.vars(i));
799void AddLinearExpressionToConstraint(
const int64_t coeff,
800 const LinearExpressionProto& expr,
801 LinearConstraintProto* constraint,
802 int64_t* rhs_offset) {
803 *rhs_offset -= coeff * expr.offset();
804 for (
int i = 0; i < expr.vars_size(); ++i) {
805 constraint->add_vars(expr.vars(i));
806 constraint->add_coeffs(expr.coeffs(i) * coeff);
810void AddPrecedenceConstraints(
const absl::Span<const int> intervals,
811 const absl::flat_hash_set<int>& ignored_intervals,
812 const CpSolverResponse& initial_solution,
813 const NeighborhoodGeneratorHelper& helper,
814 Neighborhood* neighborhood) {
817 std::vector<std::pair<int64_t, int>> start_interval_pairs;
818 for (
const int i : intervals) {
819 if (ignored_intervals.contains(i))
continue;
820 const ConstraintProto& interval_ct = helper.ModelProto().constraints(i);
823 const LinearExpressionProto size_var = GetSize(interval_ct.interval());
824 if (GetLinearExpressionValue(size_var, initial_solution) == 0)
continue;
826 const LinearExpressionProto start_var = GetStart(interval_ct.interval());
827 const int64_t start_value =
828 GetLinearExpressionValue(start_var, initial_solution);
830 start_interval_pairs.push_back({start_value, i});
832 std::sort(start_interval_pairs.begin(), start_interval_pairs.end());
835 for (
int i = 0; i + 1 < start_interval_pairs.size(); ++i) {
836 const LinearExpressionProto before_start =
837 GetStart(helper.ModelProto()
838 .constraints(start_interval_pairs[i].second)
840 const LinearExpressionProto before_end =
841 GetEnd(helper.ModelProto()
842 .constraints(start_interval_pairs[i].second)
844 const LinearExpressionProto after_start =
845 GetStart(helper.ModelProto()
846 .constraints(start_interval_pairs[i + 1].second)
851 LinearConstraintProto* linear =
852 neighborhood->delta.add_constraints()->mutable_linear();
854 int64_t rhs_offset = 0;
855 if (GetLinearExpressionValue(before_end, initial_solution) <=
856 GetLinearExpressionValue(after_start, initial_solution)) {
858 AddLinearExpressionToConstraint(1, before_end, linear, &rhs_offset);
862 rhs_offset = GetLinearExpressionValue(before_start, initial_solution) -
863 GetLinearExpressionValue(after_start, initial_solution);
864 AddLinearExpressionToConstraint(1, before_start, linear, &rhs_offset);
867 AddLinearExpressionToConstraint(-1, after_start, linear, &rhs_offset);
868 linear->add_domain(rhs_offset);
872 int64_t activity = 0;
873 for (
int i = 0; i < linear->vars().size(); ++i) {
875 linear->coeffs(i) * initial_solution.solution(linear->vars(i));
877 CHECK_GE(activity, linear->domain(0));
878 CHECK_LE(activity, linear->domain(1));
885 const absl::Span<const int> intervals_to_relax,
890 (intervals_to_relax.size() <
894 absl::flat_hash_set<int> ignored_intervals(intervals_to_relax.begin(),
895 intervals_to_relax.end());
900 if (ignored_intervals.contains(i))
continue;
907 const int enforcement_var =
PositiveRef(enforcement_ref);
908 const int value = initial_solution.
solution(enforcement_var);
916 ignored_intervals.insert(i);
927 AddPrecedenceConstraints(
929 ignored_intervals, initial_solution, helper, &neighborhood);
932 AddPrecedenceConstraints(
934 ignored_intervals, initial_solution, helper, &neighborhood);
937 AddPrecedenceConstraints(
939 ignored_intervals, initial_solution, helper, &neighborhood);
940 AddPrecedenceConstraints(
942 ignored_intervals, initial_solution, helper, &neighborhood);
954 absl::BitGenRef random) {
955 std::vector<int> intervals_to_relax =
957 GetRandomSubset(
difficulty, &intervals_to_relax, random);
965 absl::BitGenRef random) {
966 std::vector<std::pair<int64_t, int>> start_interval_pairs;
967 const std::vector<int> active_intervals =
969 std::vector<int> intervals_to_relax;
973 for (
const int i : active_intervals) {
976 const int64_t start_value =
977 GetLinearExpressionValue(start_var, initial_solution);
978 start_interval_pairs.push_back({start_value, i});
980 std::sort(start_interval_pairs.begin(), start_interval_pairs.end());
981 const int relaxed_size = std::floor(
difficulty * start_interval_pairs.size());
983 std::uniform_int_distribution<int> random_var(
984 0, start_interval_pairs.size() - relaxed_size - 1);
985 const int random_start_index = random_var(random);
989 for (
int i = random_start_index; i < relaxed_size; ++i) {
990 intervals_to_relax.push_back(start_interval_pairs[i].second);
999 absl::BitGenRef random) {
1000 const std::vector<std::vector<int>> all_paths =
1004 absl::flat_hash_set<int> all_path_variables;
1005 for (
auto& path : all_paths) {
1006 all_path_variables.insert(path.begin(), path.end());
1008 std::vector<int> fixed_variables(all_path_variables.begin(),
1009 all_path_variables.end());
1010 std::sort(fixed_variables.begin(), fixed_variables.end());
1011 GetRandomSubset(1.0 -
difficulty, &fixed_variables, random);
1013 initial_solution, {fixed_variables.begin(), fixed_variables.end()});
1018 absl::BitGenRef random) {
1019 std::vector<std::vector<int>> all_paths =
1023 absl::flat_hash_set<int> all_path_variables;
1024 for (
const auto& path : all_paths) {
1025 all_path_variables.insert(path.begin(), path.end());
1029 const int num_variables_to_relax =
1030 static_cast<int>(all_path_variables.size() *
difficulty);
1031 absl::flat_hash_set<int> relaxed_variables;
1032 while (relaxed_variables.size() < num_variables_to_relax) {
1033 DCHECK(!all_paths.empty());
1034 const int path_index = absl::Uniform<int>(random, 0, all_paths.size());
1035 std::vector<int>& path = all_paths[path_index];
1036 const int path_size = path.size();
1037 const int segment_length =
1038 std::min(path_size, absl::Uniform<int>(random, 4, 8));
1039 const int segment_start =
1040 absl::Uniform<int>(random, 0, path_size - segment_length);
1041 for (
int i = segment_start; i < segment_start + segment_length; ++i) {
1042 relaxed_variables.insert(path[i]);
1046 path.erase(path.begin() + segment_start,
1047 path.begin() + segment_start + segment_length);
1049 std::swap(all_paths[path_index], all_paths.back());
1050 all_paths.pop_back();
1055 absl::flat_hash_set<int> fixed_variables;
1056 for (
const int var : all_path_variables) {
1057 if (!relaxed_variables.contains(
var)) fixed_variables.insert(
var);
1064 absl::BitGenRef random) {
1065 std::vector<std::vector<int>> all_paths =
1068 if (all_paths.empty()) {
1073 absl::flat_hash_set<int> all_path_variables;
1074 for (
const auto& path : all_paths) {
1075 all_path_variables.insert(path.begin(), path.end());
1079 const int num_variables_to_relax =
1080 static_cast<int>(all_path_variables.size() *
difficulty);
1081 absl::flat_hash_set<int> relaxed_variables;
1084 for (
const auto& path : all_paths) {
1085 relaxed_variables.insert(path.front());
1086 relaxed_variables.insert(path.back());
1090 for (
auto& path : all_paths) {
1091 std::shuffle(path.begin(), path.end(), random);
1095 const int path_to_clean = absl::Uniform<int>(random, 0, all_paths.size());
1096 while (relaxed_variables.size() < num_variables_to_relax &&
1097 !all_paths[path_to_clean].empty()) {
1098 relaxed_variables.insert(all_paths[path_to_clean].back());
1099 all_paths[path_to_clean].pop_back();
1101 if (all_paths[path_to_clean].empty()) {
1102 std::swap(all_paths[path_to_clean], all_paths.back());
1103 all_paths.pop_back();
1107 while (relaxed_variables.size() < num_variables_to_relax) {
1108 DCHECK(!all_paths.empty());
1109 const int path_index = absl::Uniform<int>(random, 0, all_paths.size());
1110 relaxed_variables.insert(all_paths[path_index].back());
1113 all_paths[path_index].pop_back();
1114 if (all_paths[path_index].empty()) {
1115 std::swap(all_paths[path_index], all_paths.back());
1116 all_paths.pop_back();
1121 absl::flat_hash_set<int> fixed_variables;
1122 for (
const int var : all_path_variables) {
1123 if (!relaxed_variables.contains(
var)) fixed_variables.insert(
var);
1129 if (incomplete_solutions_ !=
nullptr) {
1133 if (response_manager_ !=
nullptr) {
1141 if (lp_solutions_ !=
nullptr && lp_solutions_->
NumSolutions() > 0) {
1145 if (relaxation_solutions_ !=
nullptr &&
1154 absl::BitGenRef random) {
1158 const bool lp_solution_available =
1159 (lp_solutions_ !=
nullptr && lp_solutions_->
NumSolutions() > 0);
1161 const bool relaxation_solution_available =
1162 (relaxation_solutions_ !=
nullptr &&
1165 const bool incomplete_solution_available =
1166 (incomplete_solutions_ !=
nullptr &&
1169 if (!lp_solution_available && !relaxation_solution_available &&
1170 !incomplete_solution_available) {
1171 return neighborhood;
1178 std::bernoulli_distribution random_bool(0.5);
1179 const bool use_lp_relaxation =
1180 (lp_solution_available && relaxation_solution_available)
1181 ? random_bool(random)
1182 : lp_solution_available;
1183 if (use_lp_relaxation) {
1186 nullptr, lp_solutions_,
1187 incomplete_solutions_, random);
1189 incomplete_solution_available ?
"incomplete" :
"lp";
1191 CHECK(relaxation_solution_available || incomplete_solution_available);
1193 response_manager_, relaxation_solutions_,
1194 nullptr, incomplete_solutions_, random);
1196 incomplete_solution_available ?
"incomplete" :
"relaxation";
1201 return neighborhood;
1206 for (
const std::pair</*model_var*/ int, /*value*/ int64_t> fixed_var :
1208 const int var = fixed_var.first;
1209 const int64_t
value = fixed_var.second;
1215 return neighborhood;
1224 for (
const std::pair<
int,
1225 std::pair<int64_t, int64_t>>
1227 const int var = reduced_var.first;
1228 const int64_t lb = reduced_var.second.first;
1229 const int64_t ub = reduced_var.second.second;
1236 return neighborhood;
1242 return neighborhood;
1247 absl::BitGenRef random) {
1248 std::vector<int> removable_constraints;
1250 removable_constraints.reserve(num_constraints);
1251 for (
int c = 0; c < num_constraints; ++c) {
1258 removable_constraints.push_back(c);
1261 const int target_size =
1262 std::round((1.0 -
difficulty) * removable_constraints.size());
1264 const int random_start_index =
1265 absl::Uniform<int>(random, 0, removable_constraints.size());
1266 std::vector<int> removed_constraints;
1267 removed_constraints.reserve(target_size);
1268 int c = random_start_index;
1269 while (removed_constraints.size() < target_size) {
1270 removed_constraints.push_back(removable_constraints[c]);
1272 if (c == removable_constraints.size()) {
1284 std::vector<int> removable_constraints;
1286 constraint_weights_.reserve(num_constraints);
1288 for (
int c = 0; c < num_constraints; ++c) {
1295 constraint_weights_.push_back(3.0);
1296 num_removable_constraints_++;
1310 constraint_weights_.push_back(2.0);
1311 num_removable_constraints_++;
1320 constraint_weights_.push_back(1.0);
1321 num_removable_constraints_++;
1328 constraint_weights_.push_back(0.0);
1334void WeightedRandomRelaxationNeighborhoodGenerator::
1335 AdditionalProcessingOnSynchronize(
const SolveData& solve_data) {
1336 const IntegerValue best_objective_improvement =
1337 solve_data.new_objective_bound - solve_data.initial_best_objective_bound;
1339 const std::vector<int>& removed_constraints =
1340 removed_constraints_[solve_data.neighborhood_id];
1354 if (best_objective_improvement > 0) {
1356 for (
int c : removed_constraints) {
1357 if (constraint_weights_[c] <= 90.0) {
1358 constraint_weights_[c] += 10.0;
1360 constraint_weights_[c] = 100.0;
1364 best_objective_improvement < 0) {
1366 for (
int c : removed_constraints) {
1367 if (constraint_weights_[c] > 0.5) {
1368 constraint_weights_[c] -= 0.5;
1372 removed_constraints_.erase(solve_data.neighborhood_id);
1377 absl::BitGenRef random) {
1378 const int target_size =
1379 std::round((1.0 -
difficulty) * num_removable_constraints_);
1381 std::vector<int> removed_constraints;
1386 std::vector<std::pair<double, int>> constraint_removal_scores;
1387 std::uniform_real_distribution<double> random_var(0.0, 1.0);
1388 for (
int c = 0; c < constraint_weights_.size(); ++c) {
1389 if (constraint_weights_[c] <= 0)
continue;
1390 const double u = random_var(random);
1391 const double score = std::pow(u, (1 / constraint_weights_[c]));
1392 constraint_removal_scores.push_back({score, c});
1394 std::sort(constraint_removal_scores.rbegin(),
1395 constraint_removal_scores.rend());
1396 for (
int i = 0; i < target_size; ++i) {
1397 removed_constraints.push_back(constraint_removal_scores[i].second);
1403 result.
id = next_available_id_;
1404 next_available_id_++;
1405 removed_constraints_.insert({result.
id, removed_constraints});
#define CHECK_LT(val1, val2)
#define CHECK_EQ(val1, val2)
#define CHECK_GE(val1, val2)
#define CHECK_GT(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK(condition)
#define CHECK_LE(val1, val2)
#define VLOG(verboselevel)
void Update(int num_decreases, int num_increases)
We call domain any subset of Int64 = [kint64min, kint64max].
bool IsFixed() const
Returns true iff the domain is reduced to a single value.
Domain IntersectionWith(const Domain &domain) const
Returns the intersection of D and domain.
bool IsEmpty() const
Returns true if this is the empty set.
Neighborhood Generate(const CpSolverResponse &initial_solution, double difficulty, absl::BitGenRef random) final
Neighborhood Generate(const CpSolverResponse &initial_solution, double difficulty, absl::BitGenRef random) final
const ::operations_research::sat::CircuitConstraintProto & circuit() const
const ::operations_research::sat::IntervalConstraintProto & interval() const
const ::operations_research::sat::NoOverlap2DConstraintProto & no_overlap_2d() const
ConstraintCase constraint_case() const
const ::operations_research::sat::CumulativeConstraintProto & cumulative() const
const ::operations_research::sat::RoutesConstraintProto & routes() const
::PROTOBUF_NAMESPACE_ID::int32 enforcement_literal(int index) const
const ::operations_research::sat::NoOverlapConstraintProto & no_overlap() const
const ::operations_research::sat::IntegerVariableProto & variables(int index) const
const ::operations_research::sat::DecisionStrategyProto & search_strategy(int index) const
::operations_research::sat::IntegerVariableProto * mutable_variables(int index)
int variables_size() const
::operations_research::sat::IntegerVariableProto * add_variables()
int constraints_size() const
const ::operations_research::sat::ConstraintProto & constraints(int index) const
::PROTOBUF_NAMESPACE_ID::int64 solution(int index) const
::PROTOBUF_NAMESPACE_ID::int32 intervals(int index) const
void add_domain(::PROTOBUF_NAMESPACE_ID::int64 value)
const std::string & name() const
void set_name(ArgT0 &&arg0, ArgT... args)
PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final
::PROTOBUF_NAMESPACE_ID::int64 domain(int index) const
::PROTOBUF_NAMESPACE_ID::RepeatedField< ::PROTOBUF_NAMESPACE_ID::int64 > * mutable_domain()
::PROTOBUF_NAMESPACE_ID::int32 end() const
const ::operations_research::sat::LinearExpressionProto & size_view() const
bool has_start_view() const
::PROTOBUF_NAMESPACE_ID::int32 size() const
const ::operations_research::sat::LinearExpressionProto & start_view() const
::PROTOBUF_NAMESPACE_ID::int32 start() const
const ::operations_research::sat::LinearExpressionProto & end_view() const
void add_coeffs(::PROTOBUF_NAMESPACE_ID::int64 value)
::PROTOBUF_NAMESPACE_ID::int32 vars(int index) const
void add_vars(::PROTOBUF_NAMESPACE_ID::int32 value)
NeighborhoodGeneratorHelper(CpModelProto const *model_proto, SatParameters const *parameters, SharedResponseManager *shared_response, SharedTimeLimit *shared_time_limit=nullptr, SharedBoundsManager *shared_bounds=nullptr)
Neighborhood FullNeighborhood() const
Neighborhood FixAllVariables(const CpSolverResponse &initial_solution) const
const CpModelProto & ModelProto() const
const absl::Span< const int > TypeToConstraints(ConstraintProto::ConstraintCase type) const
Neighborhood FixGivenVariables(const CpSolverResponse &initial_solution, const absl::flat_hash_set< int > &variables_to_fix) const
bool CopyAndFixVariables(const CpModelProto &source_model, const absl::flat_hash_set< int > &fixed_variables_set, const CpSolverResponse &initial_solution, CpModelProto *output_model) const
bool DifficultyMeansFullNeighborhood(double difficulty) const
Neighborhood NoNeighborhood() const
Neighborhood RelaxGivenVariables(const CpSolverResponse &initial_solution, const std::vector< int > &relaxed_variables) const
std::vector< int > GetActiveIntervals(const CpSolverResponse &initial_solution) const
const SharedResponseManager & shared_response() const
std::vector< int > ActiveVariables() const
const std::vector< std::vector< int > > & VarToConstraint() const ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_)
bool IsActive(int var) const ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_)
const std::vector< int > & ActiveVariablesWhileHoldingLock() const ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_)
Neighborhood RemoveMarkedConstraints(const std::vector< int > &constraints_to_remove) const
void AddSolutionHinting(const CpSolverResponse &initial_solution, CpModelProto *model_proto) const
const std::vector< std::vector< int > > & ConstraintToVar() const ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_)
void Synchronize() override
std::vector< std::vector< int > > GetRoutingPaths(const CpSolverResponse &initial_solution) const
virtual bool IsRelaxationGenerator() const
absl::Mutex generator_mutex_
virtual bool ReadyToGenerate() const
double difficulty() const
double GetUCBScore(int64_t total_num_calls) const
virtual void AdditionalProcessingOnSynchronize(const SolveData &solve_data)
const NeighborhoodGeneratorHelper & helper_
::PROTOBUF_NAMESPACE_ID::int32 y_intervals(int index) const
::PROTOBUF_NAMESPACE_ID::int32 x_intervals(int index) const
::PROTOBUF_NAMESPACE_ID::int32 intervals(int index) const
Neighborhood Generate(const CpSolverResponse &initial_solution, double difficulty, absl::BitGenRef random) final
Neighborhood Generate(const CpSolverResponse &initial_solution, double difficulty, absl::BitGenRef random) final
bool ReadyToGenerate() const override
Neighborhood Generate(const CpSolverResponse &initial_solution, double difficulty, absl::BitGenRef random) final
Neighborhood Generate(const CpSolverResponse &initial_solution, double difficulty, absl::BitGenRef random) final
Neighborhood Generate(const CpSolverResponse &initial_solution, double difficulty, absl::BitGenRef random) final
Neighborhood Generate(const CpSolverResponse &initial_solution, double difficulty, absl::BitGenRef random) final
bool lns_focus_on_decision_variables() const
bool lns_expand_intervals_in_constraint_graph() const
Neighborhood Generate(const CpSolverResponse &initial_solution, double difficulty, absl::BitGenRef random) final
Neighborhood Generate(const CpSolverResponse &initial_solution, double difficulty, absl::BitGenRef random) final
void GetChangedBounds(int id, std::vector< int > *variables, std::vector< int64_t > *new_lower_bounds, std::vector< int64_t > *new_upper_bounds)
bool HasNewSolution() const
const SharedSolutionRepository< int64_t > & SolutionsRepository() const
Neighborhood Generate(const CpSolverResponse &initial_solution, double difficulty, absl::BitGenRef random) final
WeightedRandomRelaxationNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, const std::string &name)
Neighborhood Generate(const CpSolverResponse &initial_solution, double difficulty, absl::BitGenRef random) final
CpModelProto const * model_proto
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
std::vector< int > UsedVariables(const ConstraintProto &ct)
bool RefIsPositive(int ref)
std::vector< int > UsedIntervals(const ConstraintProto &ct)
bool DomainInProtoContains(const ProtoWithDomain &proto, int64_t value)
void FillDomainInProto(const Domain &domain, ProtoWithDomain *proto)
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
Neighborhood GenerateSchedulingNeighborhoodForRelaxation(const absl::Span< const int > intervals_to_relax, const CpSolverResponse &initial_solution, const NeighborhoodGeneratorHelper &helper)
RINSNeighborhood GetRINSNeighborhood(const SharedResponseManager *response_manager, const SharedRelaxationSolutionRepository *relaxation_solutions, const SharedLPSolutionRepository *lp_solutions, SharedIncompleteSolutionManager *incomplete_solutions, absl::BitGenRef random)
Collection of objects used to extend the Constraint Solver library.
int64_t CapSub(int64_t x, int64_t y)
std::vector< int > constraints_to_ignore
std::vector< std::pair< int, int64_t > > fixed_vars
std::vector< std::pair< int, std::pair< int64_t, int64_t > > > reduced_domain_vars
#define VLOG_IS_ON(verboselevel)