28 #include "absl/container/flat_hash_map.h"
29 #include "absl/container/flat_hash_set.h"
30 #include "absl/log/check.h"
31 #include "absl/meta/type_traits.h"
32 #include "absl/random/bit_gen_ref.h"
33 #include "absl/random/distributions.h"
34 #include "absl/strings/str_cat.h"
35 #include "absl/strings/str_join.h"
36 #include "absl/synchronization/mutex.h"
37 #include "absl/time/clock.h"
38 #include "absl/time/time.h"
39 #include "absl/types/span.h"
43 #include "ortools/sat/cp_model.pb.h"
50 #include "ortools/sat/sat_parameters.pb.h"
65 :
SubSolver(
"neighborhood_helper", HELPER),
68 shared_bounds_(shared_bounds),
69 shared_response_(shared_response) {
70 CHECK(shared_response_ !=
nullptr);
71 if (shared_bounds_ !=
nullptr) {
74 *model_proto_with_only_variables_.mutable_variables() =
75 model_proto_.variables();
76 InitializeHelperData();
77 RecomputeHelperData();
79 last_logging_time_ = absl::Now();
83 if (shared_bounds_ !=
nullptr) {
84 std::vector<int> model_variables;
85 std::vector<int64_t> new_lower_bounds;
86 std::vector<int64_t> new_upper_bounds;
88 &new_lower_bounds, &new_upper_bounds);
90 bool new_variables_have_been_fixed =
false;
93 absl::MutexLock domain_lock(&domain_mutex_);
95 for (
int i = 0; i < model_variables.size(); ++i) {
96 const int var = model_variables[i];
97 const int64_t new_lb = new_lower_bounds[i];
98 const int64_t new_ub = new_upper_bounds[i];
101 model_proto_with_only_variables_.variables(
var).domain();
102 const int64_t old_lb = domain.Get(0);
103 const int64_t old_ub = domain.Get(domain.size() - 1);
104 VLOG(3) <<
"Variable: " <<
var <<
" old domain: [" << old_lb <<
", "
105 << old_ub <<
"] new domain: [" << new_lb <<
", " << new_ub
109 model_proto_with_only_variables_.variables(
var));
130 model_proto_with_only_variables_.mutable_variables(
var));
131 new_variables_have_been_fixed |= new_domain.
IsFixed();
136 if (new_variables_have_been_fixed) {
137 RecomputeHelperData();
142 bool NeighborhoodGeneratorHelper::ObjectiveDomainIsConstraining()
const {
143 if (!model_proto_.has_objective())
return false;
144 if (model_proto_.objective().domain().empty())
return false;
146 int64_t min_activity = 0;
147 int64_t max_activity = 0;
148 const int num_terms = model_proto_.objective().vars().size();
149 for (
int i = 0; i < num_terms; ++i) {
151 const int64_t coeff = model_proto_.objective().coeffs(i);
152 const auto& var_domain =
153 model_proto_with_only_variables_.variables(
var).domain();
154 const int64_t v1 = coeff * var_domain[0];
155 const int64_t v2 = coeff * var_domain[var_domain.size() - 1];
161 const Domain inferred_domain =
162 Domain(min_activity, max_activity)
168 void NeighborhoodGeneratorHelper::InitializeHelperData() {
169 type_to_constraints_.clear();
170 const int num_constraints = model_proto_.constraints_size();
171 for (
int c = 0; c < num_constraints; ++c) {
172 const int type = model_proto_.constraints(c).constraint_case();
173 if (
type >= type_to_constraints_.size()) {
174 type_to_constraints_.resize(
type + 1);
176 type_to_constraints_[
type].push_back(c);
179 const int num_variables = model_proto_.variables().size();
180 is_in_objective_.resize(num_variables,
false);
181 if (model_proto_.has_objective()) {
182 for (
const int ref : model_proto_.objective().vars()) {
190 void NeighborhoodGeneratorHelper::RecomputeHelperData() {
192 absl::ReaderMutexLock domain_lock(&domain_mutex_);
206 CpModelProto mapping_proto;
207 simplied_model_proto_.Clear();
208 *simplied_model_proto_.mutable_variables() =
209 model_proto_with_only_variables_.variables();
210 PresolveContext
context(&local_model, &simplied_model_proto_,
216 copier.ImportAndSimplifyConstraints(model_proto_, {});
222 const auto& constraints = simplied_model_proto_.constraints();
223 var_to_constraint_.assign(model_proto_.variables_size(), {});
224 constraint_to_var_.assign(constraints.size(), {});
225 int reduced_ct_index = 0;
226 for (
int ct_index = 0; ct_index < constraints.size(); ++ct_index) {
232 if (constraints[ct_index].constraint_case() == ConstraintProto::kInterval) {
237 if (IsConstant(
var))
continue;
238 constraint_to_var_[reduced_ct_index].push_back(
var);
245 if (IsConstant(
var))
continue;
246 constraint_to_var_[reduced_ct_index].push_back(
var);
252 if (constraint_to_var_[reduced_ct_index].size() <= 1) {
253 constraint_to_var_[reduced_ct_index].clear();
258 for (
const int var : constraint_to_var_[reduced_ct_index]) {
259 var_to_constraint_[
var].push_back(reduced_ct_index);
263 constraint_to_var_.resize(reduced_ct_index);
267 active_variables_.clear();
268 const int num_variables = model_proto_.variables_size();
269 active_variables_set_.assign(num_variables,
false);
270 for (
int i = 0; i < num_variables; ++i) {
271 if (!IsConstant(i)) {
272 active_variables_.push_back(i);
273 active_variables_set_[i] =
true;
277 active_objective_variables_.clear();
278 for (
const int var : model_proto_.objective().vars()) {
280 if (active_variables_set_[
var]) {
281 active_objective_variables_.push_back(
var);
289 for (
const std::vector<int>& var_in_constraint : constraint_to_var_) {
290 if (var_in_constraint.size() <= 1)
continue;
291 for (
int i = 1; i < var_in_constraint.size(); ++i) {
292 union_find.
AddEdge(var_in_constraint[0], var_in_constraint[i]);
298 if (ObjectiveDomainIsConstraining()) {
299 const auto& refs = model_proto_.objective().vars();
300 const int num_terms = refs.size();
301 for (
int i = 1; i < num_terms; ++i) {
312 var_to_component_index_.assign(num_variables, -1);
313 for (
int var = 0;
var < num_variables; ++
var) {
314 if (IsConstant(
var))
continue;
316 DCHECK_LT(root, var_to_component_index_.size());
317 int&
index = var_to_component_index_[root];
319 index = components_.size();
320 components_.push_back({});
322 var_to_component_index_[
var] =
index;
332 std::vector<int> component_sizes;
333 for (
const std::vector<int>& component : components_) {
334 component_sizes.push_back(component.size());
336 std::sort(component_sizes.begin(), component_sizes.end(),
337 std::greater<int>());
338 std::string compo_message;
339 if (component_sizes.size() > 1) {
340 if (component_sizes.size() <= 10) {
342 absl::StrCat(
" compo:", absl::StrJoin(component_sizes,
","));
344 component_sizes.resize(10);
346 absl::StrCat(
" compo:", absl::StrJoin(component_sizes,
","),
",...");
355 absl::StrCat(
"var:", active_variables_.size(),
"/", num_variables,
356 " constraints:", simplied_model_proto_.constraints().size(),
357 "/", model_proto_.constraints().size(), compo_message),
358 parameters_.model_reduction_log_frequency_in_seconds(),
359 &last_logging_time_);
363 return active_variables_set_[
var];
366 bool NeighborhoodGeneratorHelper::IsConstant(
int var)
const {
367 return model_proto_with_only_variables_.variables(
var).domain_size() == 2 &&
368 model_proto_with_only_variables_.variables(
var).domain(0) ==
369 model_proto_with_only_variables_.variables(
var).domain(1);
377 absl::ReaderMutexLock lock(&domain_mutex_);
378 *neighborhood.
delta.mutable_variables() =
379 model_proto_with_only_variables_.variables();
391 const CpSolverResponse& initial_solution)
const {
392 std::vector<int> active_intervals;
393 absl::ReaderMutexLock lock(&domain_mutex_);
395 const ConstraintProto& interval_ct =
ModelProto().constraints(i);
399 if (interval_ct.enforcement_literal().size() == 1) {
400 const int enforcement_ref = interval_ct.enforcement_literal(0);
401 const int enforcement_var =
PositiveRef(enforcement_ref);
402 const int value = initial_solution.solution(enforcement_var);
410 if (interval_ct.enforcement_literal().empty()) {
411 bool is_constant =
true;
412 for (
const int v : interval_ct.interval().start().vars()) {
413 if (!IsConstant(v)) {
418 for (
const int v : interval_ct.interval().size().vars()) {
419 if (!IsConstant(v)) {
424 for (
const int v : interval_ct.interval().end().vars()) {
425 if (!IsConstant(v)) {
430 if (is_constant)
continue;
433 active_intervals.push_back(i);
435 return active_intervals;
438 std::vector<std::vector<int>>
440 std::vector<std::vector<int>> intervals_in_constraints;
441 absl::flat_hash_set<std::vector<int>> added_intervals_sets;
442 const auto add_interval_list_only_once =
443 [&intervals_in_constraints,
444 &added_intervals_sets](
const auto& intervals) {
445 std::vector<int> candidate({intervals.begin(), intervals.end()});
447 if (added_intervals_sets.insert(candidate).second) {
448 intervals_in_constraints.push_back(candidate);
452 add_interval_list_only_once(
453 model_proto_.constraints(ct_index).no_overlap().intervals());
456 add_interval_list_only_once(
457 model_proto_.constraints(ct_index).cumulative().intervals());
460 add_interval_list_only_once(
461 model_proto_.constraints(ct_index).no_overlap_2d().x_intervals());
462 add_interval_list_only_once(
463 model_proto_.constraints(ct_index).no_overlap_2d().y_intervals());
465 return intervals_in_constraints;
470 int64_t GetLinearExpressionValue(
const LinearExpressionProto& expr,
471 const CpSolverResponse& initial_solution) {
472 int64_t result = expr.offset();
473 for (
int i = 0; i < expr.vars_size(); ++i) {
474 result += expr.coeffs(i) * initial_solution.solution(expr.vars(i));
479 struct StartEndInterval {
483 bool operator<(
const StartEndInterval& o)
const {
485 std::tie(o.start, o.end, o.interval_index);
491 std::vector<int> SelectIntervalsInRandomTimeWindow(
492 const std::vector<int>& intervals,
const CpModelProto&
model_proto,
493 const CpSolverResponse& initial_solution,
double difficulty,
494 absl::BitGenRef random) {
495 std::vector<StartEndInterval> start_end_intervals;
496 for (
const int i : intervals) {
497 const ConstraintProto& interval_ct =
model_proto.constraints(i);
501 if (interval_ct.enforcement_literal().size() == 1) {
502 const int enforcement_ref = interval_ct.enforcement_literal(0);
503 const int enforcement_var =
PositiveRef(enforcement_ref);
504 const int64_t
value = initial_solution.solution(enforcement_var);
509 const int64_t start_value = GetLinearExpressionValue(
510 interval_ct.interval().start(), initial_solution);
511 const int64_t end_value = GetLinearExpressionValue(
512 interval_ct.interval().end(), initial_solution);
513 start_end_intervals.push_back({start_value, end_value, i});
516 if (start_end_intervals.empty())
return {};
518 std::sort(start_end_intervals.begin(), start_end_intervals.end());
519 const int relaxed_size = std::floor(difficulty * start_end_intervals.size());
521 std::uniform_int_distribution<int> random_var(
522 0, start_end_intervals.size() - relaxed_size - 1);
525 const int random_start_index = random_var(random);
532 std::sort(start_end_intervals.begin() + random_start_index,
533 start_end_intervals.end(),
534 [](
const StartEndInterval&
a,
const StartEndInterval&
b) {
535 return std::tie(a.end, a.interval_index) <
536 std::tie(b.end, b.interval_index);
538 std::vector<int> result;
539 for (
int i = random_start_index; i < random_start_index + relaxed_size; ++i) {
555 bool operator<(
const Demand& other)
const {
557 std::tie(other.start, other.height, other.end);
560 std::string DebugString()
const {
566 void InsertPrecedencesFromSortedListOfNonOverlapingIntervals(
567 const std::vector<Demand>& demands,
568 absl::flat_hash_set<std::pair<int, int>>* precedences) {
569 for (
int i = 0; i + 1 < demands.size(); ++i) {
570 DCHECK_LE(demands[i].
end, demands[i + 1].
start);
572 {demands[i].interval_index, demands[i + 1].interval_index});
576 bool IsPresent(
const ConstraintProto& interval_ct,
577 const CpSolverResponse& initial_solution) {
578 if (interval_ct.enforcement_literal().size() != 1)
return true;
580 const int enforcement_ref = interval_ct.enforcement_literal(0);
581 const int enforcement_var =
PositiveRef(enforcement_ref);
582 const int64_t
value = initial_solution.solution(enforcement_var);
586 void InsertNoOverlapPrecedences(
587 const absl::flat_hash_set<int>& ignored_intervals,
588 const CpSolverResponse& initial_solution,
const CpModelProto&
model_proto,
589 int no_overlap_index,
590 absl::flat_hash_set<std::pair<int, int>>* precedences) {
591 std::vector<Demand> demands;
592 const NoOverlapConstraintProto& no_overlap =
593 model_proto.constraints(no_overlap_index).no_overlap();
596 const ConstraintProto& interval_ct =
598 if (!IsPresent(interval_ct, initial_solution))
continue;
600 const int64_t start_value = GetLinearExpressionValue(
601 interval_ct.interval().start(), initial_solution);
602 const int64_t end_value = GetLinearExpressionValue(
603 interval_ct.interval().end(), initial_solution);
604 DCHECK_LE(start_value, end_value);
610 std::sort(demands.begin(), demands.end());
611 InsertPrecedencesFromSortedListOfNonOverlapingIntervals(demands, precedences);
614 void ProcessDemandListFromCumulativeConstraint(
615 const std::vector<Demand>& demands, int64_t
capacity,
616 std::deque<std::pair<std::vector<Demand>, int64_t>>* to_process,
617 absl::BitGenRef random,
618 absl::flat_hash_set<std::pair<int, int>>* precedences) {
619 if (demands.size() <= 1)
return;
622 int64_t sum_of_min_two_capacities = 2;
626 for (
const Demand&
demand : demands) {
627 if (
demand.height <= min1) {
630 }
else if (
demand.height < min2) {
634 sum_of_min_two_capacities = min1 + min2;
637 DCHECK_GT(sum_of_min_two_capacities, 1);
638 if (sum_of_min_two_capacities >
capacity) {
639 InsertPrecedencesFromSortedListOfNonOverlapingIntervals(demands,
644 std::vector<int64_t> unique_starts;
645 for (
const Demand&
demand : demands) {
646 DCHECK(unique_starts.empty() ||
demand.start >= unique_starts.back());
647 if (unique_starts.empty() || unique_starts.back() <
demand.start) {
648 unique_starts.push_back(
demand.start);
651 DCHECK(std::is_sorted(unique_starts.begin(), unique_starts.end()));
652 const int num_points = unique_starts.size();
655 const int64_t capacity1 =
capacity / 2;
656 std::vector<int64_t> usage1(num_points);
657 std::vector<Demand> demands1;
659 const int64_t capacity2 =
capacity - capacity1;
660 std::vector<int64_t> usage2(num_points);
661 std::vector<Demand> demands2;
664 for (
const Demand& d : demands) {
667 while (usage_index < num_points && unique_starts[usage_index] < d.start) {
670 DCHECK_LT(usage_index, num_points);
671 DCHECK_EQ(unique_starts[usage_index], d.start);
672 const int64_t slack1 = capacity1 - usage1[usage_index];
673 const int64_t slack2 = capacity2 - usage2[usage_index];
680 ? absl::Bernoulli(random, 0.5)
681 : (d.
height <= std::
min(slack1, slack2) ? slack2 < slack1
684 auto& selected_usage = prefer2 ? usage2 : usage1;
685 auto& residual_usage = prefer2 ? usage1 : usage2;
686 std::vector<Demand>& selected_demands = prefer2 ? demands2 : demands1;
687 std::vector<Demand>& residual_demands = prefer2 ? demands1 : demands2;
688 const int64_t selected_slack = prefer2 ? slack2 : slack1;
690 const int64_t assigned_to_selected =
std::min(selected_slack, d.height);
691 DCHECK_GT(assigned_to_selected, 0);
692 for (
int i = usage_index; i < num_points; ++i) {
693 if (d.end <= unique_starts[i])
break;
694 selected_usage[i] += assigned_to_selected;
696 selected_demands.push_back(
697 {d.interval_index, d.start, d.end, assigned_to_selected});
699 if (d.height > selected_slack) {
700 const int64_t residual = d.height - selected_slack;
701 DCHECK_GT(residual, 0);
702 DCHECK_LE(residual, prefer2 ? slack1 : slack2);
703 for (
int i = usage_index; i < num_points; ++i) {
704 if (d.end <= unique_starts[i])
break;
705 residual_usage[i] += residual;
707 residual_demands.push_back({d.interval_index, d.start, d.end, residual});
711 if (demands1.size() > 1) {
712 to_process->emplace_back(std::move(demands1), capacity1);
714 if (demands2.size() > 1) {
715 to_process->emplace_back(std::move(demands2), capacity2);
719 void InsertCumulativePrecedences(
720 const absl::flat_hash_set<int>& ignored_intervals,
721 const CpSolverResponse& initial_solution,
const CpModelProto&
model_proto,
722 int cumulative_index, absl::BitGenRef random,
723 absl::flat_hash_set<std::pair<int, int>>* precedences) {
724 const CumulativeConstraintProto& cumulative =
725 model_proto.constraints(cumulative_index).cumulative();
727 std::vector<Demand> demands;
728 for (
int i = 0; i < cumulative.intervals().size(); ++i) {
731 const ConstraintProto& interval_ct =
733 if (!IsPresent(interval_ct, initial_solution))
continue;
735 const int64_t start_value = GetLinearExpressionValue(
736 interval_ct.interval().start(), initial_solution);
737 const int64_t end_value = GetLinearExpressionValue(
738 interval_ct.interval().end(), initial_solution);
739 const int64_t demand_value =
740 GetLinearExpressionValue(cumulative.demands(i), initial_solution);
741 if (start_value == end_value || demand_value == 0)
continue;
743 demands.push_back({
interval_index, start_value, end_value, demand_value});
745 std::sort(demands.begin(), demands.end());
747 const int64_t capacity_value =
748 GetLinearExpressionValue(cumulative.capacity(), initial_solution);
749 DCHECK_GT(capacity_value, 0);
752 std::deque<std::pair<std::vector<Demand>, int64_t>> to_process;
753 to_process.emplace_back(std::move(demands), capacity_value);
755 while (!to_process.empty()) {
756 auto& next_task = to_process.front();
757 ProcessDemandListFromCumulativeConstraint(next_task.first,
759 &to_process, random, precedences);
760 to_process.pop_front();
771 bool operator<(
const Rectangle& other)
const {
772 return std::tie(
x_start,
x_end) < std::tie(other.x_start, other.x_end);
776 void InsertRectanglePredecences(
777 const std::vector<Rectangle>& rectangles,
778 absl::flat_hash_set<std::pair<int, int>>* precedences) {
780 std::vector<int64_t> interesting_points;
781 for (
const Rectangle& r : rectangles) {
782 interesting_points.push_back(r.y_end - 1);
785 std::vector<Demand> demands;
786 for (
const int64_t t : interesting_points) {
788 for (
const Rectangle& r : rectangles) {
789 if (r.y_start > t || r.y_end <= t)
continue;
790 demands.push_back({r.interval_index, r.x_start, r.x_end, 1});
792 std::sort(demands.begin(), demands.end());
793 InsertPrecedencesFromSortedListOfNonOverlapingIntervals(demands,
798 void InsertNoOverlap2dPrecedences(
799 const absl::flat_hash_set<int>& ignored_intervals,
800 const CpSolverResponse& initial_solution,
const CpModelProto&
model_proto,
801 int no_overlap_2d_index,
802 absl::flat_hash_set<std::pair<int, int>>* precedences) {
803 std::vector<Demand> demands;
804 const NoOverlap2DConstraintProto& no_overlap_2d =
805 model_proto.constraints(no_overlap_2d_index).no_overlap_2d();
806 std::vector<Rectangle> x_main;
807 std::vector<Rectangle> y_main;
808 for (
int i = 0; i < no_overlap_2d.x_intervals_size(); ++i) {
810 const int x_interval_index = no_overlap_2d.x_intervals(i);
811 if (ignored_intervals.contains(x_interval_index))
continue;
812 const ConstraintProto& x_interval_ct =
814 if (!IsPresent(x_interval_ct, initial_solution))
continue;
816 const int y_interval_index = no_overlap_2d.y_intervals(i);
817 if (ignored_intervals.contains(y_interval_index))
continue;
818 const ConstraintProto& y_interval_ct =
820 if (!IsPresent(y_interval_ct, initial_solution))
continue;
822 const int64_t x_start_value = GetLinearExpressionValue(
823 x_interval_ct.interval().start(), initial_solution);
824 const int64_t x_end_value = GetLinearExpressionValue(
825 x_interval_ct.interval().end(), initial_solution);
826 const int64_t y_start_value = GetLinearExpressionValue(
827 y_interval_ct.interval().start(), initial_solution);
828 const int64_t y_end_value = GetLinearExpressionValue(
829 y_interval_ct.interval().end(), initial_solution);
832 if (x_start_value == x_end_value || y_start_value == y_end_value)
continue;
834 x_main.push_back({x_interval_index, x_start_value, x_end_value,
835 y_start_value, y_end_value});
836 y_main.push_back({y_interval_index, y_start_value, y_end_value,
837 x_start_value, x_end_value});
840 if (x_main.empty() || y_main.empty())
return;
842 std::sort(x_main.begin(), x_main.end());
843 InsertRectanglePredecences(x_main, precedences);
844 std::sort(y_main.begin(), y_main.end());
845 InsertRectanglePredecences(y_main, precedences);
853 std::vector<std::pair<int, int>>
855 const absl::flat_hash_set<int>& ignored_intervals,
856 const CpSolverResponse& initial_solution, absl::BitGenRef random)
const {
857 absl::flat_hash_set<std::pair<int, int>> precedences;
859 InsertNoOverlapPrecedences(ignored_intervals, initial_solution,
863 InsertCumulativePrecedences(ignored_intervals, initial_solution,
867 InsertNoOverlap2dPrecedences(ignored_intervals, initial_solution,
872 std::vector<std::pair<int, int>> result(precedences.begin(),
874 std::sort(result.begin(), result.end());
879 const CpSolverResponse& initial_solution)
const {
880 struct HeadAndArcLiteral {
885 std::vector<std::vector<int>> result;
886 absl::flat_hash_map<int, HeadAndArcLiteral> tail_to_head_and_arc_literal;
889 const CircuitConstraintProto&
ct =
ModelProto().constraints(i).circuit();
893 tail_to_head_and_arc_literal.clear();
894 for (
int i = 0; i <
ct.literals_size(); ++i) {
896 const int head =
ct.heads(i);
897 const int tail =
ct.tails(i);
899 const int64_t
value = initial_solution.solution(bool_var);
904 tail_to_head_and_arc_literal[
tail] = {
head, bool_var};
907 if (tail_to_head_and_arc_literal.empty())
continue;
910 int current_node = min_node;
911 std::vector<int> path;
913 auto it = tail_to_head_and_arc_literal.find(current_node);
914 CHECK(it != tail_to_head_and_arc_literal.end());
915 current_node = it->second.head;
916 path.push_back(it->second.literal);
917 }
while (current_node != min_node);
918 result.push_back(std::move(path));
921 std::vector<HeadAndArcLiteral> route_starts;
923 const RoutesConstraintProto&
ct =
ModelProto().constraints(i).routes();
924 tail_to_head_and_arc_literal.clear();
925 route_starts.clear();
928 for (
int i = 0; i <
ct.literals_size(); ++i) {
930 const int head =
ct.heads(i);
931 const int tail =
ct.tails(i);
933 const int64_t
value = initial_solution.solution(bool_var);
939 route_starts.push_back({
head, bool_var});
941 tail_to_head_and_arc_literal[
tail] = {
head, bool_var};
946 for (
const HeadAndArcLiteral& head_var : route_starts) {
947 std::vector<int> path;
948 int current_node = head_var.head;
949 path.push_back(head_var.literal);
951 auto it = tail_to_head_and_arc_literal.find(current_node);
952 CHECK(it != tail_to_head_and_arc_literal.end());
953 current_node = it->second.head;
954 path.push_back(it->second.literal);
955 }
while (current_node != 0);
956 result.push_back(std::move(path));
964 const CpSolverResponse& base_solution,
965 const absl::flat_hash_set<int>& variables_to_fix)
const {
970 absl::ReaderMutexLock domain_lock(&domain_mutex_);
972 const int num_variables =
973 model_proto_with_only_variables_.variables().size();
974 neighborhood.
delta.mutable_variables()->Reserve(num_variables);
975 for (
int i = 0; i < num_variables; ++i) {
976 const IntegerVariableProto& current_var =
977 model_proto_with_only_variables_.variables(i);
978 IntegerVariableProto* new_var = neighborhood.
delta.add_variables();
981 if (
DEBUG_MODE) new_var->set_name(current_var.name());
984 const int64_t base_value = base_solution.solution(i);
986 if (variables_to_fix.contains(i)) {
988 new_var->add_domain(base_value);
989 new_var->add_domain(base_value);
994 int64_t closest_value = domain.
Min();
995 int64_t closest_dist = std::abs(closest_value - base_value);
998 const int64_t dist = std::abs(
value - base_value);
999 if (dist < closest_dist) {
1000 closest_value =
value;
1001 closest_dist = dist;
1018 std::vector<int> count(components_.size(), 0);
1019 const int num_variables = neighborhood.
delta.variables().size();
1020 for (
int var = 0;
var < num_variables; ++
var) {
1021 const auto& domain = neighborhood.
delta.variables(
var).domain();
1022 if (domain.size() != 2 || domain[0] != domain[1]) {
1024 if (is_in_objective_[
var]) {
1027 const int c = var_to_component_index_[
var];
1028 if (c != -1) count[c]++;
1032 for (
int i = 0; i < components_.size(); ++i) {
1033 if (count[i] == components_[i].size()) {
1036 components_[i].begin(), components_[i].end());
1046 if (model_proto_.has_objective() &&
1047 (model_proto_.objective().domain().size() != 2 ||
1049 model_proto_.objective().domain(0))) {
1056 neighborhood.
is_reduced = !variables_to_fix.empty();
1063 return neighborhood;
1067 const CpSolverResponse& initial_solution, CpModelProto*
model_proto)
const {
1071 const IntegerVariableProto& var_proto =
model_proto->variables(
var);
1072 return var_proto.domain_size() == 2 &&
1073 var_proto.domain(0) == var_proto.domain(1);
1076 if (is_fixed(
var))
continue;
1080 initial_solution.solution(
var));
1085 const std::vector<int>& constraints_to_remove)
const {
1088 if (constraints_to_remove.empty())
return neighborhood;
1091 return neighborhood;
1095 const CpSolverResponse& initial_solution,
1096 const std::vector<int>& relaxed_variables)
const {
1097 std::vector<bool> relaxed_variables_set(model_proto_.variables_size(),
false);
1098 for (
const int var : relaxed_variables) relaxed_variables_set[
var] =
true;
1099 absl::flat_hash_set<int> fixed_variables;
1102 for (
const int i : active_variables_) {
1103 if (!relaxed_variables_set[i]) {
1104 fixed_variables.insert(i);
1112 const CpSolverResponse& initial_solution)
const {
1114 const absl::flat_hash_set<int> fixed_variables(all_variables.begin(),
1115 all_variables.end());
1125 DCHECK_GE(total_num_calls, num_calls_);
1126 if (num_calls_ <= 10)
return std::numeric_limits<double>::infinity();
1127 return current_average_ + sqrt((2 * log(total_num_calls)) / num_calls_);
1135 std::sort(solve_data_.begin(), solve_data_.end());
1138 int num_fully_solved_in_batch = 0;
1139 int num_not_fully_solved_in_batch = 0;
1141 for (
const SolveData& data : solve_data_) {
1149 ++num_fully_solved_calls_;
1150 ++num_fully_solved_in_batch;
1152 ++num_not_fully_solved_in_batch;
1161 const IntegerValue best_objective_improvement = IntegerValue(
CapSub(
1162 data.initial_best_objective.value(), data.new_objective.value()));
1163 if (best_objective_improvement > 0) {
1164 num_consecutive_non_improving_calls_ = 0;
1166 ++num_consecutive_non_improving_calls_;
1171 const double gain_per_time_unit =
1172 std::max(0.0,
static_cast<double>(best_objective_improvement.value())) /
1173 (1.0 + data.deterministic_time);
1174 if (num_calls_ <= 100) {
1175 current_average_ += (gain_per_time_unit - current_average_) / num_calls_;
1177 current_average_ = 0.9 * current_average_ + 0.1 * gain_per_time_unit;
1180 deterministic_time_ += data.deterministic_time;
1184 difficulty_.
Update(num_not_fully_solved_in_batch,
1185 num_fully_solved_in_batch);
1193 if (num_consecutive_non_improving_calls_ > 50) {
1194 num_consecutive_non_improving_calls_ = 0;
1195 deterministic_limit_ *= 1.02;
1199 deterministic_limit_ =
std::min(60.0, deterministic_limit_);
1202 solve_data_.clear();
1208 void GetRandomSubset(
double relative_size, std::vector<T>* base,
1209 absl::BitGenRef random) {
1210 if (base->empty())
return;
1214 std::shuffle(base->begin(), base->end(), random);
1215 const int target_size = std::round(relative_size * base->size());
1216 base->resize(target_size);
1222 const CpSolverResponse& initial_solution,
double difficulty,
1223 absl::BitGenRef random) {
1225 GetRandomSubset(1.0 -
difficulty, &fixed_variables, random);
1227 initial_solution, {fixed_variables.begin(), fixed_variables.end()});
1231 const CpSolverResponse& initial_solution,
double difficulty,
1232 absl::BitGenRef random) {
1237 std::vector<int> relaxed_variables;
1241 std::vector<int> active_constraints(num_active_constraints);
1242 for (
int c = 0; c < num_active_constraints; ++c) {
1243 active_constraints[c] = c;
1245 std::shuffle(active_constraints.begin(), active_constraints.end(), random);
1248 std::vector<bool> visited_variables_set(num_model_vars,
false);
1250 const int num_active_vars =
1252 const int target_size = std::ceil(
difficulty * num_active_vars);
1253 DCHECK_GT(target_size, 0);
1255 for (
const int constraint_index : active_constraints) {
1257 if (visited_variables_set[
var])
continue;
1258 visited_variables_set[
var] =
true;
1260 relaxed_variables.push_back(
var);
1261 if (relaxed_variables.size() == target_size)
break;
1264 if (relaxed_variables.size() == target_size)
break;
1274 const CpSolverResponse& initial_solution,
double difficulty,
1275 absl::BitGenRef random) {
1277 std::vector<bool> visited_variables_set(num_model_vars,
false);
1278 std::vector<int> relaxed_variables;
1279 std::vector<int> visited_variables;
1283 std::vector<bool> scanned_constraints(num_model_constraints,
false);
1285 std::vector<int> random_variables;
1291 const int num_active_vars =
1293 const int target_size = std::ceil(
difficulty * num_active_vars);
1296 const int first_var =
1298 random, 0, num_active_vars)];
1300 visited_variables_set[first_var] =
true;
1301 visited_variables.push_back(first_var);
1302 relaxed_variables.push_back(first_var);
1304 for (
int i = 0; i < visited_variables.size(); ++i) {
1305 random_variables.clear();
1309 if (scanned_constraints[
ct])
continue;
1310 scanned_constraints[
ct] =
true;
1312 if (visited_variables_set[
var])
continue;
1313 visited_variables_set[
var] =
true;
1314 random_variables.push_back(
var);
1319 std::shuffle(random_variables.begin(), random_variables.end(), random);
1320 for (
const int var : random_variables) {
1321 if (relaxed_variables.size() < target_size) {
1322 visited_variables.push_back(
var);
1324 relaxed_variables.push_back(
var);
1330 if (relaxed_variables.size() >= target_size)
break;
1340 const CpSolverResponse& initial_solution,
double difficulty,
1341 absl::BitGenRef random) {
1343 if (num_model_constraints == 0) {
1348 std::vector<bool> visited_variables_set(num_model_vars,
false);
1349 std::vector<int> relaxed_variables;
1351 std::vector<bool> added_constraints(num_model_constraints,
false);
1352 std::vector<int> next_constraints;
1354 std::vector<int> random_variables;
1357 const int num_active_vars =
1359 const int target_size = std::ceil(
difficulty * num_active_vars);
1364 if (num_active_constraints != 0) {
1365 next_constraints.push_back(
1366 absl::Uniform<int>(random, 0, num_active_constraints));
1367 added_constraints[next_constraints.back()] =
true;
1370 while (relaxed_variables.size() < target_size) {
1372 if (next_constraints.empty())
break;
1375 const int i = absl::Uniform<int>(random, 0, next_constraints.size());
1376 const int constraint_index = next_constraints[i];
1377 std::swap(next_constraints[i], next_constraints.back());
1378 next_constraints.pop_back();
1382 DCHECK_LT(constraint_index, num_active_constraints);
1384 std::shuffle(random_variables.begin(), random_variables.end(), random);
1385 for (
const int var : random_variables) {
1386 if (visited_variables_set[
var])
continue;
1387 visited_variables_set[
var] =
true;
1389 relaxed_variables.push_back(
var);
1391 if (relaxed_variables.size() == target_size)
break;
1394 if (added_constraints[
ct])
continue;
1395 added_constraints[
ct] =
true;
1396 next_constraints.push_back(
ct);
1406 const CpSolverResponse& initial_solution,
double difficulty,
1407 absl::BitGenRef random) {
1409 GetRandomSubset(1.0 -
difficulty, &fixed_variables, random);
1411 initial_solution, {fixed_variables.begin(), fixed_variables.end()});
1416 void AddPrecedence(
const LinearExpressionProto& before,
1417 const LinearExpressionProto& after, CpModelProto*
model) {
1418 LinearConstraintProto* linear =
model->add_constraints()->mutable_linear();
1420 linear->add_domain(after.offset() - before.offset());
1421 for (
int i = 0; i < before.vars_size(); ++i) {
1422 linear->add_vars(before.vars(i));
1423 linear->add_coeffs(before.coeffs(i));
1425 for (
int i = 0; i < after.vars_size(); ++i) {
1426 linear->add_vars(after.vars(i));
1427 linear->add_coeffs(-after.coeffs(i));
1434 const absl::Span<
const std::pair<int, int>> precedences,
1435 const CpSolverResponse& initial_solution,
1439 neighborhood.
is_reduced = !precedences.empty();
1443 return neighborhood;
1447 absl::flat_hash_set<int> seen_intervals;
1448 for (
const std::pair<int, int>& prec : precedences) {
1449 seen_intervals.insert(prec.first);
1450 seen_intervals.insert(prec.second);
1454 bool enforcement_literals_fixed =
false;
1456 if (seen_intervals.contains(i))
continue;
1458 const ConstraintProto& interval_ct = helper.
ModelProto().constraints(i);
1459 if (interval_ct.enforcement_literal().empty())
continue;
1461 DCHECK_EQ(interval_ct.enforcement_literal().size(), 1);
1462 const int enforcement_ref = interval_ct.enforcement_literal(0);
1463 const int enforcement_var =
PositiveRef(enforcement_ref);
1464 const int value = initial_solution.solution(enforcement_var);
1474 neighborhood.
delta.mutable_variables(enforcement_var)->clear_domain();
1475 neighborhood.
delta.mutable_variables(enforcement_var)->add_domain(
value);
1476 neighborhood.
delta.mutable_variables(enforcement_var)->add_domain(
value);
1477 enforcement_literals_fixed =
true;
1480 for (
const std::pair<int, int>& prec : precedences) {
1481 const LinearExpressionProto& before_end =
1482 helper.
ModelProto().constraints(prec.first).interval().end();
1483 const LinearExpressionProto& after_start =
1484 helper.
ModelProto().constraints(prec.second).interval().start();
1485 DCHECK_LE(GetLinearExpressionValue(before_end, initial_solution),
1486 GetLinearExpressionValue(after_start, initial_solution));
1487 AddPrecedence(before_end, after_start, &neighborhood.
delta);
1494 return neighborhood;
1498 const absl::Span<const int> intervals_to_relax,
1499 const CpSolverResponse& initial_solution, absl::BitGenRef random,
1504 absl::flat_hash_set<int> ignored_intervals(intervals_to_relax.begin(),
1505 intervals_to_relax.end());
1510 if (ignored_intervals.contains(i))
continue;
1512 const ConstraintProto& interval_ct = helper.
ModelProto().constraints(i);
1513 if (interval_ct.enforcement_literal().empty())
continue;
1515 DCHECK_EQ(interval_ct.enforcement_literal().size(), 1);
1516 const int enforcement_ref = interval_ct.enforcement_literal(0);
1517 const int enforcement_var =
PositiveRef(enforcement_ref);
1518 const int value = initial_solution.solution(enforcement_var);
1526 ignored_intervals.insert(i);
1531 neighborhood.
delta.mutable_variables(enforcement_var)->clear_domain();
1532 neighborhood.
delta.mutable_variables(enforcement_var)->add_domain(
value);
1533 neighborhood.
delta.mutable_variables(enforcement_var)->add_domain(
value);
1536 if (ignored_intervals.size() >=
1541 return neighborhood;
1550 const std::vector<std::pair<int, int>> precedences =
1553 for (
const std::pair<int, int>& prec : precedences) {
1554 const LinearExpressionProto& before_end =
1555 helper.
ModelProto().constraints(prec.first).interval().end();
1556 const LinearExpressionProto& after_start =
1557 helper.
ModelProto().constraints(prec.second).interval().start();
1558 DCHECK_LE(GetLinearExpressionValue(before_end, initial_solution),
1559 GetLinearExpressionValue(after_start, initial_solution));
1560 AddPrecedence(before_end, after_start, &neighborhood.
delta);
1567 return neighborhood;
1571 const CpSolverResponse& initial_solution,
double difficulty,
1572 absl::BitGenRef random) {
1573 std::vector<int> intervals_to_relax =
1575 GetRandomSubset(
difficulty, &intervals_to_relax, random);
1578 intervals_to_relax, initial_solution, random,
helper_);
1582 const CpSolverResponse& initial_solution,
double difficulty,
1583 absl::BitGenRef random) {
1584 std::vector<std::pair<int, int>> precedences =
1586 GetRandomSubset(1.0 -
difficulty, &precedences, random);
1588 precedences, initial_solution,
helper_);
1592 const CpSolverResponse& initial_solution,
double difficulty,
1593 absl::BitGenRef random) {
1594 const std::vector<int> active_intervals =
1599 const std::vector<int> intervals_to_relax =
1603 intervals_to_relax, initial_solution, random,
helper_);
1607 const CpSolverResponse& initial_solution,
double difficulty,
1608 absl::BitGenRef random) {
1609 intervals_to_relax_.clear();
1610 for (
const std::vector<int>& intervals : intervals_in_constraints_) {
1611 const std::vector<int> selected = SelectIntervalsInRandomTimeWindow(
1613 intervals_to_relax_.insert(selected.begin(), selected.end());
1618 const std::vector<int> intervals(
1619 {intervals_to_relax_.begin(), intervals_to_relax_.end()});
1621 intervals, initial_solution, random,
helper_);
1625 const CpSolverResponse& initial_solution,
double difficulty,
1626 absl::BitGenRef random) {
1627 const std::vector<std::vector<int>> all_paths =
1631 absl::flat_hash_set<int> all_path_variables;
1632 for (
auto& path : all_paths) {
1633 all_path_variables.insert(path.begin(), path.end());
1635 std::vector<int> fixed_variables(all_path_variables.begin(),
1636 all_path_variables.end());
1637 std::sort(fixed_variables.begin(), fixed_variables.end());
1638 GetRandomSubset(1.0 -
difficulty, &fixed_variables, random);
1640 initial_solution, {fixed_variables.begin(), fixed_variables.end()});
1644 const CpSolverResponse& initial_solution,
double difficulty,
1645 absl::BitGenRef random) {
1646 std::vector<std::vector<int>> all_paths =
1650 absl::flat_hash_set<int> all_path_variables;
1651 for (
const auto& path : all_paths) {
1652 all_path_variables.insert(path.begin(), path.end());
1656 const int num_variables_to_relax =
1657 static_cast<int>(all_path_variables.size() *
difficulty);
1658 absl::flat_hash_set<int> relaxed_variables;
1659 while (relaxed_variables.size() < num_variables_to_relax) {
1660 DCHECK(!all_paths.empty());
1661 const int path_index = absl::Uniform<int>(random, 0, all_paths.size());
1662 std::vector<int>& path = all_paths[path_index];
1663 const int path_size = path.size();
1664 const int segment_length =
1665 std::min(path_size, absl::Uniform<int>(random, 4, 8));
1666 const int segment_start =
1667 absl::Uniform<int>(random, 0, path_size - segment_length);
1668 for (
int i = segment_start; i < segment_start + segment_length; ++i) {
1669 relaxed_variables.insert(path[i]);
1673 path.erase(path.begin() + segment_start,
1674 path.begin() + segment_start + segment_length);
1676 std::swap(all_paths[path_index], all_paths.back());
1677 all_paths.pop_back();
1682 absl::flat_hash_set<int> fixed_variables;
1683 for (
const int var : all_path_variables) {
1684 if (!relaxed_variables.contains(
var)) fixed_variables.insert(
var);
1690 const CpSolverResponse& initial_solution,
double difficulty,
1691 absl::BitGenRef random) {
1692 std::vector<std::vector<int>> all_paths =
1695 if (all_paths.empty()) {
1700 absl::flat_hash_set<int> all_path_variables;
1701 for (
const auto& path : all_paths) {
1702 all_path_variables.insert(path.begin(), path.end());
1706 const int num_variables_to_relax =
1707 static_cast<int>(all_path_variables.size() *
difficulty);
1708 absl::flat_hash_set<int> relaxed_variables;
1711 for (
const auto& path : all_paths) {
1712 relaxed_variables.insert(path.front());
1713 relaxed_variables.insert(path.back());
1717 for (
auto& path : all_paths) {
1718 std::shuffle(path.begin(), path.end(), random);
1722 const int path_to_clean = absl::Uniform<int>(random, 0, all_paths.size());
1723 while (relaxed_variables.size() < num_variables_to_relax &&
1724 !all_paths[path_to_clean].empty()) {
1725 relaxed_variables.insert(all_paths[path_to_clean].back());
1726 all_paths[path_to_clean].pop_back();
1728 if (all_paths[path_to_clean].empty()) {
1729 std::swap(all_paths[path_to_clean], all_paths.back());
1730 all_paths.pop_back();
1734 while (relaxed_variables.size() < num_variables_to_relax) {
1735 DCHECK(!all_paths.empty());
1736 const int path_index = absl::Uniform<int>(random, 0, all_paths.size());
1737 relaxed_variables.insert(all_paths[path_index].back());
1740 all_paths[path_index].pop_back();
1741 if (all_paths[path_index].empty()) {
1742 std::swap(all_paths[path_index], all_paths.back());
1743 all_paths.pop_back();
1748 absl::flat_hash_set<int> fixed_variables;
1749 for (
const int var : all_path_variables) {
1750 if (!relaxed_variables.contains(
var)) fixed_variables.insert(
var);
1756 if (incomplete_solutions_ !=
nullptr) {
1760 if (response_manager_ !=
nullptr) {
1768 if (lp_solutions_ !=
nullptr && lp_solutions_->
NumSolutions() > 0) {
1772 if (relaxation_solutions_ !=
nullptr &&
1780 const CpSolverResponse& ,
double ,
1781 absl::BitGenRef random) {
1785 const bool lp_solution_available =
1786 (lp_solutions_ !=
nullptr && lp_solutions_->
NumSolutions() > 0);
1788 const bool relaxation_solution_available =
1789 (relaxation_solutions_ !=
nullptr &&
1792 const bool incomplete_solution_available =
1793 (incomplete_solutions_ !=
nullptr &&
1796 if (!lp_solution_available && !relaxation_solution_available &&
1797 !incomplete_solution_available) {
1798 return neighborhood;
1805 std::bernoulli_distribution random_bool(0.5);
1806 const bool use_lp_relaxation =
1807 (lp_solution_available && relaxation_solution_available)
1808 ? random_bool(random)
1809 : lp_solution_available;
1810 if (use_lp_relaxation) {
1813 nullptr, lp_solutions_,
1814 incomplete_solutions_, random);
1816 incomplete_solution_available ?
"incomplete" :
"lp";
1818 CHECK(relaxation_solution_available || incomplete_solution_available);
1820 response_manager_, relaxation_solutions_,
1821 nullptr, incomplete_solutions_, random);
1823 incomplete_solution_available ?
"incomplete" :
"relaxation";
1828 return neighborhood;
1833 for (
const std::pair</*model_var*/ int, /*value*/ int64_t>& fixed_var :
1835 const int var = fixed_var.first;
1836 const int64_t
value = fixed_var.second;
1837 if (
var >= neighborhood.
delta.variables_size())
continue;
1842 return neighborhood;
1845 neighborhood.
delta.mutable_variables(
var)->clear_domain();
1846 neighborhood.
delta.mutable_variables(
var)->add_domain(
value);
1847 neighborhood.
delta.mutable_variables(
var)->add_domain(
value);
1851 for (
const std::pair<
int,
1852 std::pair<int64_t, int64_t>>& reduced_var :
1854 const int var = reduced_var.first;
1855 const int64_t lb = reduced_var.second.first;
1856 const int64_t ub = reduced_var.second.second;
1857 if (
var >= neighborhood.
delta.variables_size())
continue;
1864 return neighborhood;
1870 return neighborhood;
bool AddEdge(int node1, int node2)
void SetNumberOfNodes(int num_nodes)
void Update(int num_decreases, int num_increases)
We call domain any subset of Int64 = [kint64min, kint64max].
bool IsIncludedIn(const Domain &domain) const
Returns true iff D is included in the given domain.
bool Contains(int64_t value) const
Returns true iff value is in Domain.
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.
int64_t Min() const
Returns the min value of the domain.
bool IsEmpty() const
Returns true if this is the empty set.
int64_t Max() const
Returns the max value of the domain.
Neighborhood Generate(const CpSolverResponse &initial_solution, double difficulty, absl::BitGenRef random) final
const std::vector< std::vector< int > > & VarToConstraint() const ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_)
const SharedResponseManager & shared_response() const
std::vector< std::pair< int, int > > GetSchedulingPrecedences(const absl::flat_hash_set< int > &ignored_intervals, const CpSolverResponse &initial_solution, absl::BitGenRef random) const
Neighborhood FullNeighborhood() const
std::vector< int > ActiveVariables() const
Neighborhood FixAllVariables(const CpSolverResponse &initial_solution) const
Neighborhood FixGivenVariables(const CpSolverResponse &base_solution, const absl::flat_hash_set< int > &variables_to_fix) const
const absl::Span< const int > TypeToConstraints(ConstraintProto::ConstraintCase type) 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
std::vector< int > ActiveObjectiveVariables() const
const CpModelProto & ModelProto() const
const std::vector< std::vector< int > > & ConstraintToVar() const ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_)
std::vector< std::vector< int > > GetUniqueIntervalSets() const
NeighborhoodGeneratorHelper(CpModelProto const *model_proto, SatParameters const *parameters, SharedResponseManager *shared_response, SharedBoundsManager *shared_bounds=nullptr)
bool IsActive(int var) 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< int > & ActiveVariablesWhileHoldingLock() const ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_)
void Synchronize() override
std::vector< std::vector< int > > GetRoutingPaths(const CpSolverResponse &initial_solution) const
absl::Mutex generator_mutex_
virtual bool ReadyToGenerate() const
double difficulty() const
double GetUCBScore(int64_t total_num_calls) const
const NeighborhoodGeneratorHelper & helper_
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
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
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
void LogPeriodicMessage(const std::string &prefix, const std::string &message, double frequency_seconds, absl::Time *last_logging_time)
const SharedSolutionRepository< int64_t > & SolutionsRepository() const
bool LoggingIsEnabled() const
IntegerValue GetInnerObjectiveLowerBound()
SubsolverType type() const
Neighborhood Generate(const CpSolverResponse &initial_solution, double difficulty, absl::BitGenRef random) final
CpModelProto const * model_proto
GurobiMPCallbackContext * context
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
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)
Neighborhood GenerateSchedulingNeighborhoodFromRelaxedIntervals(const absl::Span< const int > intervals_to_relax, const CpSolverResponse &initial_solution, absl::BitGenRef random, const NeighborhoodGeneratorHelper &helper)
bool DomainInProtoContains(const ProtoWithDomain &proto, int64_t value)
void FillDomainInProto(const Domain &domain, ProtoWithDomain *proto)
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
Neighborhood GenerateSchedulingNeighborhoodFromIntervalPrecedences(const absl::Span< const std::pair< int, int >> precedences, 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)
Represents a closed interval [start, end].
int num_relaxed_variables
std::vector< int > variables_that_can_be_fixed_to_local_optimum
int num_relaxed_variables_in_objective
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(verboselevel)
#define VLOG_IS_ON(verboselevel)