Google OR-Tools: ortools/sat/synchronization.h Source File
168 absl::MutexLock mutex_lock(mutex_);
179 absl::MutexLock mutex_lock(mutex_);
239 : best_solutions_(parameters_.solution_pool_size(), "best_solutions"),
240 alternative_path_(parameters_.alternative_pool_size(),
252 std::shared_ptr<const SharedSolutionRepository<int64_t>::Solution>
256 if (alternative_path_.num_solutions_to_keep() > 0 &&
257 best_solutions_.NumRecentlyNonImproving() > 100 &&
258 absl::Bernoulli(random, 0.5) && alternative_path_.NumSolutions() > 0) {
261 auto result = alternative_path_.GetRandomBiasedSolution(random);
262 if (result != nullptr) return result;
265 if (best_solutions_.NumSolutions() > 0) {
271 std::shared_ptr<const SharedSolutionRepository<int64_t>::Solution> Add(
274 void Synchronize(absl::BitGenRef random);
276 void AddTableStats(std::vector<std::vector<std::string>>* table) const {
277 table->push_back(best_solutions_.TableLineStats());
295 int64_t max_rank_ ABSL_GUARDED_BY(mutex_) =
296 std::numeric_limits<int64_t>::min();
297 int64_t min_rank_ ABSL_GUARDED_BY(mutex_) =
298 std::numeric_limits<int64_t>::max();
299 std::vector<int64_t> ranks_;
301 std::shared_ptr<const SharedSolutionRepository<int64_t>::Solution>>
339 void AddSolution(const std::vector<double>& lp_solution);
344 std::vector<double> PopLast();
353 mutable absl::Mutex mutex_;
354 std::deque<std::vector<double>> solutions_ ABSL_GUARDED_BY(mutex_);
355 int64_t num_added_ ABSL_GUARDED_BY(mutex_) = 0;
356 mutable int64_t num_queried_ ABSL_GUARDED_BY(mutex_) = 0;
391 std::function<void(std::vector<int64_t>*)> postprocessor);
442 std::function<std::string(const CpSolverResponse&)> callback);
464 if (solution_pool_.BestSolutions().NumSolutions() > 0) {
507 IntegerValue lb, IntegerValue ub);
513 std::shared_ptr<const SharedSolutionRepository<int64_t>::Solution>
514 NewSolution(absl::Span<const int64_t> solution_values,
515 absl::string_view solution_info, Model* model = nullptr,
528 void AddUnsatCore(const std::vector<int>& core);
549 void LogMessage(absl::string_view prefix, absl::string_view message);
551 absl::string_view message);
565 const std::vector<int64_t>& DebugSolution() const { return debug_solution_; }
568 void TestGapLimitsIfNeeded() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
569 void FillObjectiveValuesInResponse(CpSolverResponse* response) const
570 ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
571 void UpdateGapIntegralInternal() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
574 ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
577 ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
581 absl::Span<const int64_t> variable_values,
582 absl::string_view solution_info) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
590 mutable absl::Mutex mutex_;
593 double absolute_gap_limit_ ABSL_GUARDED_BY(mutex_) = 0.0;
594 double relative_gap_limit_ ABSL_GUARDED_BY(mutex_) = 0.0;
597 CpSolverStatus synchronized_best_status_ ABSL_GUARDED_BY(mutex_) =
599 std::vector<int> unsat_cores_ ABSL_GUARDED_BY(mutex_);
602 int num_solutions_ ABSL_GUARDED_BY(mutex_) = 0;
603 int64_t inner_objective_lower_bound_ ABSL_GUARDED_BY(mutex_) =
604 std::numeric_limits<int64_t>::min();
605 int64_t inner_objective_upper_bound_ ABSL_GUARDED_BY(mutex_) =
606 std::numeric_limits<int64_t>::max();
607 int64_t best_solution_objective_value_ ABSL_GUARDED_BY(mutex_) =
608 std::numeric_limits<int64_t>::max();
610 bool always_synchronize_ ABSL_GUARDED_BY(mutex_) = true;
611 IntegerValue synchronized_inner_objective_lower_bound_ ABSL_GUARDED_BY(
612 mutex_) = IntegerValue(std::numeric_limits<int64_t>::min());
613 IntegerValue synchronized_inner_objective_upper_bound_ ABSL_GUARDED_BY(
614 mutex_) = IntegerValue(std::numeric_limits<int64_t>::max());
616 bool update_integral_on_each_change_ ABSL_GUARDED_BY(mutex_) = false;
617 double gap_integral_ ABSL_GUARDED_BY(mutex_) = 0.0;
618 double last_absolute_gap_ ABSL_GUARDED_BY(mutex_) = 0.0;
619 double last_gap_integral_time_stamp_ ABSL_GUARDED_BY(mutex_) = 0.0;
621 int next_callback_id_ ABSL_GUARDED_BY(mutex_) = 0;
623 callbacks_ ABSL_GUARDED_BY(mutex_);
625 int next_search_log_callback_id_ ABSL_GUARDED_BY(mutex_) = 0;
626 std::vector<
628 search_log_callbacks_ ABSL_GUARDED_BY(mutex_);
630 int next_best_bound_callback_id_ ABSL_GUARDED_BY(mutex_) = 0;
631 std::vector<std::pair<int, std::function<void(double)>>> best_bound_callbacks_
634 std::vector<std::function<void(std::vector<int64_t>*)>>
635 solution_postprocessors_ ABSL_GUARDED_BY(mutex_);
641 statistics_postprocessors_ ABSL_GUARDED_BY(mutex_);
643 status_change_callbacks_ ABSL_GUARDED_BY(mutex_);
646 std::string dump_prefix_;
648 SolverLogger* logger_ ABSL_GUARDED_BY(mutex_);
649 absl::flat_hash_map<std::string, int> throttling_ids_ ABSL_GUARDED_BY(mutex_);
652 std::vector<CpSolverResponse> subsolver_responses_ ABSL_GUARDED_BY(mutex_);
654 std::atomic<bool> first_solution_solvers_should_stop_ = false;
656 std::vector<int64_t> debug_solution_;
669 absl::Span<const int> variables,
670 absl::Span<const int64_t> new_lower_bounds,
671 absl::Span<const int64_t> new_upper_bounds);
683 absl::Span<const int> variables_to_fix);
693 std::vector<int64_t>* new_lower_bounds,
694 std::vector<int64_t>* new_upper_bounds);
698 void UpdateDomains(std::vector<Domain>* domains);
726 std::vector<int64_t> lower_bounds_ ABSL_GUARDED_BY(mutex_);
727 std::vector<int64_t> upper_bounds_ ABSL_GUARDED_BY(mutex_);
730 int64_t total_num_improvements_ ABSL_GUARDED_BY(mutex_) = 0;
733 std::vector<int64_t> synchronized_lower_bounds_ ABSL_GUARDED_BY(mutex_);
734 std::vector<int64_t> synchronized_upper_bounds_ ABSL_GUARDED_BY(mutex_);
735 std::deque<SparseBitset<int>> id_to_changed_variables_
742 int64_t num_symmetric = 0;
744 absl::btree_map<std::string, Counters> bounds_exported_
748 bool has_symmetry_ = false;
749 std::vector<int> var_to_representative_;
750 std::vector<int> var_to_orbit_index_;
751 CompactVectorVector<int, int> orbits_;
791 bool Add(absl::Span<const int> clause, int lbd = 2);
797 bool BlockClause(absl::Span<const int> clause);
812 int NumLiteralsOfSize(int size) const;
813 int NumBufferedLiterals() const;
819 static size_t HashClause(absl::Span<const int> clause, size_t hash_seed = 0);
824 constexpr static size_t kMaxFingerprints = 1024 * 1024 / sizeof(size_t);
825 constexpr static int kNumSizes = kMaxClauseSize - kMinClauseSize + 1;
827 std::vector<int>* MutableBufferForSize(int size) {
828 return &clauses_by_size_[size - kMinClauseSize];
830 absl::Span<const int> BufferForSize(int size) const {
831 return clauses_by_size_[size - kMinClauseSize];
833 absl::Span<const int> NextClause(int size) const;
836 int NumClausesOfSize(int size) const;
838 int lbd_threshold_ = kMinLbd;
839 int64_t dropped_literals_since_last_batch_ = 0;
841 absl::flat_hash_set<size_t> fingerprints_;
842 absl::flat_hash_set<size_t> old_fingerprints_;
843 std::array<std::vector<int>, kNumSizes> clauses_by_size_;
870 std::vector<std::pair<int, int>>* new_clauses);
873 int RegisterNewId(absl::string_view worker_name, bool may_terminate_early);
888 bool ShouldReadBatch(int reader_id, int writer_id)
889 ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
891 static constexpr int kMinBatches = 64;
892 mutable absl::Mutex mutex_;
896 absl::flat_hash_set<std::pair<int, int>> added_binary_clauses_set_
898 std::vector<std::pair<int, int>> added_binary_clauses_
900 std::vector<int> id_to_last_processed_binary_clause_ ABSL_GUARDED_BY(mutex_);
901 int last_visible_binary_clause_ ABSL_GUARDED_BY(mutex_) = 0;
906 std::vector<int> id_to_last_returned_batch_ ABSL_GUARDED_BY(mutex_);
907 std::vector<int> id_to_last_finished_batch_ ABSL_GUARDED_BY(mutex_);
909 std::deque<CompactVectorVector<int>> batches_ ABSL_GUARDED_BY(mutex_);
914 std::vector<CompactVectorVector<int>> pending_batches_
916 int num_full_workers_ ABSL_GUARDED_BY(mutex_) = 0;
918 const bool always_synchronize_ = true;
921 std::vector<int64_t> id_to_num_exported_ ABSL_GUARDED_BY(mutex_);
922 std::vector<int64_t> id_to_num_imported_ ABSL_GUARDED_BY(mutex_);
923 std::vector<int64_t> id_to_num_updated_ ABSL_GUARDED_BY(mutex_);
924 std::vector<std::string> id_to_worker_name_ ABSL_GUARDED_BY(mutex_);
966 void Add(int id, Key expr, IntegerValue lb, IntegerValue ub);
972 int RegisterNewImportId(std::string name);
976 std::vector<std::pair<Key, std::pair<IntegerValue, IntegerValue>>>
977 NewlyUpdatedBounds(int import_id);
988 void MaybeCompressNewlyUpdateKeys() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
990 absl::Mutex mutex_;
993 absl::flat_hash_map<Key, std::pair<IntegerValue, IntegerValue>> shared_bounds_
1004 std::vector<Key> newly_updated_keys_;
1007 std::vector<std::string> import_id_to_name_ ABSL_GUARDED_BY(mutex_);
1008 std::vector<int> import_id_to_index_ ABSL_GUARDED_BY(mutex_);
1009 std::vector<int> import_id_to_num_imported_ ABSL_GUARDED_BY(mutex_);
1015 int64_t num_imported = 0;
1017 return num_new == 0 && num_update == 0 && num_imported == 0;
1020 std::vector<Stats> id_to_stats_ ABSL_GUARDED_BY(mutex_);
1021 std::vector<std::string> id_to_worker_name_ ABSL_GUARDED_BY(mutex_);
1030 void AddStats(absl::Span<const std::pair<std::string, int64_t>> stats);
1037 absl::flat_hash_map<std::string, int64_t> stats_ ABSL_GUARDED_BY(mutex_);
1040template <typename ValueType>
1046template <typename ValueType>
1047std::shared_ptr<const typename SharedSolutionRepository<ValueType>::Solution>
1049 absl::MutexLock mutex_lock(mutex_);
1050 if (i >= solutions_.size()) return nullptr;
1052 return solutions_[i];
1055template <typename ValueType>
1057 absl::MutexLock mutex_lock(mutex_);
1058 if (solutions_.empty()) return std::numeric_limits<int64_t>::max();
1062template <typename ValueType>
1063std::vector<std::shared_ptr<
1066 absl::MutexLock mutex_lock(mutex_);
1068 DCHECK(absl::c_is_sorted(solutions_,
1069 [](const std::shared_ptr<const Solution>& a,
1070 const std::shared_ptr<const Solution>& b) {
1071 return a->rank < b->rank;
1073 DCHECK(absl::c_adjacent_find(solutions_,
1074 [](const std::shared_ptr<const Solution>& a,
1075 const std::shared_ptr<const Solution>& b) {
1076 return *a == *b;
1078 std::vector<std::shared_ptr<const Solution>> result;
1079 const int num_solutions = std::min(static_cast<int>(solutions_.size()), n);
1080 result.reserve(num_solutions);
1081 for (int i = 0; i < num_solutions; ++i) {
1082 result.push_back(solutions_[i]);
1087template <typename ValueType>
1089 int var_index, int solution_index) const {
1090 absl::MutexLock mutex_lock(mutex_);
1091 return solutions_[solution_index]->variable_values[var_index];
1095template <typename ValueType>
1096std::shared_ptr<const typename SharedSolutionRepository<ValueType>::Solution>
1098 absl::BitGenRef random) const {
1099 absl::MutexLock mutex_lock(mutex_);
1100 if (solutions_.empty()) return nullptr;
1104 if (solutions_.size() > 1) {
1105 const int64_t best_rank = solutions_[0]->rank;
1114 const int kExplorationThreshold = 100;
1118 for (int i = 0; i < solutions_.size(); ++i) {
1119 std::shared_ptr<const Solution> solution = solutions_[i];
1120 if (solution->rank == best_rank &&
1121 solution->num_selected <= kExplorationThreshold) {
1122 tmp_indices_.push_back(i);
1126 if (tmp_indices_.empty()) {
1127 index = absl::Uniform<int>(random, 0, solutions_.size());
1129 index = tmp_indices_[absl::Uniform<int>(random, 0, tmp_indices_.size())];
1134 CHECK_LT(index, solutions_.size());
1135 solutions_[index]->num_selected++;
1139template <typename ValueType>
1140std::shared_ptr<const typename SharedSolutionRepository<ValueType>::Solution>
1142 std::shared_ptr<Solution> solution_ptr =
1143 std::make_shared<Solution>(std::move(solution));
1146 absl::MutexLock mutex_lock(mutex_);
1148 solution_ptr->source_id = source_id_;
1154template <typename ValueType>
1157 absl::MutexLock mutex_lock(mutex_);
1158 if (new_solutions_.empty()) {
1159 const int64_t diff = num_queried_ - num_queried_at_last_sync_;
1160 num_non_improving_ += diff;
1161 num_queried_at_last_sync_ = num_queried_;
1168 [](const std::shared_ptr<Solution>& a,
1169 const std::shared_ptr<Solution>& b) { return *a < *b; });
1170 for (const auto& ptr : new_solutions_) {
1175 const int64_t old_best_rank = solutions_.empty()
1176 ? std::numeric_limits<int64_t>::max()
1179 solutions_.insert(solutions_.end(), new_solutions_.begin(),
1186 &solutions_, [](const std::shared_ptr<Solution>& a,
1187 const std::shared_ptr<Solution>& b) { return *a < *b; });
1188 const int64_t new_best_rank = solutions_[0]->rank;
1195 while (num_best < solutions_.size() &&
1196 solutions_[num_best]->rank == new_best_rank) {
1205 for (auto& solution : solutions_) {
1206 if (solution->num_selected == 0) {
1208 std::swap(solutions_[0], solution);
1218 const int n = solutions_.size();
1219 distances_.resize(n * n);
1220 const int size = solutions_[0]->variable_values.size();
1221 for (int i = 0; i < n; ++i) {
1222 for (int j = i + 1; j < n; ++j) {
1224 for (int k = 0; k < size; ++k) {
1225 if (solutions_[i]->variable_values[k] !=
1226 solutions_[j]->variable_values[k]) {
1230 distances_[i * n + j] = distances_[j * n + i] = dist;
1243 const std::vector<int> selected =
1247 DCHECK(std::is_sorted(selected.begin(), selected.end()));
1249 for (const int s : selected) {
1250 solutions_[new_size++] = std::move(solutions_[s]);
1252 solutions_.resize(new_size);
1255 int min_count = std::numeric_limits<int>::max();
1257 for (const auto& s : solutions_) {
1259 min_count = std::min(s->num_selected, min_count);
1260 max_count = std::max(s->num_selected, max_count);
1263 for (const int i : selected) {
1264 for (const int j : selected) {
1265 if (i > j) score += distances_[i * n + j];
1268 LOG(INFO) << name_ << " rank=" << new_best_rank
1270 << " orthogonality=" << score << " count=[" << min_count
1271 << ", " << max_count << "]";
1279 CHECK(!solutions_.empty());
1280 if (!solutions_.empty()) {
1281 VLOG(4) << "Solution pool update:" << " num_solutions=" << solutions_.size()
1282 << " min_rank=" << solutions_[0]->rank
1283 << " max_rank=" << solutions_.back()->rank;
1287 if (new_best_rank < old_best_rank) {
1290 const int64_t diff = num_queried_ - num_queried_at_last_sync_;
1291 num_non_improving_ += diff;
1305 bool lrat_check_enabled, bool drat_check_enabled,
1307 double walltime_in_seconds);
1309 void NewProofFile(absl::string_view filename);
1316 int num_subsolvers_ ABSL_GUARDED_BY(mutex_);
1317 int num_valid_proofs_ ABSL_GUARDED_BY(mutex_);
1318 int num_invalid_proofs_ ABSL_GUARDED_BY(mutex_);
1319 int num_unknown_proofs_ ABSL_GUARDED_BY(mutex_);
1320 bool lrat_check_enabled_ ABSL_GUARDED_BY(mutex_);
1321 bool drat_check_enabled_ ABSL_GUARDED_BY(mutex_);
1322 int num_assumed_clauses_ ABSL_GUARDED_BY(mutex_);
1323 double walltime_in_seconds_ ABSL_GUARDED_BY(mutex_);
1324 std::vector<std::string> proof_filenames_ ABSL_GUARDED_BY(mutex_);