24 #include "absl/container/flat_hash_map.h"
25 #include "absl/container/flat_hash_set.h"
26 #include "absl/memory/memory.h"
27 #include "absl/random/distributions.h"
28 #include "absl/random/random.h"
29 #include "absl/strings/str_cat.h"
43 "Frequency of checks for better solutions in the solution pool.");
46 "Size of TSPs solved in the TSPOpt operator.");
49 "Size of TSPs solved in the TSPLns operator.");
52 "If true, equivalent empty paths are removed from the neighborhood "
66 Assignment* deltadelta);
75 Assignment* deltadelta) {
76 CHECK(
delta !=
nullptr);
77 VLOG(2) << DebugString() <<
"::MakeNextNeighbor(delta=("
78 <<
delta->DebugString() <<
"), deltadelta=("
79 << (deltadelta ? deltadelta->DebugString() : std::string(
"nullptr"));
88 VLOG(2) <<
"Delta (" << DebugString() <<
") = " <<
delta->DebugString();
107 for (
int candidate : fragment_) {
122 fragment_.push_back(
index);
133 class SimpleLns :
public BaseLns {
135 SimpleLns(
const std::vector<IntVar*>& vars,
int number_of_variables)
136 :
BaseLns(vars), index_(0), number_of_variables_(number_of_variables) {
137 CHECK_GT(number_of_variables_, 0);
139 ~SimpleLns()
override {}
140 void InitFragments()
override { index_ = 0; }
141 bool NextFragment()
override;
142 std::string DebugString()
const override {
return "SimpleLns"; }
146 const int number_of_variables_;
149 bool SimpleLns::NextFragment() {
150 const int size = Size();
152 for (
int i = index_; i < index_ + number_of_variables_; ++i) {
153 AppendToFragment(i % size);
166 class RandomLns :
public BaseLns {
168 RandomLns(
const std::vector<IntVar*>& vars,
int number_of_variables,
170 : BaseLns(vars), rand_(seed), number_of_variables_(number_of_variables) {
171 CHECK_GT(number_of_variables_, 0);
172 CHECK_LE(number_of_variables_, Size());
174 ~RandomLns()
override {}
175 bool NextFragment()
override;
177 std::string DebugString()
const override {
return "RandomLns"; }
181 const int number_of_variables_;
184 bool RandomLns::NextFragment() {
185 DCHECK_GT(Size(), 0);
186 for (
int i = 0; i < number_of_variables_; ++i) {
187 AppendToFragment(absl::Uniform<int>(rand_, 0, Size()));
193 LocalSearchOperator* Solver::MakeRandomLnsOperator(
194 const std::vector<IntVar*>& vars,
int number_of_variables) {
195 return MakeRandomLnsOperator(vars, number_of_variables, CpRandomSeed());
198 LocalSearchOperator* Solver::MakeRandomLnsOperator(
199 const std::vector<IntVar*>& vars,
int number_of_variables,
int32 seed) {
200 return RevAlloc(
new RandomLns(vars, number_of_variables, seed));
209 class MoveTowardTargetLS :
public IntVarLocalSearchOperator {
211 MoveTowardTargetLS(
const std::vector<IntVar*>& variables,
212 const std::vector<int64>& target_values)
213 : IntVarLocalSearchOperator(variables),
214 target_(target_values),
218 variable_index_(Size() - 1) {
219 CHECK_EQ(target_values.size(), variables.size()) <<
"Illegal arguments.";
222 ~MoveTowardTargetLS()
override {}
224 std::string DebugString()
const override {
return "MoveTowardTargetLS"; }
228 bool MakeOneNeighbor()
override {
229 while (num_var_since_last_start_ < Size()) {
230 ++num_var_since_last_start_;
231 variable_index_ = (variable_index_ + 1) % Size();
232 const int64 target_value = target_.at(variable_index_);
233 const int64 current_value = OldValue(variable_index_);
234 if (current_value != target_value) {
235 SetValue(variable_index_, target_value);
243 void OnStart()
override {
255 CHECK_GE(variable_index_, 0);
256 CHECK_LT(variable_index_, Size());
257 num_var_since_last_start_ = 0;
261 const std::vector<int64> target_;
264 int64 variable_index_;
267 int64 num_var_since_last_start_;
271 LocalSearchOperator* Solver::MakeMoveTowardTargetOperator(
272 const Assignment& target) {
273 typedef std::vector<IntVarElement> Elements;
274 const Elements& elements = target.IntVarContainer().elements();
276 std::vector<IntVar*> vars;
277 std::vector<int64> values;
278 vars.reserve(target.NumIntVars());
279 values.reserve(target.NumIntVars());
280 for (
const auto& it : elements) {
281 vars.push_back(it.Var());
282 values.push_back(it.Value());
284 return MakeMoveTowardTargetOperator(vars, values);
287 LocalSearchOperator* Solver::MakeMoveTowardTargetOperator(
288 const std::vector<IntVar*>& variables,
289 const std::vector<int64>& target_values) {
290 return RevAlloc(
new MoveTowardTargetLS(variables, target_values));
301 const int size =
Size();
302 while (index_ < size) {
311 void ChangeValue::OnStart() { index_ = 0; }
316 class IncrementValue :
public ChangeValue {
318 explicit IncrementValue(
const std::vector<IntVar*>& vars)
319 : ChangeValue(vars) {}
320 ~IncrementValue()
override {}
323 std::string DebugString()
const override {
return "IncrementValue"; }
328 class DecrementValue :
public ChangeValue {
330 explicit DecrementValue(
const std::vector<IntVar*>& vars)
331 : ChangeValue(vars) {}
332 ~DecrementValue()
override {}
335 std::string DebugString()
const override {
return "DecrementValue"; }
342 const std::vector<IntVar*>& path_vars,
343 int number_of_base_nodes,
344 bool skip_locally_optimal_paths,
345 bool accept_path_end_base,
346 std::function<
int(
int64)> start_empty_path_class)
348 number_of_nexts_(next_vars.size()),
349 ignore_path_vars_(path_vars.empty()),
350 next_base_to_increment_(number_of_base_nodes),
351 base_nodes_(number_of_base_nodes),
352 base_alternatives_(number_of_base_nodes),
353 base_sibling_alternatives_(number_of_base_nodes),
354 end_nodes_(number_of_base_nodes),
355 base_paths_(number_of_base_nodes),
356 just_started_(false),
358 accept_path_end_base_(accept_path_end_base),
359 start_empty_path_class_(std::move(start_empty_path_class)),
360 skip_locally_optimal_paths_(skip_locally_optimal_paths),
361 optimal_paths_enabled_(false),
362 alternative_index_(next_vars.size(), -1) {
363 DCHECK_GT(number_of_base_nodes, 0);
367 path_basis_.push_back(0);
368 for (
int i = 1; i < base_nodes_.size(); ++i) {
371 if ((path_basis_.size() > 2) ||
372 (!next_vars.empty() && !next_vars.back()
375 .skip_locally_optimal_paths())) {
376 skip_locally_optimal_paths_ =
false;
382 void PathOperator::OnStart() {
383 optimal_paths_enabled_ =
false;
384 InitializeBaseNodes();
385 InitializeAlternatives();
390 while (IncrementPosition()) {
416 if (destination == before_chain || destination == chain_end)
return false;
419 const int64 destination_path =
Path(destination);
420 const int64 after_chain =
Next(chain_end);
421 SetNext(chain_end,
Next(destination), destination_path);
423 int current = destination;
425 while (current != chain_end) {
431 SetNext(destination,
Next(before_chain), destination_path);
433 SetNext(before_chain, after_chain,
Path(before_chain));
442 if (current == after_chain) {
446 SetNext(current, after_chain, path);
447 while (current_next != after_chain) {
449 SetNext(current_next, current, path);
450 current = current_next;
453 SetNext(before_chain, current, path);
454 *chain_last = current;
462 int64 destination_path =
Path(destination);
463 SetNext(node,
Next(destination), destination_path);
464 SetNext(destination, node, destination_path);
472 const int64 kNoPath = -1;
475 const int64 after_chain =
Next(chain_end);
477 while (current != after_chain) {
479 SetNext(current, current, kNoPath);
482 SetNext(before_chain, after_chain,
Path(before_chain));
489 if (active == inactive)
return false;
494 bool PathOperator::IncrementPosition() {
495 const int base_node_size = base_nodes_.size();
497 if (!just_started_) {
498 const int number_of_paths = path_starts_.size();
504 int last_restarted = base_node_size;
505 for (
int i = base_node_size - 1; i >= 0; --i) {
509 const int sibling_alternative_index =
511 if (sibling_alternative_index >= 0) {
512 if (base_sibling_alternatives_[i] <
513 alternative_sets_[sibling_alternative_index].size() - 1) {
514 ++base_sibling_alternatives_[i];
517 base_sibling_alternatives_[i] = 0;
521 const int alternative_index = alternative_index_[base_nodes_[i]];
522 if (alternative_index >= 0) {
523 if (base_alternatives_[i] <
524 alternative_sets_[alternative_index].size() - 1) {
525 ++base_alternatives_[i];
528 base_alternatives_[i] = 0;
529 base_sibling_alternatives_[i] = 0;
533 base_alternatives_[i] = 0;
534 base_sibling_alternatives_[i] = 0;
535 base_nodes_[i] =
OldNext(base_nodes_[i]);
536 if (accept_path_end_base_ || !
IsPathEnd(base_nodes_[i]))
break;
538 base_alternatives_[i] = 0;
539 base_sibling_alternatives_[i] = 0;
553 for (
int i = last_restarted; i < base_node_size; ++i) {
554 base_alternatives_[i] = 0;
555 base_sibling_alternatives_[i] = 0;
558 if (last_restarted > 0) {
564 if (optimal_paths_enabled_ && skip_locally_optimal_paths_) {
565 if (path_basis_.size() > 1) {
566 for (
int i = 1; i < path_basis_.size(); ++i) {
576 std::vector<int> current_starts(base_node_size);
577 for (
int i = 0; i < base_node_size; ++i) {
582 optimal_paths_enabled_ =
true;
584 for (
int i = base_node_size - 1; i >= 0; --i) {
585 const int next_path_index = base_paths_[i] + 1;
586 if (next_path_index < number_of_paths) {
587 base_paths_[i] = next_path_index;
588 base_alternatives_[i] = 0;
589 base_sibling_alternatives_[i] = 0;
590 base_nodes_[i] = path_starts_[next_path_index];
596 base_alternatives_[i] = 0;
597 base_sibling_alternatives_[i] = 0;
598 base_nodes_[i] = path_starts_[0];
601 if (!skip_locally_optimal_paths_)
return CheckEnds();
604 if (path_basis_.size() > 1) {
605 for (
int j = 1; j < path_basis_.size(); ++j) {
607 path_basis_[j - 1])] +
621 if (!CheckEnds())
return false;
623 for (
int i = 0; i < base_node_size; ++i) {
629 if (stop)
return false;
632 just_started_ =
false;
638 void PathOperator::InitializePathStarts() {
646 has_prevs[
next] =
true;
651 if (optimal_paths_.empty() && skip_locally_optimal_paths_) {
663 if (skip_locally_optimal_paths_) {
683 std::vector<int64> new_path_starts;
684 const bool use_empty_path_symmetry_breaker =
685 FLAGS_cp_use_empty_path_symmetry_breaker;
689 if (start_empty_path_class_ !=
nullptr) {
690 if (empty_found[start_empty_path_class_(i)]) {
693 empty_found[start_empty_path_class_(i)] =
true;
697 new_path_starts.push_back(i);
705 std::vector<int> node_paths(max_next + 1, -1);
706 for (
int i = 0; i < path_starts_.size(); ++i) {
707 int node = path_starts_[i];
709 node_paths[node] = i;
712 node_paths[node] = i;
714 for (
int j = 0; j < base_nodes_.size(); ++j) {
716 base_alternatives_[j] = 0;
717 base_sibling_alternatives_[j] = 0;
718 if (
IsInactive(base_nodes_[j]) || node_paths[base_nodes_[j]] == -1) {
721 base_nodes_[j] = path_starts_[base_paths_[j]];
723 base_paths_[j] = node_paths[base_nodes_[j]];
730 absl::flat_hash_set<int> found_bases;
731 for (
int i = 0; i < path_starts_.size(); ++i) {
732 int index = new_index;
734 while (
index < new_path_starts.size() &&
735 new_path_starts[
index] < path_starts_[i]) {
738 const bool found = (
index < new_path_starts.size() &&
739 new_path_starts[
index] == path_starts_[i]);
743 for (
int j = 0; j < base_nodes_.size(); ++j) {
745 found_bases.insert(j);
746 base_paths_[j] = new_index;
750 base_nodes_[j] = new_path_starts[new_index];
756 path_starts_.swap(new_path_starts);
759 void PathOperator::InitializeInactives() {
762 inactives_.push_back(
OldNext(i) == i);
766 void PathOperator::InitializeBaseNodes() {
768 InitializeInactives();
769 InitializePathStarts();
773 for (
int i = 0; i < base_nodes_.size(); ++i) {
775 base_nodes_[i] = path_starts_[0];
777 first_start_ =
false;
779 for (
int i = 0; i < base_nodes_.size(); ++i) {
781 int64 base_node = base_nodes_[i];
783 base_node = path_starts_[base_paths_[i]];
784 base_nodes_[i] = base_node;
786 end_nodes_[i] = base_node;
790 for (
int i = 1; i < base_nodes_.size(); ++i) {
792 !OnSamePath(base_nodes_[i - 1], base_nodes_[i])) {
793 const int64 base_node = base_nodes_[i - 1];
794 base_nodes_[i] = base_node;
795 end_nodes_[i] = base_node;
796 base_paths_[i] = base_paths_[i - 1];
799 for (
int i = 0; i < base_nodes_.size(); ++i) {
800 base_alternatives_[i] = 0;
801 base_sibling_alternatives_[i] = 0;
803 just_started_ =
true;
806 void PathOperator::InitializeAlternatives() {
807 active_in_alternative_set_.resize(alternative_sets_.size(), -1);
808 for (
int i = 0; i < alternative_sets_.size(); ++i) {
809 const int64 current_active = active_in_alternative_set_[i];
810 if (current_active >= 0 && !
IsInactive(current_active))
continue;
813 active_in_alternative_set_[i] =
index;
820 bool PathOperator::OnSamePath(
int64 node1,
int64 node2)
const {
843 int64 exclude)
const {
844 if (before_chain == chain_end || before_chain == exclude)
return false;
845 int64 current = before_chain;
847 while (current != chain_end) {
854 current =
Next(current);
856 if (current == exclude) {
876 const std::vector<IntVar*>& secondary_vars,
877 std::function<
int(
int64)> start_empty_path_class)
879 std::move(start_empty_path_class)),
898 void OnNodeInitialization()
override { last_ = -1; }
906 if (last_base_ !=
BaseNode(0) || last_ == -1) {
918 && last_ != chain_last) {
949 const std::vector<IntVar*>& secondary_vars,
const std::string&
name,
950 std::function<
int(
int64)> start_empty_path_class,
951 int64 chain_length = 1LL,
bool single_path =
false)
953 std::move(start_empty_path_class)),
954 chain_length_(chain_length),
955 single_path_(single_path),
957 CHECK_GT(chain_length_, 0);
960 const std::vector<IntVar*>& secondary_vars,
961 std::function<
int(
int64)> start_empty_path_class,
962 int64 chain_length = 1LL,
bool single_path =
false)
964 absl::StrCat(
"Relocate<", chain_length,
">"),
965 std::move(start_empty_path_class), chain_length, single_path) {
980 const int64 chain_length_;
981 const bool single_path_;
982 const std::string name_;
990 int64 chain_end = before_chain;
991 for (
int i = 0; i < chain_length_; ++i) {
992 if (
IsPathEnd(chain_end) || chain_end == destination) {
995 chain_end =
Next(chain_end);
998 MoveChain(before_chain, chain_end, destination);
1014 const std::vector<IntVar*>& secondary_vars,
1015 std::function<
int(
int64)> start_empty_path_class)
1017 std::move(start_empty_path_class)) {}
1031 const bool ok =
MoveChain(prev_node0, node0, prev_node1);
1050 const std::vector<IntVar*>& secondary_vars,
1051 std::function<
int(
int64)> start_empty_path_class)
1053 std::move(start_empty_path_class)) {}
1063 if (start1 == start0)
return false;
1065 if (node0 == start0)
return false;
1067 if (node1 == start1)
return false;
1076 return MoveChain(start0, node0, start1);
1078 return MoveChain(start1, node1, start0);
1089 const std::vector<IntVar*>& vars,
1090 const std::vector<IntVar*>& secondary_vars,
int number_of_base_nodes,
1091 std::function<
int(
int64)> start_empty_path_class)
1092 :
PathOperator(vars, secondary_vars, number_of_base_nodes, false, false,
1093 std::move(start_empty_path_class)),
1104 void OnNodeInitialization()
override;
1109 void BaseInactiveNodeToPathOperator::OnNodeInitialization() {
1110 for (
int i = 0; i <
Size(); ++i) {
1116 inactive_node_ =
Size();
1120 while (inactive_node_ <
Size()) {
1143 const std::vector<IntVar*>& secondary_vars,
1144 std::function<
int(
int64)> start_empty_path_class)
1146 std::move(start_empty_path_class)) {}
1150 std::string
DebugString()
const override {
return "MakeActiveOperator"; }
1169 const std::vector<IntVar*>& vars,
1170 const std::vector<IntVar*>& secondary_vars,
1171 std::function<
int(
int64)> start_empty_path_class)
1173 std::move(start_empty_path_class)) {}
1177 const int64 node =
Next(before_node_to_move);
1184 return "RelocateAndMakeActiveOpertor";
1197 const std::vector<IntVar*>& secondary_vars,
1198 std::function<
int(
int64)> start_empty_path_class)
1200 std::move(start_empty_path_class)) {}
1205 return "MakeActiveAndRelocateOperator";
1211 const int64 chain_end =
Next(before_chain);
1214 MoveChain(before_chain, chain_end, destination) &&
1229 const std::vector<IntVar*>& secondary_vars,
1230 std::function<
int(
int64)> start_empty_path_class)
1232 std::move(start_empty_path_class)) {}
1239 std::string
DebugString()
const override {
return "MakeInactiveOperator"; }
1253 const std::vector<IntVar*>& vars,
1254 const std::vector<IntVar*>& secondary_vars,
1255 std::function<
int(
int64)> start_empty_path_class)
1257 std::move(start_empty_path_class)) {}
1262 const int64 node_to_inactivate =
Next(destination);
1263 if (node_to_inactivate == before_to_move ||
IsPathEnd(node_to_inactivate) ||
1267 const int64 node =
Next(before_to_move);
1272 return "RelocateAndMakeInactiveOperator";
1288 const std::vector<IntVar*>& secondary_vars,
1289 std::function<
int(
int64)> start_empty_path_class)
1291 std::move(start_empty_path_class)) {}
1298 return "MakeChainInactiveOperator";
1310 if (base_index == 0) {
1329 const std::vector<IntVar*>& secondary_vars,
1330 std::function<
int(
int64)> start_empty_path_class)
1332 std::move(start_empty_path_class)) {}
1336 std::string
DebugString()
const override {
return "SwapActiveOperator"; }
1361 const std::vector<IntVar*>& secondary_vars,
1362 std::function<
int(
int64)> start_empty_path_class)
1364 std::move(start_empty_path_class)) {}
1369 return "ExtendedSwapActiveOperator";
1376 if (
Next(base0) == base1) {
1394 TSPOpt(
const std::vector<IntVar*>& vars,
1395 const std::vector<IntVar*>& secondary_vars,
1396 Solver::IndexEvaluator3 evaluator,
int chain_length);
1403 std::vector<std::vector<int64>> cost_;
1405 hamiltonian_path_solver_;
1406 Solver::IndexEvaluator3 evaluator_;
1407 const int chain_length_;
1411 const std::vector<IntVar*>& secondary_vars,
1412 Solver::IndexEvaluator3 evaluator,
int chain_length)
1413 :
PathOperator(vars, secondary_vars, 1, true, false, nullptr),
1414 hamiltonian_path_solver_(cost_),
1416 chain_length_(chain_length) {}
1419 std::vector<int64> nodes;
1421 for (
int i = 0; i < chain_length_ + 1; ++i) {
1422 nodes.push_back(chain_end);
1426 chain_end =
Next(chain_end);
1428 if (nodes.size() <= 3) {
1432 const int size = nodes.size() - 1;
1434 for (
int i = 0; i < size; ++i) {
1435 cost_[i].resize(size);
1436 cost_[i][0] = evaluator_(nodes[i], nodes[size], chain_path);
1437 for (
int j = 1; j < size; ++j) {
1438 cost_[i][j] = evaluator_(nodes[i], nodes[j], chain_path);
1442 std::vector<PathNodeIndex> path;
1444 CHECK_EQ(size + 1, path.size());
1445 for (
int i = 0; i < size - 1; ++i) {
1446 SetNext(nodes[path[i]], nodes[path[i + 1]], chain_path);
1448 SetNext(nodes[path[size - 1]], nodes[size], chain_path);
1462 TSPLns(
const std::vector<IntVar*>& vars,
1463 const std::vector<IntVar*>& secondary_vars,
1464 Solver::IndexEvaluator3 evaluator,
int tsp_size);
1474 void OnNodeInitialization()
override {
1476 has_long_enough_paths_ =
Size() != 0;
1479 std::vector<std::vector<int64>> cost_;
1480 HamiltonianPathSolver<int64, std::vector<std::vector<int64>>>
1481 hamiltonian_path_solver_;
1482 Solver::IndexEvaluator3 evaluator_;
1483 const int tsp_size_;
1485 bool has_long_enough_paths_;
1489 const std::vector<IntVar*>& secondary_vars,
1490 Solver::IndexEvaluator3 evaluator,
int tsp_size)
1491 :
PathOperator(vars, secondary_vars, 1, true, false, nullptr),
1492 hamiltonian_path_solver_(cost_),
1494 tsp_size_(tsp_size),
1495 rand_(CpRandomSeed()),
1496 has_long_enough_paths_(true) {
1497 CHECK_GE(tsp_size_, 0);
1498 cost_.resize(tsp_size_);
1499 for (
int i = 0; i < tsp_size_; ++i) {
1500 cost_[i].resize(tsp_size_);
1505 while (has_long_enough_paths_) {
1506 has_long_enough_paths_ =
false;
1510 Var(0)->solver()->TopPeriodicCheck();
1517 std::vector<int64> nodes;
1519 nodes.push_back(node);
1521 if (nodes.size() <= tsp_size_) {
1524 has_long_enough_paths_ =
true;
1527 absl::flat_hash_set<int64> breaks_set;
1529 breaks_set.insert(base_node);
1530 CHECK(!nodes.empty());
1531 while (breaks_set.size() < tsp_size_) {
1532 const int64 one_break = nodes[absl::Uniform<int>(rand_, 0, nodes.size())];
1534 breaks_set.insert(one_break);
1537 CHECK_EQ(breaks_set.size(), tsp_size_);
1542 std::vector<int> breaks;
1543 std::vector<int64> meta_node_costs;
1550 breaks.push_back(node);
1551 meta_node_costs.push_back(
cost);
1558 meta_node_costs[0] +=
cost;
1559 CHECK_EQ(breaks.size(), tsp_size_);
1561 CHECK_EQ(meta_node_costs.size(), tsp_size_);
1562 for (
int i = 0; i < tsp_size_; ++i) {
1564 CapAdd(meta_node_costs[i],
1565 evaluator_(breaks[i],
Next(breaks[tsp_size_ - 1]), node_path));
1566 for (
int j = 1; j < tsp_size_; ++j) {
1568 CapAdd(meta_node_costs[i],
1569 evaluator_(breaks[i],
Next(breaks[j - 1]), node_path));
1575 std::vector<PathNodeIndex> path;
1577 bool nochange =
true;
1578 for (
int i = 0; i < path.size() - 1; ++i) {
1587 CHECK_EQ(0, path[path.size() - 1]);
1588 for (
int i = 0; i < tsp_size_ - 1; ++i) {
1589 SetNext(breaks[path[i]],
OldNext(breaks[path[i + 1] - 1]), node_path);
1591 SetNext(breaks[path[tsp_size_ - 1]],
OldNext(breaks[tsp_size_ - 1]),
1612 virtual std::string
DebugString()
const {
return "NearestNeighbors"; }
1615 void ComputeNearest(
int row);
1617 std::vector<std::vector<int>> neighbors_;
1618 Solver::IndexEvaluator3 evaluator_;
1629 path_operator_(path_operator),
1631 initialized_(false) {}
1635 if (!initialized_) {
1636 initialized_ =
true;
1638 neighbors_.push_back(std::vector<int>());
1645 return neighbors_[
index];
1648 void NearestNeighbors::ComputeNearest(
int row) {
1650 const int path = path_operator_.
Path(
row);
1651 const IntVar*
var = path_operator_.
Var(
row);
1653 const int var_size =
var->Max() - var_min + 1;
1654 using ValuedIndex = std::pair<
int64 ,
int >;
1655 std::vector<ValuedIndex> neighbors(var_size);
1656 for (
int i = 0; i < var_size; ++i) {
1657 const int index = i + var_min;
1658 neighbors[i] = std::make_pair(evaluator_(
row,
index, path),
index);
1660 if (var_size > size_) {
1661 std::nth_element(neighbors.begin(), neighbors.begin() + size_ - 1,
1666 for (
int i = 0; i <
std::min(size_, var_size); ++i) {
1667 neighbors_[
row].push_back(neighbors[i].second);
1669 std::sort(neighbors_[
row].begin(), neighbors_[
row].end());
1675 const std::vector<IntVar*>& secondary_vars,
1676 const Solver::IndexEvaluator3& evaluator,
bool topt);
1683 void OnNodeInitialization()
override;
1685 static const int kNeighbors;
1689 Solver::IndexEvaluator3
const evaluator_;
1691 absl::flat_hash_set<int64> marked_;
1700 const std::vector<IntVar*>& secondary_vars,
1701 const Solver::IndexEvaluator3& evaluator,
bool topt)
1702 :
PathOperator(vars, secondary_vars, 1, true, false, nullptr),
1704 neighbors_(evaluator, *this, kNeighbors),
1709 void LinKernighan::OnNodeInitialization() { neighbors_.
Initialize(); }
1720 marked_.insert(node);
1722 if (!InFromOut(node,
next, &out, &gain))
return false;
1723 marked_.insert(
next);
1724 marked_.insert(out);
1725 const int64 node1 = out;
1729 if (!InFromOut(node1, next1, &out, &gain))
return false;
1730 marked_.insert(next1);
1731 marked_.insert(out);
1736 const int64 in_cost = evaluator_(node, next_out, path);
1737 const int64 out_cost = evaluator_(out, next_out, path);
1738 if (
CapAdd(
CapSub(gain, in_cost), out_cost) > 0)
return true;
1745 while (InFromOut(node,
next, &out, &gain)) {
1746 marked_.insert(
next);
1747 marked_.insert(out);
1752 int64 in_cost = evaluator_(base, chain_last, path);
1753 int64 out_cost = evaluator_(chain_last, out, path);
1769 const int LinKernighan::kNeighbors = 5 + 1;
1772 const std::vector<int>& nexts = neighbors_.
Neighbors(in_j);
1775 int64 out_cost = evaluator_(in_i, in_j, path);
1776 const int64 current_gain =
CapAdd(*gain, out_cost);
1777 for (
int k = 0; k < nexts.size(); ++k) {
1780 int64 in_cost = evaluator_(in_j,
next, path);
1782 if (new_gain > 0 &&
next !=
Next(in_j) && marked_.count(in_j) == 0 &&
1783 marked_.count(
next) == 0) {
1784 if (best_gain < new_gain) {
1786 best_gain = new_gain;
1804 const std::vector<IntVar*>& secondary_vars,
int number_of_chunks,
1805 int chunk_size,
bool unactive_fragments)
1806 :
PathOperator(vars, secondary_vars, number_of_chunks, true, true,
1808 number_of_chunks_(number_of_chunks),
1809 chunk_size_(chunk_size),
1810 unactive_fragments_(unactive_fragments) {
1811 CHECK_GE(chunk_size_, 0);
1820 inline bool ChainsAreFullPaths()
const {
return chunk_size_ == 0; }
1821 void DeactivateChain(
int64 node);
1822 void DeactivateUnactives();
1824 const int number_of_chunks_;
1825 const int chunk_size_;
1826 const bool unactive_fragments_;
1830 if (ChainsAreFullPaths()) {
1834 for (
int i = 0; i < number_of_chunks_; ++i) {
1838 for (
int i = 0; i < number_of_chunks_; ++i) {
1841 DeactivateUnactives();
1845 void PathLns::DeactivateChain(
int64 node) {
1846 for (
int i = 0, current = node;
1847 (ChainsAreFullPaths() || i < chunk_size_) && !
IsPathEnd(current);
1848 ++i, current =
Next(current)) {
1856 void PathLns::DeactivateUnactives() {
1857 if (unactive_fragments_) {
1858 for (
int i = 0; i <
Size(); ++i) {
1874 : operator_(op), limit_(limit), next_neighborhood_calls_(0) {
1875 CHECK(op !=
nullptr);
1879 void Start(
const Assignment* assignment)
override {
1880 next_neighborhood_calls_ = 0;
1881 operator_->
Start(assignment);
1885 if (next_neighborhood_calls_ >= limit_) {
1888 ++next_neighborhood_calls_;
1894 std::string
DebugString()
const override {
return "NeighborhoodLimit"; }
1899 int64 next_neighborhood_calls_;
1902 LocalSearchOperator* Solver::MakeNeighborhoodLimit(
1903 LocalSearchOperator*
const op,
int64 limit) {
1904 return RevAlloc(
new NeighborhoodLimit(op, limit));
1910 class CompoundOperator :
public LocalSearchOperator {
1912 CompoundOperator(std::vector<LocalSearchOperator*> operators,
1913 std::function<
int64(
int,
int)> evaluator);
1914 ~CompoundOperator()
override {}
1915 void Reset()
override;
1916 void Start(
const Assignment* assignment)
override;
1917 bool MakeNextNeighbor(Assignment*
delta, Assignment* deltadelta)
override;
1918 bool HasFragments()
const override {
return has_fragments_; }
1919 bool HoldsDelta()
const override {
return true; }
1921 std::string DebugString()
const override {
1922 return operators_[operator_indices_[index_]]->DebugString();
1924 const LocalSearchOperator* Self()
const override {
1925 return operators_[operator_indices_[index_]]->Self();
1929 class OperatorComparator {
1931 OperatorComparator(std::function<
int64(
int,
int)> evaluator,
1932 int active_operator)
1933 :
evaluator_(std::move(evaluator)), active_operator_(active_operator) {}
1934 bool operator()(
int lhs,
int rhs)
const {
1935 const int64 lhs_value = Evaluate(lhs);
1936 const int64 rhs_value = Evaluate(rhs);
1937 return lhs_value < rhs_value || (lhs_value == rhs_value && lhs < rhs);
1941 int64 Evaluate(
int operator_index)
const {
1942 return evaluator_(active_operator_, operator_index);
1946 const int active_operator_;
1950 std::vector<LocalSearchOperator*> operators_;
1951 std::vector<int> operator_indices_;
1953 Bitset64<> started_;
1954 const Assignment* start_assignment_;
1955 bool has_fragments_;
1958 CompoundOperator::CompoundOperator(std::vector<LocalSearchOperator*> operators,
1959 std::function<
int64(
int,
int)> evaluator)
1961 operators_(std::move(operators)),
1963 started_(operators_.size()),
1964 start_assignment_(nullptr),
1965 has_fragments_(false) {
1966 operators_.erase(std::remove(operators_.begin(), operators_.end(),
nullptr),
1968 operator_indices_.resize(operators_.size());
1969 std::iota(operator_indices_.begin(), operator_indices_.end(), 0);
1971 if (op->HasFragments()) {
1972 has_fragments_ =
true;
1978 void CompoundOperator::Reset() {
1979 for (LocalSearchOperator*
const op : operators_) {
1984 void CompoundOperator::Start(
const Assignment* assignment) {
1985 start_assignment_ = assignment;
1987 if (!operators_.empty()) {
1988 OperatorComparator comparator(
evaluator_, operator_indices_[index_]);
1989 std::sort(operator_indices_.begin(), operator_indices_.end(), comparator);
1994 bool CompoundOperator::MakeNextNeighbor(Assignment*
delta,
1995 Assignment* deltadelta) {
1996 if (!operators_.empty()) {
2000 const int64 operator_index = operator_indices_[index_];
2001 if (!started_[operator_index]) {
2002 operators_[operator_index]->Start(start_assignment_);
2003 started_.
Set(operator_index);
2005 if (!operators_[operator_index]->HoldsDelta()) {
2008 if (operators_[operator_index]->MakeNextNeighbor(
delta, deltadelta)) {
2013 if (index_ == operators_.size()) {
2016 }
while (index_ != 0);
2021 int64 CompoundOperatorNoRestart(
int size,
int active_index,
2022 int operator_index) {
2023 if (operator_index < active_index) {
2024 return size + operator_index - active_index;
2026 return operator_index - active_index;
2030 int64 CompoundOperatorRestart(
int active_index,
int operator_index) {
2035 LocalSearchOperator* Solver::ConcatenateOperators(
2036 const std::vector<LocalSearchOperator*>& ops) {
2037 return ConcatenateOperators(ops,
false);
2040 LocalSearchOperator* Solver::ConcatenateOperators(
2041 const std::vector<LocalSearchOperator*>& ops,
bool restart) {
2043 std::function<
int64(
int,
int)> eval = CompoundOperatorRestart;
2044 return ConcatenateOperators(ops, eval);
2046 const int size = ops.size();
2047 return ConcatenateOperators(ops, [size](
int i,
int j) {
2048 return CompoundOperatorNoRestart(size, i, j);
2053 LocalSearchOperator* Solver::ConcatenateOperators(
2054 const std::vector<LocalSearchOperator*>& ops,
2055 std::function<
int64(
int,
int)> evaluator) {
2056 return RevAlloc(
new CompoundOperator(ops, std::move(evaluator)));
2060 class RandomCompoundOperator :
public LocalSearchOperator {
2062 explicit RandomCompoundOperator(std::vector<LocalSearchOperator*> operators);
2063 RandomCompoundOperator(std::vector<LocalSearchOperator*> operators,
2065 ~RandomCompoundOperator()
override {}
2066 void Reset()
override;
2067 void Start(
const Assignment* assignment)
override;
2068 bool MakeNextNeighbor(Assignment*
delta, Assignment* deltadelta)
override;
2069 bool HoldsDelta()
const override {
return true; }
2071 std::string DebugString()
const override {
return "RandomCompoundOperator"; }
2076 const std::vector<LocalSearchOperator*> operators_;
2077 bool has_fragments_;
2080 void RandomCompoundOperator::Start(
const Assignment* assignment) {
2081 for (LocalSearchOperator*
const op : operators_) {
2082 op->Start(assignment);
2086 RandomCompoundOperator::RandomCompoundOperator(
2087 std::vector<LocalSearchOperator*> operators)
2088 : RandomCompoundOperator(std::move(operators), CpRandomSeed()) {}
2090 RandomCompoundOperator::RandomCompoundOperator(
2091 std::vector<LocalSearchOperator*> operators,
int32 seed)
2092 : rand_(seed), operators_(std::move(operators)), has_fragments_(false) {
2094 if (op->HasFragments()) {
2095 has_fragments_ =
true;
2101 void RandomCompoundOperator::Reset() {
2102 for (LocalSearchOperator*
const op : operators_) {
2107 bool RandomCompoundOperator::MakeNextNeighbor(Assignment*
delta,
2108 Assignment* deltadelta) {
2109 const int size = operators_.size();
2110 std::vector<int> indices(size);
2111 std::iota(indices.begin(), indices.end(), 0);
2112 std::shuffle(indices.begin(), indices.end(), rand_);
2113 for (
int index : indices) {
2114 if (!operators_[
index]->HoldsDelta()) {
2117 if (operators_[
index]->MakeNextNeighbor(
delta, deltadelta)) {
2126 LocalSearchOperator* Solver::RandomConcatenateOperators(
2127 const std::vector<LocalSearchOperator*>& ops) {
2128 return RevAlloc(
new RandomCompoundOperator(ops));
2131 LocalSearchOperator* Solver::RandomConcatenateOperators(
2132 const std::vector<LocalSearchOperator*>& ops,
int32 seed) {
2133 return RevAlloc(
new RandomCompoundOperator(ops, seed));
2140 Solver* solver,
const std::vector<IntVar*>& vars,
2141 const std::vector<IntVar*>& secondary_vars,
2142 std::function<
int(
int64)> start_empty_path_class) {
2143 return solver->RevAlloc(
2144 new T(vars, secondary_vars, std::move(start_empty_path_class)));
2147 #define MAKE_LOCAL_SEARCH_OPERATOR(OperatorClass) \
2149 LocalSearchOperator* MakeLocalSearchOperator<OperatorClass>( \
2150 Solver * solver, const std::vector<IntVar*>& vars, \
2151 const std::vector<IntVar*>& secondary_vars, \
2152 std::function<int(int64)> start_empty_path_class) { \
2153 return solver->RevAlloc(new OperatorClass( \
2154 vars, secondary_vars, std::move(start_empty_path_class))); \
2170 #undef MAKE_LOCAL_SEARCH_OPERATOR
2172 LocalSearchOperator* Solver::MakeOperator(
const std::vector<IntVar*>& vars,
2173 Solver::LocalSearchOperators op) {
2174 return MakeOperator(vars, std::vector<IntVar*>(), op);
2177 LocalSearchOperator* Solver::MakeOperator(
2178 const std::vector<IntVar*>& vars,
2179 const std::vector<IntVar*>& secondary_vars,
2180 Solver::LocalSearchOperators op) {
2181 LocalSearchOperator* result =
nullptr;
2183 case Solver::TWOOPT: {
2184 result = RevAlloc(
new TwoOpt(vars, secondary_vars,
nullptr));
2187 case Solver::OROPT: {
2188 std::vector<LocalSearchOperator*> operators;
2189 for (
int i = 1; i < 4; ++i) {
2190 operators.push_back(RevAlloc(
2191 new Relocate(vars, secondary_vars, absl::StrCat(
"OrOpt<", i,
">"),
2192 nullptr, i,
true)));
2194 result = ConcatenateOperators(operators);
2197 case Solver::RELOCATE: {
2198 result = MakeLocalSearchOperator<Relocate>(
this, vars, secondary_vars,
2202 case Solver::EXCHANGE: {
2203 result = MakeLocalSearchOperator<Exchange>(
this, vars, secondary_vars,
2207 case Solver::CROSS: {
2209 MakeLocalSearchOperator<Cross>(
this, vars, secondary_vars,
nullptr);
2212 case Solver::MAKEACTIVE: {
2213 result = MakeLocalSearchOperator<MakeActiveOperator>(
2214 this, vars, secondary_vars,
nullptr);
2217 case Solver::MAKEINACTIVE: {
2218 result = MakeLocalSearchOperator<MakeInactiveOperator>(
2219 this, vars, secondary_vars,
nullptr);
2222 case Solver::MAKECHAININACTIVE: {
2223 result = MakeLocalSearchOperator<MakeChainInactiveOperator>(
2224 this, vars, secondary_vars,
nullptr);
2227 case Solver::SWAPACTIVE: {
2228 result = MakeLocalSearchOperator<SwapActiveOperator>(
2229 this, vars, secondary_vars,
nullptr);
2232 case Solver::EXTENDEDSWAPACTIVE: {
2233 result = MakeLocalSearchOperator<ExtendedSwapActiveOperator>(
2234 this, vars, secondary_vars,
nullptr);
2237 case Solver::PATHLNS: {
2238 result = RevAlloc(
new PathLns(vars, secondary_vars, 2, 3,
false));
2241 case Solver::FULLPATHLNS: {
2242 result = RevAlloc(
new PathLns(vars, secondary_vars,
2248 case Solver::UNACTIVELNS: {
2249 result = RevAlloc(
new PathLns(vars, secondary_vars, 1, 6,
true));
2252 case Solver::INCREMENT: {
2253 if (secondary_vars.empty()) {
2254 result = RevAlloc(
new IncrementValue(vars));
2256 LOG(FATAL) <<
"Operator " << op
2257 <<
" does not support secondary variables";
2261 case Solver::DECREMENT: {
2262 if (secondary_vars.empty()) {
2263 result = RevAlloc(
new DecrementValue(vars));
2265 LOG(FATAL) <<
"Operator " << op
2266 <<
" does not support secondary variables";
2270 case Solver::SIMPLELNS: {
2271 if (secondary_vars.empty()) {
2272 result = RevAlloc(
new SimpleLns(vars, 1));
2274 LOG(FATAL) <<
"Operator " << op
2275 <<
" does not support secondary variables";
2280 LOG(FATAL) <<
"Unknown operator " << op;
2285 LocalSearchOperator* Solver::MakeOperator(
2286 const std::vector<IntVar*>& vars, Solver::IndexEvaluator3 evaluator,
2287 Solver::EvaluatorLocalSearchOperators op) {
2288 return MakeOperator(vars, std::vector<IntVar*>(), std::move(evaluator), op);
2291 LocalSearchOperator* Solver::MakeOperator(
2292 const std::vector<IntVar*>& vars,
2293 const std::vector<IntVar*>& secondary_vars,
2294 Solver::IndexEvaluator3 evaluator,
2295 Solver::EvaluatorLocalSearchOperators op) {
2296 LocalSearchOperator* result =
nullptr;
2299 std::vector<LocalSearchOperator*> operators;
2300 operators.push_back(RevAlloc(
2301 new LinKernighan(vars, secondary_vars, evaluator,
false)));
2302 operators.push_back(RevAlloc(
2303 new LinKernighan(vars, secondary_vars, evaluator,
true)));
2304 result = ConcatenateOperators(operators);
2307 case Solver::TSPOPT: {
2308 result = RevAlloc(
new TSPOpt(vars, secondary_vars, evaluator,
2309 FLAGS_cp_local_search_tsp_opt_size));
2312 case Solver::TSPLNS: {
2313 result = RevAlloc(
new TSPLns(vars, secondary_vars, evaluator,
2314 FLAGS_cp_local_search_tsp_lns_size));
2318 LOG(FATAL) <<
"Unknown operator " << op;
2326 class SumOperation {
2328 SumOperation() : value_(0) {}
2329 void Init() { value_ = 0; }
2330 void Update(
int64 update) { value_ =
CapAdd(value_, update); }
2331 void Remove(
int64 remove) { value_ =
CapSub(value_, remove); }
2333 void set_value(
int64 new_value) { value_ = new_value; }
2339 class ProductOperation {
2341 ProductOperation() : value_(1) {}
2342 void Init() { value_ = 1; }
2343 void Update(
int64 update) { value_ *= update; }
2344 void Remove(
int64 remove) {
2350 void set_value(
int64 new_value) { value_ = new_value; }
2356 class MinOperation {
2358 void Init() { values_set_.clear(); }
2359 void Update(
int64 update) { values_set_.insert(update); }
2360 void Remove(
int64 remove) { values_set_.erase(remove); }
2362 return (!values_set_.empty()) ? *values_set_.begin() : 0;
2364 void set_value(
int64 new_value) {}
2367 std::set<int64> values_set_;
2370 class MaxOperation {
2372 void Init() { values_set_.clear(); }
2373 void Update(
int64 update) { values_set_.insert(update); }
2374 void Remove(
int64 remove) { values_set_.erase(remove); }
2376 return (!values_set_.empty()) ? *values_set_.rbegin() : 0;
2378 void set_value(
int64 new_value) {}
2381 std::set<int64> values_set_;
2385 class AcceptFilter :
public LocalSearchFilter {
2387 std::string DebugString()
const override {
return "AcceptFilter"; }
2388 bool Accept(
const Assignment*
delta,
const Assignment* deltadelta,
2392 void Synchronize(
const Assignment* assignment,
2393 const Assignment*
delta)
override {}
2397 LocalSearchFilter* Solver::MakeAcceptFilter() {
2398 return RevAlloc(
new AcceptFilter());
2403 class RejectFilter :
public LocalSearchFilter {
2405 std::string DebugString()
const override {
return "RejectFilter"; }
2406 bool Accept(
const Assignment*
delta,
const Assignment* deltadelta,
2410 void Synchronize(
const Assignment* assignment,
2411 const Assignment*
delta)
override {}
2415 LocalSearchFilter* Solver::MakeRejectFilter() {
2416 return RevAlloc(
new RejectFilter());
2420 std::vector<int> path_end)
2421 : num_nodes_(num_nodes),
2422 num_paths_(path_start.size()),
2423 num_nodes_threshold_(std::
max(16, 4 * num_nodes_))
2425 DCHECK_EQ(path_start.size(), num_paths_);
2426 DCHECK_EQ(path_end.size(), num_paths_);
2427 for (
int p = 0; p < num_paths_; ++p) {
2428 path_start_end_.push_back({path_start[p], path_end[p]});
2431 committed_index_.assign(num_nodes_, -1);
2432 committed_nodes_.assign(2 * num_paths_, {-1, -1});
2433 chains_.assign(num_paths_ + 1, {-1, -1});
2434 paths_.assign(num_paths_, {-1, -1});
2435 for (
int path = 0; path < num_paths_; ++path) {
2436 const int index = 2 * path;
2437 const PathStartEnd start_end = path_start_end_[path];
2438 committed_index_[start_end.start] =
index;
2439 committed_index_[start_end.end] =
index + 1;
2441 committed_nodes_[
index] = {start_end.start, path};
2442 committed_nodes_[
index + 1] = {start_end.end, path};
2445 paths_[path] = {path, path + 1};
2447 chains_[num_paths_] = {0, 0};
2449 for (
int node = 0; node < num_nodes_; ++node) {
2450 if (committed_index_[node] != -1)
continue;
2451 committed_index_[node] = committed_nodes_.size();
2452 committed_nodes_.push_back({node, -1});
2454 path_has_changed_.assign(num_paths_,
false);
2458 const PathBounds
bounds = paths_[path];
2460 chains_.data() +
bounds.end_index,
2461 committed_nodes_.data());
2465 const PathBounds
bounds = paths_[path];
2467 chains_.data() +
bounds.end_index,
2468 committed_nodes_.data());
2475 DCHECK_EQ(chains_.size(), num_paths_ + 1);
2476 DCHECK(changed_paths_.empty());
2477 tail_head_indices_.clear();
2478 int num_changed_arcs = 0;
2479 for (
const auto& arc : changed_arcs_) {
2481 std::tie(node,
next) = arc;
2482 const int node_index = committed_index_[node];
2483 const int next_index = committed_index_[
next];
2484 const int node_path = committed_nodes_[node_index].path;
2486 (next_index != node_index + 1 || node_path == -1)) {
2487 tail_head_indices_.push_back({node_index, next_index});
2488 changed_arcs_[num_changed_arcs++] = {node,
next};
2489 if (node_path != -1 && !path_has_changed_[node_path]) {
2490 path_has_changed_[node_path] =
true;
2491 changed_paths_.push_back(node_path);
2493 }
else if (node ==
next && node_path != -1) {
2494 changed_arcs_[num_changed_arcs++] = {node, node};
2497 changed_arcs_.resize(num_changed_arcs);
2514 for (
const int path : changed_paths_) {
2515 const PathStartEnd start_end = path_start_end_[path];
2516 tail_head_indices_.push_back(
2517 {committed_index_[start_end.end], committed_index_[start_end.start]});
2522 const int num_arc_indices = tail_head_indices_.size();
2523 arcs_by_tail_index_.resize(num_arc_indices);
2524 arcs_by_head_index_.resize(num_arc_indices);
2525 for (
int i = 0; i < num_arc_indices; ++i) {
2526 arcs_by_tail_index_[i] = {tail_head_indices_[i].tail_index, i};
2527 arcs_by_head_index_[i] = {tail_head_indices_[i].head_index, i};
2529 std::sort(arcs_by_tail_index_.begin(), arcs_by_tail_index_.end());
2530 std::sort(arcs_by_head_index_.begin(), arcs_by_head_index_.end());
2532 next_arc_.resize(num_arc_indices);
2533 for (
int i = 0; i < num_arc_indices; ++i) {
2534 next_arc_[arcs_by_head_index_[i].arc] = arcs_by_tail_index_[i].arc;
2540 const int first_fake_arc = num_arc_indices - changed_paths_.size();
2541 for (
int fake_arc = first_fake_arc; fake_arc < num_arc_indices; ++fake_arc) {
2542 const int new_path_begin = chains_.size();
2543 int32 arc = fake_arc;
2545 const int chain_begin = tail_head_indices_[arc].head_index;
2546 arc = next_arc_[arc];
2547 const int chain_end = tail_head_indices_[arc].tail_index + 1;
2548 chains_.emplace_back(chain_begin, chain_end);
2549 }
while (arc != fake_arc);
2550 const int path = changed_paths_[fake_arc - first_fake_arc];
2551 const int new_path_end = chains_.size();
2552 paths_[path] = {new_path_begin, new_path_end};
2554 chains_.emplace_back(0, 0);
2558 if (committed_nodes_.size() < num_nodes_threshold_) {
2559 IncrementalCommit();
2566 chains_.resize(num_paths_ + 1);
2567 for (
const int path : changed_paths_) {
2568 paths_[path] = {path, path + 1};
2569 path_has_changed_[path] =
false;
2571 changed_paths_.clear();
2572 changed_arcs_.clear();
2575 void PathState::CopyNewPathAtEndOfNodes(
int path) {
2577 const int new_path_begin_index = committed_nodes_.size();
2578 const PathBounds path_bounds = paths_[path];
2579 for (
int i = path_bounds.begin_index; i < path_bounds.end_index; ++i) {
2580 const ChainBounds chain_bounds = chains_[i];
2581 committed_nodes_.insert(committed_nodes_.end(),
2582 committed_nodes_.data() + chain_bounds.begin_index,
2583 committed_nodes_.data() + chain_bounds.end_index);
2585 const int new_path_end_index = committed_nodes_.size();
2587 for (
int i = new_path_begin_index; i < new_path_end_index; ++i) {
2588 committed_nodes_[i].path = path;
2594 void PathState::IncrementalCommit() {
2595 const int new_nodes_begin = committed_nodes_.size();
2597 const int chain_begin = committed_nodes_.size();
2598 CopyNewPathAtEndOfNodes(path);
2599 const int chain_end = committed_nodes_.size();
2600 chains_[path] = {chain_begin, chain_end};
2603 const int new_nodes_end = committed_nodes_.size();
2604 for (
int i = new_nodes_begin; i < new_nodes_end; ++i) {
2605 committed_index_[committed_nodes_[i].node] = i;
2611 std::tie(node,
next) = arc;
2612 if (node !=
next)
continue;
2613 const int index = committed_index_[node];
2614 committed_nodes_[
index].path = -1;
2620 void PathState::FullCommit() {
2623 const int old_num_nodes = committed_nodes_.size();
2624 for (
int path = 0; path < num_paths_; ++path) {
2625 const int new_path_begin = committed_nodes_.size() - old_num_nodes;
2626 CopyNewPathAtEndOfNodes(path);
2627 const int new_path_end = committed_nodes_.size() - old_num_nodes;
2628 chains_[path] = {new_path_begin, new_path_end};
2630 committed_nodes_.erase(committed_nodes_.begin(),
2631 committed_nodes_.begin() + old_num_nodes);
2634 constexpr
int kUnindexed = -1;
2635 committed_index_.assign(num_nodes_, kUnindexed);
2637 for (
const CommittedNode committed_node : committed_nodes_) {
2638 committed_index_[committed_node.node] =
index++;
2640 for (
int node = 0; node < num_nodes_; ++node) {
2641 if (committed_index_[node] != kUnindexed)
continue;
2642 committed_index_[node] =
index++;
2643 committed_nodes_.push_back({node, -1});
2651 class PathStateFilter :
public LocalSearchFilter {
2653 std::string DebugString()
const override {
return "PathStateFilter"; }
2654 PathStateFilter(std::unique_ptr<PathState> path_state,
2655 const std::vector<IntVar*>& nexts);
2656 void Relax(
const Assignment*
delta,
const Assignment* deltadelta)
override;
2657 bool Accept(
const Assignment*
delta,
const Assignment* deltadelta,
2658 int64 objective_min,
int64 objective_max)
override {
2661 void Synchronize(
const Assignment*
delta,
2662 const Assignment* deltadelta)
override;
2663 void Revert()
override;
2666 const std::unique_ptr<PathState> path_state_;
2668 std::vector<int> variable_index_to_node_;
2672 PathStateFilter::PathStateFilter(std::unique_ptr<PathState> path_state,
2673 const std::vector<IntVar*>& nexts)
2674 : path_state_(std::move(path_state)) {
2676 for (
const IntVar*
next : nexts) {
2677 index_offset_ = std::min<int>(index_offset_,
next->index());
2679 variable_index_to_node_.resize(nexts.size(), -1);
2680 for (
int node = 0; node < nexts.size(); ++node) {
2681 const int index = nexts[node]->index() - index_offset_;
2682 if (variable_index_to_node_.size() <=
index) {
2683 variable_index_to_node_.resize(
index + 1, -1);
2685 variable_index_to_node_[
index] = node;
2689 void PathStateFilter::Relax(
const Assignment*
delta,
2690 const Assignment* deltadelta) {
2691 for (
const IntVarElement& var_value :
delta->IntVarContainer().elements()) {
2692 const int index = var_value.Var()->index() - index_offset_;
2693 if (
index < 0 || variable_index_to_node_.size() <=
index)
continue;
2694 const int node = variable_index_to_node_[
index];
2695 if (node == -1)
continue;
2696 path_state_->ChangeNext(node, var_value.Value());
2698 path_state_->CutChains();
2704 void PathStateFilter::Synchronize(
const Assignment*
delta,
2705 const Assignment* deltadelta) {
2706 path_state_->Revert();
2707 Relax(
delta, deltadelta);
2708 path_state_->Commit();
2711 void PathStateFilter::Revert() { path_state_->Revert(); }
2716 std::unique_ptr<PathState> path_state,
2717 const std::vector<IntVar*>& nexts) {
2718 PathStateFilter* filter =
new PathStateFilter(std::move(path_state), nexts);
2719 return solver->RevAlloc(filter);
2723 const PathState* path_state, std::vector<Interval> path_capacity,
2724 std::vector<int> path_class, std::vector<std::vector<Interval>>
demand,
2725 std::vector<Interval> node_capacity)
2726 : path_state_(path_state),
2727 path_capacity_(std::move(path_capacity)),
2728 path_class_(std::move(path_class)),
2729 demand_(std::move(
demand)),
2730 node_capacity_(std::move(node_capacity)),
2731 index_(path_state_->NumNodes(), 0),
2732 maximum_partial_demand_layer_size_(
2733 std::
max(16, 4 * path_state_->NumNodes()))
2735 const int num_nodes = path_state_->
NumNodes();
2736 const int num_paths = path_state_->
NumPaths();
2737 DCHECK_EQ(num_paths, path_capacity_.size());
2738 DCHECK_EQ(num_paths, path_class_.size());
2740 partial_demand_sums_rmq_.resize(maximum_rmq_exponent + 1);
2741 for (
auto& sums : partial_demand_sums_rmq_) {
2742 sums.resize(num_nodes + num_paths);
2744 previous_nontrivial_index_.reserve(num_nodes + num_paths);
2750 const Interval path_capacity = path_capacity_[path];
2754 const int path_class = path_class_[path];
2756 Interval capacity_used = node_capacity_[path_state_->
Start(path)];
2759 if (capacity_used.
min > capacity_used.
max)
return false;
2761 for (
const auto chain : path_state_->
Chains(path)) {
2762 const int first_node = chain.First();
2763 const int last_node = chain.Last();
2765 const int first_index = index_[first_node];
2766 const int last_index = index_[last_node];
2768 const int chain_path = path_state_->
Path(first_node);
2769 const int chain_path_class =
2770 chain_path == -1 ? -1 : path_class_[chain_path];
2774 constexpr
int kMinRangeSizeForRMQ = 4;
2775 if (last_index - first_index > kMinRangeSizeForRMQ &&
2776 path_class == chain_path_class &&
2777 SubpathOnlyHasTrivialNodes(first_index, last_index)) {
2782 GetMinMaxPartialDemandSum(first_index, last_index);
2783 const Interval prev_sum = partial_demand_sums_rmq_[0][first_index - 1];
2791 if (capacity_used.
min > capacity_used.
max)
return false;
2793 const Interval last_sum = partial_demand_sums_rmq_[0][last_index];
2798 for (
const int node : chain) {
2799 const Interval node_capacity = node_capacity_[node];
2802 if (capacity_used.
min > capacity_used.
max)
return false;
2820 const int current_layer_size = partial_demand_sums_rmq_[0].size();
2823 for (
const auto chain : path_state_->
Chains(path)) {
2824 change_size += chain.NumNodes();
2827 if (current_layer_size + change_size <= maximum_partial_demand_layer_size_) {
2828 IncrementalCommit();
2834 void UnaryDimensionChecker::IncrementalCommit() {
2836 const int begin_index = partial_demand_sums_rmq_[0].size();
2837 AppendPathDemandsToSums(path);
2838 UpdateRMQStructure(begin_index, partial_demand_sums_rmq_[0].size());
2842 void UnaryDimensionChecker::FullCommit() {
2844 previous_nontrivial_index_.clear();
2845 for (
auto& sums : partial_demand_sums_rmq_) sums.clear();
2847 const int num_paths = path_state_->
NumPaths();
2848 for (
int path = 0; path < num_paths; ++path) {
2849 const int begin_index = partial_demand_sums_rmq_[0].size();
2850 AppendPathDemandsToSums(path);
2851 UpdateRMQStructure(begin_index, partial_demand_sums_rmq_[0].size());
2855 void UnaryDimensionChecker::AppendPathDemandsToSums(
int path) {
2856 const int path_class = path_class_[path];
2857 Interval demand_sum = {0, 0};
2858 int previous_nontrivial_index = -1;
2859 int index = partial_demand_sums_rmq_[0].size();
2862 partial_demand_sums_rmq_[0].push_back(demand_sum);
2863 previous_nontrivial_index_.push_back(-1);
2866 for (
const int node : path_state_->
Nodes(path)) {
2867 index_[node] =
index;
2868 const Interval
demand = demand_[path_class][node];
2871 partial_demand_sums_rmq_[0].push_back(demand_sum);
2873 const Interval node_capacity = node_capacity_[node];
2876 previous_nontrivial_index =
index;
2878 previous_nontrivial_index_.push_back(previous_nontrivial_index);
2883 void UnaryDimensionChecker::UpdateRMQStructure(
int begin_index,
int end_index) {
2886 const int maximum_rmq_exponent =
2888 for (
int layer = 1, window_size = 1; layer <= maximum_rmq_exponent;
2889 ++layer, window_size *= 2) {
2890 partial_demand_sums_rmq_[layer].resize(end_index);
2891 for (
int i = begin_index; i < end_index - window_size; ++i) {
2892 const Interval i1 = partial_demand_sums_rmq_[layer - 1][i];
2893 const Interval i2 = partial_demand_sums_rmq_[layer - 1][i + window_size];
2894 partial_demand_sums_rmq_[layer][i] = {
std::min(i1.min, i2.min),
2898 partial_demand_sums_rmq_[layer - 1].begin() + end_index - window_size,
2899 partial_demand_sums_rmq_[layer - 1].begin() + end_index,
2900 partial_demand_sums_rmq_[layer].begin() + end_index - window_size);
2910 UnaryDimensionChecker::Interval
2911 UnaryDimensionChecker::GetMinMaxPartialDemandSum(
int first_node_index,
2912 int last_node_index)
const {
2913 DCHECK_LT(first_node_index, last_node_index);
2918 const int window_size = 1 << layer;
2920 const Interval i1 = partial_demand_sums_rmq_[layer][first_node_index];
2922 partial_demand_sums_rmq_[layer][last_node_index - window_size + 1];
2926 bool UnaryDimensionChecker::SubpathOnlyHasTrivialNodes(
2927 int first_node_index,
int last_node_index)
const {
2928 DCHECK_LE(first_node_index, last_node_index);
2929 return first_node_index > previous_nontrivial_index_[last_node_index];
2934 class UnaryDimensionFilter :
public LocalSearchFilter {
2936 std::string DebugString()
const override {
return "UnaryDimensionFilter"; }
2937 explicit UnaryDimensionFilter(std::unique_ptr<UnaryDimensionChecker> checker)
2938 : checker_(std::move(checker)) {}
2940 bool Accept(
const Assignment*
delta,
const Assignment* deltadelta,
2941 int64 objective_min,
int64 objective_max)
override {
2942 return checker_->Check();
2945 void Synchronize(
const Assignment* assignment,
2946 const Assignment*
delta)
override {
2951 std::unique_ptr<UnaryDimensionChecker> checker_;
2957 Solver* solver, std::unique_ptr<UnaryDimensionChecker> checker) {
2958 UnaryDimensionFilter* filter =
new UnaryDimensionFilter(std::move(checker));
2959 return solver->RevAlloc(filter);
2966 class VariableDomainFilter :
public LocalSearchFilter {
2968 VariableDomainFilter() {}
2969 ~VariableDomainFilter()
override {}
2970 bool Accept(
const Assignment*
delta,
const Assignment* deltadelta,
2971 int64 objective_min,
int64 objective_max)
override;
2972 void Synchronize(
const Assignment* assignment,
2973 const Assignment*
delta)
override {}
2975 std::string DebugString()
const override {
return "VariableDomainFilter"; }
2978 bool VariableDomainFilter::Accept(
const Assignment*
delta,
2979 const Assignment* deltadelta,
2981 const Assignment::IntContainer& container =
delta->IntVarContainer();
2982 const int size = container.Size();
2983 for (
int i = 0; i < size; ++i) {
2984 const IntVarElement& element = container.Element(i);
2985 if (element.Activated() && !element.Var()->Contains(element.Value())) {
2993 LocalSearchFilter* Solver::MakeVariableDomainFilter() {
2994 return RevAlloc(
new VariableDomainFilter());
2999 const int IntVarLocalSearchFilter::kUnassigned = -1;
3002 const std::vector<IntVar*>& vars) {
3007 if (!vars.empty()) {
3008 for (
int i = 0; i < vars.size(); ++i) {
3009 const int index = vars[i]->index();
3010 if (
index >= var_index_to_index_.size()) {
3011 var_index_to_index_.resize(
index + 1, kUnassigned);
3013 var_index_to_index_[
index] = i + vars_.size();
3015 vars_.insert(vars_.end(), vars.begin(), vars.end());
3016 values_.resize(vars_.size(), 0);
3017 var_synced_.resize(vars_.size(),
false);
3024 const Assignment*
delta) {
3026 var_synced_.assign(var_synced_.size(),
false);
3035 const Assignment* assignment) {
3036 const Assignment::IntContainer& container = assignment->IntVarContainer();
3037 const int size = container.Size();
3038 for (
int i = 0; i < size; ++i) {
3039 const IntVarElement& element = container.Element(i);
3040 IntVar*
const var = element.Var();
3041 if (
var !=
nullptr) {
3042 if (i < vars_.size() && vars_[i] ==
var) {
3043 values_[i] = element.Value();
3044 var_synced_[i] =
true;
3046 const int64 kUnallocated = -1;
3049 values_[
index] = element.Value();
3050 var_synced_[
index] =
true;
3069 SumObjectiveFilter(
const std::vector<IntVar*>& vars,
3070 Solver::LocalSearchFilterBound filter_enum)
3079 for (
int i = 0; i < vars.size(); ++i) {
3084 ~SumObjectiveFilter()
override {
3088 bool Accept(
const Assignment*
delta,
const Assignment* deltadelta,
3089 int64 objective_min,
int64 objective_max)
override {
3090 if (
delta ==
nullptr) {
3093 if (deltadelta->Empty()) {
3124 LOG(ERROR) <<
"Unknown local search filter enum value";
3135 virtual bool FillCostOfBoundDeltaVariable(
3136 const Assignment::IntContainer& container,
int index,
3137 int* container_index,
int64* new_cost) = 0;
3138 bool IsIncremental()
const override {
return true; }
3140 std::string DebugString()
const override {
return "SumObjectiveFilter"; }
3142 int64 GetSynchronizedObjectiveValue()
const override {
3145 int64 GetAcceptedObjectiveValue()
const override {
return delta_sum_; }
3157 void OnSynchronize(
const Assignment*
delta)
override {
3160 const int64 cost = CostOfSynchronizedVariable(i);
3168 int64 CostOfChanges(
const Assignment* changes,
const int64*
const old_costs,
3169 bool cache_delta_values) {
3170 int64 total_cost = 0;
3171 const Assignment::IntContainer& container = changes->IntVarContainer();
3172 const int size = container.Size();
3173 for (
int i = 0; i < size; ++i) {
3174 const IntVarElement& new_element = container.Element(i);
3175 IntVar*
const var = new_element.Var();
3178 total_cost =
CapSub(total_cost, old_costs[
index]);
3179 int64 new_cost = 0LL;
3180 if (FillCostOfBoundDeltaVariable(container,
index, &i, &new_cost)) {
3181 total_cost =
CapAdd(total_cost, new_cost);
3183 if (cache_delta_values) {
3192 class BinaryObjectiveFilter :
public SumObjectiveFilter {
3194 BinaryObjectiveFilter(
const std::vector<IntVar*>& vars,
3195 Solver::IndexEvaluator2 value_evaluator,
3196 Solver::LocalSearchFilterBound filter_enum)
3197 : SumObjectiveFilter(vars, filter_enum),
3198 value_evaluator_(std::move(value_evaluator)) {}
3199 ~BinaryObjectiveFilter()
override {}
3205 bool FillCostOfBoundDeltaVariable(
const Assignment::IntContainer& container,
3206 int index,
int* container_index,
3207 int64* new_cost)
override {
3208 const IntVarElement& element = container.Element(*container_index);
3209 if (element.Activated()) {
3210 *new_cost = value_evaluator_(
index, element.Value());
3213 const IntVar*
var = element.Var();
3215 *new_cost = value_evaluator_(
index,
var->Min());
3224 Solver::IndexEvaluator2 value_evaluator_;
3227 class TernaryObjectiveFilter :
public SumObjectiveFilter {
3229 TernaryObjectiveFilter(
const std::vector<IntVar*>& vars,
3230 const std::vector<IntVar*>& secondary_vars,
3231 Solver::IndexEvaluator3 value_evaluator,
3232 Solver::LocalSearchFilterBound filter_enum)
3233 : SumObjectiveFilter(vars, filter_enum),
3234 secondary_vars_offset_(vars.size()),
3235 value_evaluator_(std::move(value_evaluator)) {
3239 ~TernaryObjectiveFilter()
override {}
3241 DCHECK_LT(
index, secondary_vars_offset_);
3245 index + secondary_vars_offset_))
3248 bool FillCostOfBoundDeltaVariable(
const Assignment::IntContainer& container,
3249 int index,
int* container_index,
3250 int64* new_cost)
override {
3251 DCHECK_LT(
index, secondary_vars_offset_);
3253 const IntVarElement& element = container.Element(*container_index);
3254 const IntVar* secondary_var =
3256 if (element.Activated()) {
3258 int hint_index = *container_index + 1;
3259 if (hint_index < container.Size() &&
3260 secondary_var == container.Element(hint_index).Var()) {
3262 container.Element(hint_index).Value());
3263 *container_index = hint_index;
3266 container.Element(secondary_var).Value());
3270 const IntVar*
var = element.Var();
3271 if (
var->Bound() && secondary_var->Bound()) {
3272 *new_cost = value_evaluator_(
index,
var->Min(), secondary_var->Min());
3281 int secondary_vars_offset_;
3282 Solver::IndexEvaluator3 value_evaluator_;
3286 IntVarLocalSearchFilter* Solver::MakeSumObjectiveFilter(
3287 const std::vector<IntVar*>& vars, Solver::IndexEvaluator2 values,
3288 Solver::LocalSearchFilterBound filter_enum) {
3290 new BinaryObjectiveFilter(vars, std::move(values), filter_enum));
3293 IntVarLocalSearchFilter* Solver::MakeSumObjectiveFilter(
3294 const std::vector<IntVar*>& vars,
3295 const std::vector<IntVar*>& secondary_vars, Solver::IndexEvaluator3 values,
3296 Solver::LocalSearchFilterBound filter_enum) {
3297 return RevAlloc(
new TernaryObjectiveFilter(vars, secondary_vars,
3298 std::move(values), filter_enum));
3302 int64 initial_max) {
3303 DCHECK(state_is_valid_);
3304 DCHECK_LE(initial_min, initial_max);
3305 initial_variable_bounds_.push_back({initial_min, initial_max});
3306 variable_bounds_.push_back({initial_min, initial_max});
3307 variable_is_relaxed_.push_back(
false);
3309 const int variable_index = variable_bounds_.size() - 1;
3310 return {
this, variable_index};
3313 void LocalSearchState::RelaxVariableBounds(
int variable_index) {
3314 DCHECK(state_is_valid_);
3315 DCHECK(0 <= variable_index && variable_index < variable_is_relaxed_.size());
3316 if (!variable_is_relaxed_[variable_index]) {
3317 variable_is_relaxed_[variable_index] =
true;
3318 saved_variable_bounds_trail_.emplace_back(variable_bounds_[variable_index],
3320 variable_bounds_[variable_index] = initial_variable_bounds_[variable_index];
3324 int64 LocalSearchState::VariableMin(
int variable_index)
const {
3325 DCHECK(state_is_valid_);
3326 DCHECK(0 <= variable_index && variable_index < variable_bounds_.size());
3327 return variable_bounds_[variable_index].min;
3330 int64 LocalSearchState::VariableMax(
int variable_index)
const {
3331 DCHECK(state_is_valid_);
3332 DCHECK(0 <= variable_index && variable_index < variable_bounds_.size());
3333 return variable_bounds_[variable_index].max;
3336 bool LocalSearchState::TightenVariableMin(
int variable_index,
int64 min_value) {
3337 DCHECK(state_is_valid_);
3338 DCHECK(variable_is_relaxed_[variable_index]);
3339 DCHECK(0 <= variable_index && variable_index < variable_bounds_.size());
3340 Bounds&
bounds = variable_bounds_[variable_index];
3341 if (
bounds.max < min_value) {
3342 state_is_valid_ =
false;
3345 return state_is_valid_;
3348 bool LocalSearchState::TightenVariableMax(
int variable_index,
int64 max_value) {
3349 DCHECK(state_is_valid_);
3350 DCHECK(variable_is_relaxed_[variable_index]);
3351 DCHECK(0 <= variable_index && variable_index < variable_bounds_.size());
3352 Bounds&
bounds = variable_bounds_[variable_index];
3353 if (
bounds.min > max_value) {
3354 state_is_valid_ =
false;
3357 return state_is_valid_;
3364 DCHECK(state_is_valid_);
3365 saved_variable_bounds_trail_.clear();
3366 variable_is_relaxed_.assign(variable_is_relaxed_.size(),
false);
3370 for (
const auto& bounds_index : saved_variable_bounds_trail_) {
3371 DCHECK(variable_is_relaxed_[bounds_index.second]);
3372 variable_bounds_[bounds_index.second] = bounds_index.first;
3374 saved_variable_bounds_trail_.clear();
3375 variable_is_relaxed_.assign(variable_is_relaxed_.size(),
false);
3376 state_is_valid_ =
true;
3384 std::string
DebugString()
const override {
return "LocalSearchProfiler"; }
3386 operator_stats_.clear();
3387 filter_stats_.clear();
3391 if (solver()->TopLevelSearch() == solver()->ActiveSearch()) {
3396 LocalSearchStatistics statistics_proto;
3397 for (
const auto& operator_stats : operator_stats_) {
3399 const OperatorStats& stats = operator_stats.second;
3400 LocalSearchStatistics::LocalSearchOperatorStatistics*
const
3401 local_search_operator_statistics =
3402 statistics_proto.add_local_search_operator_statistics();
3403 local_search_operator_statistics->set_local_search_operator(
3405 local_search_operator_statistics->set_num_neighbors(stats.neighbors);
3406 local_search_operator_statistics->set_num_filtered_neighbors(
3407 stats.filtered_neighbors);
3408 local_search_operator_statistics->set_num_accepted_neighbors(
3409 stats.accepted_neighbors);
3410 local_search_operator_statistics->set_duration_seconds(stats.seconds);
3412 return statistics_proto;
3415 size_t max_name_size = 0;
3416 std::vector<const LocalSearchOperator*> operators;
3417 for (
const auto& stat : operator_stats_) {
3418 operators.push_back(stat.first);
3420 std::max(max_name_size, stat.first->DebugString().length());
3423 operators.begin(), operators.end(),
3425 return gtl::FindOrDie(operator_stats_, op1).neighbors >
3426 gtl::FindOrDie(operator_stats_, op2).neighbors;
3428 std::string overview =
"Local search operator statistics:\n";
3429 absl::StrAppendFormat(&overview,
3430 "%*s | Neighbors | Filtered | Accepted | Time (s)\n",
3432 OperatorStats total_stats;
3434 const OperatorStats& stats =
gtl::FindOrDie(operator_stats_, op);
3435 const std::string&
name = op->DebugString();
3436 absl::StrAppendFormat(&overview,
"%*s | %9ld | %8ld | %8ld | %7.2g\n",
3437 max_name_size,
name, stats.neighbors,
3438 stats.filtered_neighbors, stats.accepted_neighbors,
3440 total_stats.neighbors += stats.neighbors;
3441 total_stats.filtered_neighbors += stats.filtered_neighbors;
3442 total_stats.accepted_neighbors += stats.accepted_neighbors;
3443 total_stats.seconds += stats.seconds;
3445 absl::StrAppendFormat(&overview,
"%*s | %9ld | %8ld | %8ld | %7.2g\n",
3446 max_name_size,
"Total", total_stats.neighbors,
3447 total_stats.filtered_neighbors,
3448 total_stats.accepted_neighbors, total_stats.seconds);
3450 std::vector<const LocalSearchFilter*> filters;
3451 for (
const auto& stat : filter_stats_) {
3452 filters.push_back(stat.first);
3454 std::max(max_name_size, stat.first->DebugString().length());
3456 std::sort(filters.begin(), filters.end(),
3459 return gtl::FindOrDie(filter_stats_, filter1).calls >
3460 gtl::FindOrDie(filter_stats_, filter2).calls;
3462 absl::StrAppendFormat(&overview,
3463 "Local search filter statistics:\n%*s | Calls | "
3464 " Rejects | Time (s) "
3467 FilterStats total_filter_stats;
3469 const FilterStats& stats =
gtl::FindOrDie(filter_stats_, filter);
3470 const std::string&
name = filter->DebugString();
3471 absl::StrAppendFormat(&overview,
"%*s | %9ld | %9ld | %7.2g | %7.2g\n",
3472 max_name_size,
name, stats.calls, stats.rejects,
3473 stats.seconds, stats.rejects / stats.seconds);
3474 total_filter_stats.calls += stats.calls;
3475 total_filter_stats.rejects += stats.rejects;
3476 total_filter_stats.seconds += stats.seconds;
3478 absl::StrAppendFormat(
3479 &overview,
"%*s | %9ld | %9ld | %7.2g | %7.2g\n", max_name_size,
3480 "Total", total_filter_stats.calls, total_filter_stats.rejects,
3481 total_filter_stats.seconds,
3482 total_filter_stats.rejects / total_filter_stats.seconds);
3488 if (last_operator_ != op->
Self()) {
3490 last_operator_ = op->
Self();
3494 const Assignment*
delta,
3495 const Assignment* deltadelta)
override {
3496 if (neighbor_found) {
3497 operator_stats_[op->
Self()].neighbors++;
3502 bool neighbor_found)
override {
3503 if (neighbor_found) {
3504 operator_stats_[op->
Self()].filtered_neighbors++;
3509 bool neighbor_found)
override {
3510 if (neighbor_found) {
3511 operator_stats_[op->
Self()].accepted_neighbors++;
3515 filter_stats_[filter].calls++;
3516 filter_timer_.
Start();
3519 filter_timer_.
Stop();
3520 auto& stats = filter_stats_[filter];
3521 stats.seconds += filter_timer_.
Get();
3526 void Install()
override { SearchMonitor::Install(); }
3530 if (last_operator_ !=
nullptr) {
3532 operator_stats_[last_operator_].seconds += timer_.
Get();
3537 struct OperatorStats {
3538 int64 neighbors = 0;
3539 int64 filtered_neighbors = 0;
3540 int64 accepted_neighbors = 0;
3544 struct FilterStats {
3551 const LocalSearchOperator* last_operator_ =
nullptr;
3552 absl::flat_hash_map<const LocalSearchOperator*, OperatorStats>
3554 absl::flat_hash_map<const LocalSearchFilter*, FilterStats> filter_stats_;
3562 if (solver->IsLocalSearchProfilingEnabled()) {
3571 std::string Solver::LocalSearchProfile()
const {
3572 if (local_search_profiler_ !=
nullptr) {
3578 LocalSearchStatistics Solver::GetLocalSearchStatistics()
const {
3579 if (local_search_profiler_ !=
nullptr) {
3580 return local_search_profiler_->ExportToLocalSearchStatistics();
3582 return LocalSearchStatistics();
3585 void LocalSearchFilterManager::InitializeForcedEvents() {
3586 const int num_events = filter_events_.size();
3587 int next_forced_event = num_events;
3588 next_forced_events_.resize(num_events);
3589 for (
int i = num_events - 1; i >= 0; --i) {
3590 next_forced_events_[i] = next_forced_event;
3591 if (filter_events_[i].filter->IsIncremental() ||
3592 (filter_events_[i].event_type == FilterEventType::kRelax &&
3593 next_forced_event != num_events)) {
3594 next_forced_event = i;
3600 std::vector<LocalSearchFilter*> filters)
3602 filter_events_.reserve(2 * filters.size());
3604 filter_events_.push_back({filter, FilterEventType::kRelax});
3607 filter_events_.push_back({filter, FilterEventType::kAccept});
3609 InitializeForcedEvents();
3613 std::vector<FilterEvent> filter_events)
3614 : filter_events_(std::move(filter_events)),
3617 InitializeForcedEvents();
3623 for (
int i = last_event_called_; i >= 0; --i) {
3624 auto [filter, event_type] = filter_events_[i];
3625 if (event_type == FilterEventType::kRelax) filter->Revert();
3627 last_event_called_ = -1;
3634 const Assignment*
delta,
3635 const Assignment* deltadelta,
3636 int64 objective_min,
3637 int64 objective_max) {
3639 accepted_value_ = 0;
3641 const int num_events = filter_events_.size();
3642 for (
int i = 0; i < num_events;) {
3643 last_event_called_ = i;
3644 auto [filter, event_type] = filter_events_[last_event_called_];
3645 switch (event_type) {
3646 case FilterEventType::kAccept: {
3648 const bool accept = filter->Accept(
3649 delta, deltadelta,
CapSub(objective_min, accepted_value_),
3650 CapSub(objective_max, accepted_value_));
3652 if (monitor !=
nullptr) monitor->
EndFiltering(filter, !accept);
3655 CapAdd(accepted_value_, filter->GetAcceptedObjectiveValue());
3657 ok = accepted_value_ <= objective_max;
3661 case FilterEventType::kRelax: {
3662 filter->Relax(
delta, deltadelta);
3666 LOG(FATAL) <<
"Unknown filter event type.";
3672 i = next_forced_events_[i];
3679 const Assignment*
delta) {
3680 synchronized_value_ = 0;
3682 switch (event_type) {
3683 case FilterEventType::kAccept: {
3684 filter->Synchronize(assignment,
delta);
3685 synchronized_value_ =
CapAdd(synchronized_value_,
3686 filter->GetSynchronizedObjectiveValue());
3689 case FilterEventType::kRelax: {
3690 filter->Commit(assignment,
delta);
3694 LOG(FATAL) <<
"Unknown filter event type.";
3700 std::vector<LocalSearchFilter*> filters) {
3709 SolutionPool*
const pool,
3711 DecisionBuilder*
const sub_decision_builder,
3712 const RegularLimit*
const limit,
3715 Decision*
Next(Solver*
const solver)
override;
3716 std::string
DebugString()
const override {
return "FindOneNeighbor"; }
3719 bool FilterAccept(Solver* solver, Assignment*
delta, Assignment* deltadelta,
3721 void SynchronizeAll(Solver* solver,
bool synchronize_filters =
true);
3723 Assignment*
const assignment_;
3724 IntVar*
const objective_;
3725 std::unique_ptr<Assignment> reference_assignment_;
3726 SolutionPool*
const pool_;
3728 DecisionBuilder*
const sub_decision_builder_;
3729 RegularLimit* limit_;
3730 const RegularLimit*
const original_limit_;
3731 bool neighbor_found_;
3733 int64 solutions_since_last_check_;
3734 int64 check_period_;
3735 Assignment last_checked_assignment_;
3736 bool has_checked_assignment_ =
false;
3743 IntVar* objective, SolutionPool*
const pool,
3745 DecisionBuilder*
const sub_decision_builder,
3746 const RegularLimit*
const limit,
3748 : assignment_(assignment),
3750 reference_assignment_(new Assignment(assignment_)),
3752 ls_operator_(ls_operator),
3753 sub_decision_builder_(sub_decision_builder),
3755 original_limit_(limit),
3756 neighbor_found_(false),
3757 filter_manager_(filter_manager),
3758 solutions_since_last_check_(0),
3760 assignment_->solver()->
parameters().check_solution_period()),
3761 last_checked_assignment_(assignment) {
3762 CHECK(
nullptr != assignment);
3763 CHECK(
nullptr != ls_operator);
3765 Solver*
const solver = assignment_->solver();
3767 if (
nullptr == limit) {
3768 limit_ = solver->MakeSolutionsLimit(1);
3770 limit_ = limit->MakeIdenticalClone();
3774 if (limit_->solutions() != 1) {
3775 VLOG(1) <<
"Disabling neighbor-check skipping outside of first accept.";
3782 VLOG(1) <<
"Disabling neighbor-check skipping for LNS.";
3788 CHECK(
nullptr != solver);
3790 if (original_limit_ !=
nullptr) {
3791 limit_->Copy(original_limit_);
3794 if (!last_checked_assignment_.HasObjective()) {
3795 last_checked_assignment_.AddObjective(assignment_->Objective());
3798 if (!neighbor_found_) {
3805 pool_->Initialize(assignment_);
3806 SynchronizeAll(solver,
false);
3811 Assignment* assignment_copy =
3812 solver->MakeAssignment(reference_assignment_.get());
3815 DecisionBuilder* restore = solver->MakeRestoreAssignment(assignment_copy);
3816 if (sub_decision_builder_) {
3817 restore = solver->Compose(restore, sub_decision_builder_);
3819 Assignment*
delta = solver->MakeAssignment();
3820 Assignment* deltadelta = solver->MakeAssignment();
3825 delta->ClearObjective();
3826 deltadelta->Clear();
3827 solver->TopPeriodicCheck();
3828 if (++counter >= FLAGS_cp_local_search_sync_frequency &&
3829 pool_->SyncNeeded(reference_assignment_.get())) {
3832 SynchronizeAll(solver);
3835 bool has_neighbor =
false;
3836 if (!limit_->Check()) {
3837 solver->GetLocalSearchMonitor()->BeginMakeNextNeighbor(ls_operator_);
3839 solver->GetLocalSearchMonitor()->EndMakeNextNeighbor(
3840 ls_operator_, has_neighbor,
delta, deltadelta);
3843 if (has_neighbor && !solver->IsUncheckedSolutionLimitReached()) {
3844 solver->neighbors_ += 1;
3850 solver->GetLocalSearchMonitor()->BeginFilterNeighbor(ls_operator_);
3851 const bool mh_filter =
3856 objective_min = objective_->Min();
3857 objective_max = objective_->Max();
3859 if (
delta->HasObjective() &&
delta->Objective() == objective_) {
3860 objective_min =
std::max(objective_min,
delta->ObjectiveMin());
3861 objective_max =
std::min(objective_max,
delta->ObjectiveMax());
3863 const bool move_filter = FilterAccept(solver,
delta, deltadelta,
3864 objective_min, objective_max);
3865 solver->GetLocalSearchMonitor()->EndFilterNeighbor(
3866 ls_operator_, mh_filter && move_filter);
3867 if (!mh_filter || !move_filter) {
3868 if (filter_manager_ !=
nullptr) filter_manager_->
Revert();
3871 solver->filtered_neighbors_ += 1;
3872 if (
delta->HasObjective()) {
3873 if (!assignment_copy->HasObjective()) {
3874 assignment_copy->AddObjective(
delta->Objective());
3876 if (!assignment_->HasObjective()) {
3877 assignment_->AddObjective(
delta->Objective());
3878 last_checked_assignment_.AddObjective(
delta->Objective());
3881 assignment_copy->CopyIntersection(reference_assignment_.get());
3882 assignment_copy->CopyIntersection(
delta);
3883 solver->GetLocalSearchMonitor()->BeginAcceptNeighbor(ls_operator_);
3884 const bool check_solution = (solutions_since_last_check_ == 0) ||
3885 !solver->UseFastLocalSearch() ||
3887 !
delta->AreAllElementsBound();
3888 if (has_checked_assignment_) solutions_since_last_check_++;
3889 if (solutions_since_last_check_ >= check_period_) {
3890 solutions_since_last_check_ = 0;
3892 const bool accept = !check_solution || solver->SolveAndCommit(restore);
3893 solver->GetLocalSearchMonitor()->EndAcceptNeighbor(ls_operator_,
3896 solver->accepted_neighbors_ += 1;
3897 if (check_solution) {
3898 solver->SetSearchContext(solver->ParentSearch(),
3899 ls_operator_->DebugString());
3900 assignment_->Store();
3901 last_checked_assignment_.CopyIntersection(assignment_);
3902 neighbor_found_ =
true;
3903 has_checked_assignment_ =
true;
3906 solver->SetSearchContext(solver->ActiveSearch(),
3907 ls_operator_->DebugString());
3908 assignment_->CopyIntersection(assignment_copy);
3909 assignment_->SetObjectiveValue(
3917 solver->IncrementUncheckedSolutionCounter();
3918 pool_->RegisterNewSolution(assignment_);
3919 SynchronizeAll(solver);
3922 neighbor_found_ =
true;
3925 if (filter_manager_ !=
nullptr) filter_manager_->
Revert();
3926 if (check_period_ > 1 && has_checked_assignment_) {
3932 VLOG(1) <<
"Imperfect filtering detected, backtracking to last "
3933 "checked solution and checking all solutions.";
3935 solutions_since_last_check_ = 0;
3936 pool_->RegisterNewSolution(&last_checked_assignment_);
3937 SynchronizeAll(solver);
3938 assignment_->CopyIntersection(&last_checked_assignment_);
3942 if (neighbor_found_) {
3947 if (last_checked_assignment_.ObjectiveValue() !=
3948 assignment_->ObjectiveValue()) {
3951 assignment_copy->CopyIntersection(assignment_);
3952 if (!solver->SolveAndCommit(restore)) solver->Fail();
3953 last_checked_assignment_.CopyIntersection(assignment_);
3954 has_checked_assignment_ =
true;
3961 pool_->RegisterNewSolution(assignment_);
3962 SynchronizeAll(solver);
3973 bool FindOneNeighbor::FilterAccept(Solver* solver, Assignment*
delta,
3974 Assignment* deltadelta,
int64 objective_min,
3975 int64 objective_max) {
3976 if (filter_manager_ ==
nullptr)
return true;
3978 return filter_manager_->
Accept(monitor,
delta, deltadelta, objective_min,
3982 void FindOneNeighbor::SynchronizeAll(Solver* solver,
bool synchronize_filters) {
3983 pool_->GetNextSolution(reference_assignment_.get());
3984 neighbor_found_ =
false;
3986 solver->GetLocalSearchMonitor()->BeginOperatorStart();
3987 ls_operator_->
Start(reference_assignment_.get());
3988 if (synchronize_filters && filter_manager_ !=
nullptr) {
3989 filter_manager_->
Synchronize(reference_assignment_.get(),
nullptr);
3991 solver->GetLocalSearchMonitor()->EndOperatorStart();
4001 RegularLimit*
const limit,
4004 solution_pool_(pool),
4011 return "LocalSearchPhaseParameters";
4018 return sub_decision_builder_;
4020 RegularLimit*
limit()
const {
return limit_; }
4022 return filter_manager_;
4026 IntVar*
const objective_;
4027 SolutionPool*
const solution_pool_;
4029 DecisionBuilder*
const sub_decision_builder_;
4030 RegularLimit*
const limit_;
4034 LocalSearchPhaseParameters* Solver::MakeLocalSearchPhaseParameters(
4035 IntVar* objective, LocalSearchOperator*
const ls_operator,
4036 DecisionBuilder*
const sub_decision_builder) {
4037 return MakeLocalSearchPhaseParameters(objective, MakeDefaultSolutionPool(),
4038 ls_operator, sub_decision_builder,
4042 LocalSearchPhaseParameters* Solver::MakeLocalSearchPhaseParameters(
4043 IntVar* objective, LocalSearchOperator*
const ls_operator,
4044 DecisionBuilder*
const sub_decision_builder, RegularLimit*
const limit) {
4045 return MakeLocalSearchPhaseParameters(objective, MakeDefaultSolutionPool(),
4046 ls_operator, sub_decision_builder,
4050 LocalSearchPhaseParameters* Solver::MakeLocalSearchPhaseParameters(
4051 IntVar* objective, LocalSearchOperator*
const ls_operator,
4052 DecisionBuilder*
const sub_decision_builder, RegularLimit*
const limit,
4053 LocalSearchFilterManager* filter_manager) {
4054 return MakeLocalSearchPhaseParameters(objective, MakeDefaultSolutionPool(),
4055 ls_operator, sub_decision_builder,
4056 limit, filter_manager);
4059 LocalSearchPhaseParameters* Solver::MakeLocalSearchPhaseParameters(
4060 IntVar* objective, SolutionPool*
const pool,
4061 LocalSearchOperator*
const ls_operator,
4062 DecisionBuilder*
const sub_decision_builder) {
4063 return MakeLocalSearchPhaseParameters(objective, pool, ls_operator,
4064 sub_decision_builder,
nullptr,
nullptr);
4067 LocalSearchPhaseParameters* Solver::MakeLocalSearchPhaseParameters(
4068 IntVar* objective, SolutionPool*
const pool,
4069 LocalSearchOperator*
const ls_operator,
4070 DecisionBuilder*
const sub_decision_builder, RegularLimit*
const limit) {
4071 return MakeLocalSearchPhaseParameters(objective, pool, ls_operator,
4072 sub_decision_builder, limit,
nullptr);
4075 LocalSearchPhaseParameters* Solver::MakeLocalSearchPhaseParameters(
4076 IntVar* objective, SolutionPool*
const pool,
4077 LocalSearchOperator*
const ls_operator,
4078 DecisionBuilder*
const sub_decision_builder, RegularLimit*
const limit,
4079 LocalSearchFilterManager* filter_manager) {
4080 return RevAlloc(
new LocalSearchPhaseParameters(objective, pool, ls_operator,
4081 sub_decision_builder, limit,
4095 class NestedSolveDecision :
public Decision {
4098 enum StateType { DECISION_PENDING, DECISION_FAILED, DECISION_FOUND };
4100 NestedSolveDecision(DecisionBuilder*
const db,
bool restore,
4101 const std::vector<SearchMonitor*>& monitors);
4102 NestedSolveDecision(DecisionBuilder*
const db,
bool restore);
4103 ~NestedSolveDecision()
override {}
4104 void Apply(Solver*
const solver)
override;
4105 void Refute(Solver*
const solver)
override;
4106 std::string DebugString()
const override {
return "NestedSolveDecision"; }
4107 int state()
const {
return state_; }
4110 DecisionBuilder*
const db_;
4112 std::vector<SearchMonitor*> monitors_;
4116 NestedSolveDecision::NestedSolveDecision(
4117 DecisionBuilder*
const db,
bool restore,
4118 const std::vector<SearchMonitor*>& monitors)
4121 monitors_(monitors),
4122 state_(DECISION_PENDING) {
4123 CHECK(
nullptr != db);
4126 NestedSolveDecision::NestedSolveDecision(DecisionBuilder*
const db,
4128 : db_(db), restore_(restore), state_(DECISION_PENDING) {
4129 CHECK(
nullptr != db);
4132 void NestedSolveDecision::Apply(Solver*
const solver) {
4133 CHECK(
nullptr != solver);
4135 if (solver->Solve(db_, monitors_)) {
4136 solver->SaveAndSetValue(&state_,
static_cast<int>(DECISION_FOUND));
4138 solver->SaveAndSetValue(&state_,
static_cast<int>(DECISION_FAILED));
4141 if (solver->SolveAndCommit(db_, monitors_)) {
4142 solver->SaveAndSetValue(&state_,
static_cast<int>(DECISION_FOUND));
4144 solver->SaveAndSetValue(&state_,
static_cast<int>(DECISION_FAILED));
4149 void NestedSolveDecision::Refute(Solver*
const solver) {}
4160 class LocalSearch :
public DecisionBuilder {
4162 LocalSearch(Assignment*
const assignment, IntVar* objective,
4163 SolutionPool*
const pool, LocalSearchOperator*
const ls_operator,
4164 DecisionBuilder*
const sub_decision_builder,
4165 RegularLimit*
const limit,
4166 LocalSearchFilterManager* filter_manager);
4169 LocalSearch(
const std::vector<IntVar*>& vars, IntVar* objective,
4170 SolutionPool*
const pool, DecisionBuilder*
const first_solution,
4171 LocalSearchOperator*
const ls_operator,
4172 DecisionBuilder*
const sub_decision_builder,
4173 RegularLimit*
const limit,
4174 LocalSearchFilterManager* filter_manager);
4175 LocalSearch(
const std::vector<IntVar*>& vars, IntVar* objective,
4176 SolutionPool*
const pool, DecisionBuilder*
const first_solution,
4177 DecisionBuilder*
const first_solution_sub_decision_builder,
4178 LocalSearchOperator*
const ls_operator,
4179 DecisionBuilder*
const sub_decision_builder,
4180 RegularLimit*
const limit,
4181 LocalSearchFilterManager* filter_manager);
4182 LocalSearch(
const std::vector<SequenceVar*>& vars, IntVar* objective,
4183 SolutionPool*
const pool, DecisionBuilder*
const first_solution,
4184 LocalSearchOperator*
const ls_operator,
4185 DecisionBuilder*
const sub_decision_builder,
4186 RegularLimit*
const limit,
4187 LocalSearchFilterManager* filter_manager);
4188 ~LocalSearch()
override;
4189 Decision* Next(Solver*
const solver)
override;
4190 std::string DebugString()
const override {
return "LocalSearch"; }
4191 void Accept(ModelVisitor*
const visitor)
const override;
4194 void PushFirstSolutionDecision(DecisionBuilder* first_solution);
4195 void PushLocalSearchDecision();
4198 Assignment* assignment_;
4200 SolutionPool*
const pool_;
4201 LocalSearchOperator*
const ls_operator_;
4202 DecisionBuilder*
const first_solution_sub_decision_builder_;
4203 DecisionBuilder*
const sub_decision_builder_;
4204 std::vector<NestedSolveDecision*> nested_decisions_;
4205 int nested_decision_index_;
4206 RegularLimit*
const limit_;
4207 LocalSearchFilterManager*
const filter_manager_;
4211 LocalSearch::LocalSearch(Assignment*
const assignment, IntVar* objective,
4212 SolutionPool*
const pool,
4213 LocalSearchOperator*
const ls_operator,
4214 DecisionBuilder*
const sub_decision_builder,
4215 RegularLimit*
const limit,
4216 LocalSearchFilterManager* filter_manager)
4217 : assignment_(nullptr),
4220 ls_operator_(ls_operator),
4221 first_solution_sub_decision_builder_(sub_decision_builder),
4222 sub_decision_builder_(sub_decision_builder),
4223 nested_decision_index_(0),
4225 filter_manager_(filter_manager),
4226 has_started_(false) {
4227 CHECK(
nullptr != assignment);
4229 Solver*
const solver = assignment->solver();
4230 assignment_ = solver->GetOrCreateLocalSearchState();
4231 assignment_->Copy(assignment);
4232 DecisionBuilder* restore = solver->MakeRestoreAssignment(assignment);
4233 PushFirstSolutionDecision(restore);
4234 PushLocalSearchDecision();
4237 LocalSearch::LocalSearch(
const std::vector<IntVar*>& vars, IntVar* objective,
4238 SolutionPool*
const pool,
4239 DecisionBuilder*
const first_solution,
4240 LocalSearchOperator*
const ls_operator,
4241 DecisionBuilder*
const sub_decision_builder,
4242 RegularLimit*
const limit,
4243 LocalSearchFilterManager* filter_manager)
4244 : assignment_(nullptr),
4247 ls_operator_(ls_operator),
4248 first_solution_sub_decision_builder_(sub_decision_builder),
4249 sub_decision_builder_(sub_decision_builder),
4250 nested_decision_index_(0),
4252 filter_manager_(filter_manager),
4253 has_started_(false) {
4254 CHECK(
nullptr != first_solution);
4256 CHECK(!vars.empty());
4257 Solver*
const solver = vars[0]->solver();
4258 assignment_ = solver->GetOrCreateLocalSearchState();
4259 assignment_->Add(vars);
4260 PushFirstSolutionDecision(first_solution);
4261 PushLocalSearchDecision();
4264 LocalSearch::LocalSearch(
4265 const std::vector<IntVar*>& vars, IntVar* objective,
4266 SolutionPool*
const pool, DecisionBuilder*
const first_solution,
4267 DecisionBuilder*
const first_solution_sub_decision_builder,
4268 LocalSearchOperator*
const ls_operator,
4269 DecisionBuilder*
const sub_decision_builder, RegularLimit*
const limit,
4270 LocalSearchFilterManager* filter_manager)
4271 : assignment_(nullptr),
4274 ls_operator_(ls_operator),
4275 first_solution_sub_decision_builder_(first_solution_sub_decision_builder),
4276 sub_decision_builder_(sub_decision_builder),
4277 nested_decision_index_(0),
4279 filter_manager_(filter_manager),
4280 has_started_(false) {
4281 CHECK(
nullptr != first_solution);
4283 CHECK(!vars.empty());
4284 Solver*
const solver = vars[0]->solver();
4285 assignment_ = solver->GetOrCreateLocalSearchState();
4286 assignment_->Add(vars);
4287 PushFirstSolutionDecision(first_solution);
4288 PushLocalSearchDecision();
4291 LocalSearch::LocalSearch(
const std::vector<SequenceVar*>& vars,
4292 IntVar* objective, SolutionPool*
const pool,
4293 DecisionBuilder*
const first_solution,
4294 LocalSearchOperator*
const ls_operator,
4295 DecisionBuilder*
const sub_decision_builder,
4296 RegularLimit*
const limit,
4297 LocalSearchFilterManager* filter_manager)
4298 : assignment_(nullptr),
4301 ls_operator_(ls_operator),
4302 first_solution_sub_decision_builder_(sub_decision_builder),
4303 sub_decision_builder_(sub_decision_builder),
4304 nested_decision_index_(0),
4306 filter_manager_(filter_manager),
4307 has_started_(false) {
4308 CHECK(
nullptr != first_solution);
4310 CHECK(!vars.empty());
4311 Solver*
const solver = vars[0]->solver();
4312 assignment_ = solver->GetOrCreateLocalSearchState();
4313 assignment_->Add(vars);
4314 PushFirstSolutionDecision(first_solution);
4315 PushLocalSearchDecision();
4318 LocalSearch::~LocalSearch() {}
4321 void LocalSearch::Accept(ModelVisitor*
const visitor)
const {
4322 DCHECK(assignment_ !=
nullptr);
4323 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
4325 const std::vector<IntVarElement>& elements =
4326 assignment_->IntVarContainer().elements();
4327 if (!elements.empty()) {
4328 std::vector<IntVar*> vars;
4329 for (
const IntVarElement& elem : elements) {
4330 vars.push_back(elem.Var());
4332 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
4335 const std::vector<IntervalVarElement>& interval_elements =
4336 assignment_->IntervalVarContainer().elements();
4337 if (!interval_elements.empty()) {
4338 std::vector<IntervalVar*> interval_vars;
4339 for (
const IntervalVarElement& elem : interval_elements) {
4340 interval_vars.push_back(elem.Var());
4342 visitor->VisitIntervalArrayArgument(ModelVisitor::kIntervalsArgument,
4345 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
4353 Decision* LocalSearch::Next(Solver*
const solver) {
4354 CHECK(
nullptr != solver);
4355 CHECK_LT(0, nested_decisions_.size());
4356 if (!has_started_) {
4357 nested_decision_index_ = 0;
4358 solver->SaveAndSetValue(&has_started_,
true);
4359 }
else if (nested_decision_index_ < 0) {
4362 NestedSolveDecision* decision = nested_decisions_[nested_decision_index_];
4363 const int state = decision->state();
4365 case NestedSolveDecision::DECISION_FAILED: {
4369 ls_operator_->
Reset();
4371 nested_decision_index_ = -1;
4376 case NestedSolveDecision::DECISION_PENDING: {
4379 const int32 kLocalSearchBalancedTreeDepth = 32;
4380 const int depth = solver->SearchDepth();
4381 if (depth < kLocalSearchBalancedTreeDepth) {
4382 return solver->balancing_decision();
4383 }
else if (depth > kLocalSearchBalancedTreeDepth) {
4388 case NestedSolveDecision::DECISION_FOUND: {
4390 if (nested_decision_index_ + 1 < nested_decisions_.size()) {
4391 ++nested_decision_index_;
4396 LOG(ERROR) <<
"Unknown local search state";
4404 class SynchronizeFiltersDecisionBuilder :
public DecisionBuilder {
4406 SynchronizeFiltersDecisionBuilder(Assignment* assignment,
4407 LocalSearchFilterManager* filter_manager)
4408 : assignment_(assignment), filter_manager_(filter_manager) {}
4410 Decision* Next(Solver*
const solver)
override {
4411 if (filter_manager_ !=
nullptr)
4412 filter_manager_->Synchronize(assignment_,
nullptr);
4417 Assignment*
const assignment_;
4418 LocalSearchFilterManager*
const filter_manager_;
4422 void LocalSearch::PushFirstSolutionDecision(DecisionBuilder* first_solution) {
4423 CHECK(first_solution);
4424 Solver*
const solver = assignment_->solver();
4425 DecisionBuilder* store = solver->MakeStoreAssignment(assignment_);
4426 DecisionBuilder* synchronize = solver->RevAlloc(
4427 new SynchronizeFiltersDecisionBuilder(assignment_, filter_manager_));
4428 DecisionBuilder* first_solution_and_store = solver->Compose(
4429 first_solution, first_solution_sub_decision_builder_, store, synchronize);
4430 std::vector<SearchMonitor*> monitor;
4431 monitor.push_back(
limit_);
4432 nested_decisions_.push_back(solver->RevAlloc(
4433 new NestedSolveDecision(first_solution_and_store,
false, monitor)));
4436 void LocalSearch::PushLocalSearchDecision() {
4437 Solver*
const solver = assignment_->solver();
4438 DecisionBuilder* find_neighbors = solver->RevAlloc(
4439 new FindOneNeighbor(assignment_,
objective_, pool_, ls_operator_,
4440 sub_decision_builder_,
limit_, filter_manager_));
4441 nested_decisions_.push_back(
4442 solver->RevAlloc(
new NestedSolveDecision(find_neighbors,
false)));
4445 class DefaultSolutionPool :
public SolutionPool {
4447 DefaultSolutionPool() {}
4449 ~DefaultSolutionPool()
override {}
4451 void Initialize(Assignment*
const assignment)
override {
4452 reference_assignment_ = absl::make_unique<Assignment>(assignment);
4455 void RegisterNewSolution(Assignment*
const assignment)
override {
4456 reference_assignment_->CopyIntersection(assignment);
4459 void GetNextSolution(Assignment*
const assignment)
override {
4460 assignment->CopyIntersection(reference_assignment_.get());
4463 bool SyncNeeded(Assignment*
const local_assignment)
override {
return false; }
4465 std::string DebugString()
const override {
return "DefaultSolutionPool"; }
4468 std::unique_ptr<Assignment> reference_assignment_;
4472 SolutionPool* Solver::MakeDefaultSolutionPool() {
4473 return RevAlloc(
new DefaultSolutionPool());
4476 DecisionBuilder* Solver::MakeLocalSearchPhase(
4477 Assignment* assignment, LocalSearchPhaseParameters*
parameters) {
4478 return RevAlloc(
new LocalSearch(
4484 DecisionBuilder* Solver::MakeLocalSearchPhase(
4485 const std::vector<IntVar*>& vars, DecisionBuilder* first_solution,
4487 return RevAlloc(
new LocalSearch(
4494 DecisionBuilder* Solver::MakeLocalSearchPhase(
4495 const std::vector<IntVar*>& vars, DecisionBuilder* first_solution,
4496 DecisionBuilder* first_solution_sub_decision_builder,
4498 return RevAlloc(
new LocalSearch(
4500 first_solution, first_solution_sub_decision_builder,
4505 DecisionBuilder* Solver::MakeLocalSearchPhase(
4506 const std::vector<SequenceVar*>& vars, DecisionBuilder* first_solution,
4508 return RevAlloc(
new LocalSearch(