30 #if !defined(__PORTABLE_PLATFORM__)
34 #include "absl/container/btree_map.h"
35 #include "absl/container/flat_hash_map.h"
36 #include "absl/container/flat_hash_set.h"
37 #include "absl/flags/flag.h"
38 #include "absl/status/status.h"
39 #include "absl/strings/str_cat.h"
40 #include "absl/strings/str_format.h"
41 #include "absl/strings/string_view.h"
42 #include "absl/synchronization/mutex.h"
43 #include "absl/time/clock.h"
44 #include "absl/time/time.h"
45 #include "ortools/sat/cp_model.pb.h"
50 #include "ortools/sat/sat_parameters.pb.h"
60 "DEBUG ONLY. If true, all the intermediate solution will be dumped "
61 "under '\"FLAGS_cp_model_dump_prefix\" + \"solution_xxx.pb.txt\"'.");
67 absl::Span<const int64_t> solution_values,
68 IntegerValue inner_objective_value) {
71 if (solution_values.empty())
return;
75 solution.variable_values.assign(solution_values.begin(),
76 solution_values.end());
82 solution.rank = -inner_objective_value.value();
88 std::vector<double> lp_solution) {
89 if (lp_solution.empty())
return;
93 solution.variable_values = std::move(lp_solution);
96 absl::MutexLock mutex_lock(&
mutex_);
97 solution.rank = -num_synchronization_;
102 absl::MutexLock mutex_lock(&mutex_);
103 return !solutions_.empty();
107 absl::MutexLock mutex_lock(&mutex_);
108 std::vector<double> solution;
109 if (solutions_.empty())
return solution;
111 solution = std::move(solutions_.back());
112 solutions_.pop_back();
117 const std::vector<double>& lp_solution) {
118 absl::MutexLock mutex_lock(&mutex_);
119 solutions_.push_back(lp_solution);
123 : parameters_(*
model->GetOrCreate<SatParameters>()),
126 solutions_(parameters_.solution_pool_size()),
131 std::string ProgressMessage(
const std::string& event_or_solution_count,
132 double time_in_seconds,
double obj_best,
133 double obj_lb,
double obj_ub,
134 const std::string& solution_info) {
135 const std::string obj_next =
136 obj_lb <= obj_ub ? absl::StrFormat(
"next:[%.9g,%.9g]", obj_lb, obj_ub)
138 return absl::StrFormat(
"#%-5s %6.2fs best:%-5.9g %-15s %s",
139 event_or_solution_count, time_in_seconds, obj_best,
140 obj_next, solution_info);
143 std::string SatProgressMessage(
const std::string& event_or_solution_count,
144 double time_in_seconds,
145 const std::string& solution_info) {
146 return absl::StrFormat(
"#%-5s %6.2fs %s", event_or_solution_count,
147 time_in_seconds, solution_info);
153 if (
model ==
nullptr)
return;
156 response->set_num_booleans(sat_solver->NumVariables());
157 response->set_num_branches(sat_solver->num_branches());
158 response->set_num_conflicts(sat_solver->num_failures());
159 response->set_num_binary_propagations(sat_solver->num_propagations());
160 response->set_num_restarts(sat_solver->num_restarts());
163 integer_trail ==
nullptr
165 : integer_trail->NumIntegerVariables().value() / 2);
166 response->set_num_integer_propagations(
167 integer_trail ==
nullptr ? 0 : integer_trail->num_enqueues());
172 for (
const auto& set_stats :
180 absl::MutexLock mutex_lock(&mutex_);
181 SOLVER_LOG(logger_, absl::StrFormat(
"#%-5s %6.2fs %s", prefix,
187 double frequency_seconds,
188 absl::Time* last_logging_time) {
189 if (frequency_seconds < 0.0 || last_logging_time ==
nullptr)
return;
190 const absl::Time now = absl::Now();
191 if (now - *last_logging_time < absl::Seconds(frequency_seconds)) {
195 absl::MutexLock mutex_lock(&mutex_);
196 *last_logging_time = now;
197 SOLVER_LOG(logger_, absl::StrFormat(
"#%-5s %6.2fs %s", prefix,
202 if (cp_model.has_objective()) {
203 objective_or_null_ = &cp_model.objective();
207 IntegerValue(domain.
Max()));
210 objective_or_null_ =
nullptr;
215 absl::MutexLock mutex_lock(&mutex_);
216 always_synchronize_ = always_synchronize;
220 absl::MutexLock mutex_lock(&mutex_);
221 update_integral_on_each_change_ = set;
225 absl::MutexLock mutex_lock(&mutex_);
226 UpdateGapIntegralInternal();
229 void SharedResponseManager::UpdateGapIntegralInternal() {
230 if (objective_or_null_ ==
nullptr)
return;
233 const double time_delta = current_time - last_gap_integral_time_stamp_;
240 const CpObjectiveProto& obj = *objective_or_null_;
241 const double factor =
242 obj.scaling_factor() != 0.0 ? std::abs(obj.scaling_factor()) : 1.0;
243 const double bounds_delta = std::log(1 + factor * last_absolute_gap_);
244 gap_integral_ += time_delta * bounds_delta;
247 last_gap_integral_time_stamp_ = current_time;
249 std::max(0.0,
static_cast<double>(inner_objective_upper_bound_) -
250 static_cast<double>(inner_objective_lower_bound_));
255 absl::MutexLock mutex_lock(&mutex_);
256 if (objective_or_null_ ==
nullptr)
return;
257 absolute_gap_limit_ =
parameters.absolute_gap_limit();
258 relative_gap_limit_ =
parameters.relative_gap_limit();
261 void SharedResponseManager::TestGapLimitsIfNeeded() {
265 if (update_integral_on_each_change_) UpdateGapIntegralInternal();
269 if (absolute_gap_limit_ == 0 && relative_gap_limit_ == 0)
return;
272 if (inner_objective_lower_bound_ > inner_objective_upper_bound_)
return;
274 const CpObjectiveProto& obj = *objective_or_null_;
275 const double user_best =
277 const double user_bound =
279 const double gap = std::abs(user_best - user_bound);
280 if (gap <= absolute_gap_limit_) {
281 SOLVER_LOG(logger_,
"Absolute gap limit of ", absolute_gap_limit_,
288 shared_time_limit_->
Stop();
290 if (gap /
std::max(1.0, std::abs(user_best)) < relative_gap_limit_) {
291 SOLVER_LOG(logger_,
"Relative gap limit of ", relative_gap_limit_,
296 shared_time_limit_->
Stop();
301 const std::string& update_info, IntegerValue lb, IntegerValue ub) {
302 absl::MutexLock mutex_lock(&mutex_);
303 CHECK(objective_or_null_ !=
nullptr);
310 if (inner_objective_lower_bound_ > inner_objective_upper_bound_) {
315 (lb > inner_objective_lower_bound_ || ub < inner_objective_upper_bound_);
316 if (lb > inner_objective_lower_bound_) {
321 DCHECK_LE(inner_objective_upper_bound_, best_solution_objective_value_);
322 inner_objective_lower_bound_ =
323 std::min(best_solution_objective_value_, lb.value());
325 if (ub < inner_objective_upper_bound_) {
326 inner_objective_upper_bound_ = ub.value();
328 if (inner_objective_lower_bound_ > inner_objective_upper_bound_) {
335 if (update_integral_on_each_change_) UpdateGapIntegralInternal();
337 SatProgressMessage(
"Done", wall_timer_.
Get(), update_info));
341 const CpObjectiveProto& obj = *objective_or_null_;
346 if (obj.scaling_factor() < 0) {
349 RegisterObjectiveBoundImprovement(update_info);
350 SOLVER_LOG(logger_, ProgressMessage(
"Bound", wall_timer_.
Get(), best,
351 new_lb, new_ub, update_info));
353 if (change) TestGapLimitsIfNeeded();
360 const std::string& worker_info) {
361 absl::MutexLock mutex_lock(&mutex_);
370 inner_objective_lower_bound_ = best_solution_objective_value_;
371 if (update_integral_on_each_change_) UpdateGapIntegralInternal();
373 CHECK_EQ(num_solutions_, 0);
377 SatProgressMessage(
"Done", wall_timer_.
Get(), worker_info));
381 absl::MutexLock mutex_lock(&mutex_);
386 absl::MutexLock mutex_lock(&mutex_);
387 return IntegerValue(inner_objective_lower_bound_);
391 absl::MutexLock mutex_lock(&mutex_);
392 return IntegerValue(inner_objective_upper_bound_);
396 absl::MutexLock mutex_lock(&mutex_);
397 synchronized_inner_objective_lower_bound_ =
398 IntegerValue(inner_objective_lower_bound_);
399 synchronized_inner_objective_upper_bound_ =
400 IntegerValue(inner_objective_upper_bound_);
401 synchronized_best_status_ = best_status_;
402 if (solutions_.NumSolutions() > 0) {
403 first_solution_solvers_should_stop_ =
true;
408 absl::MutexLock mutex_lock(&mutex_);
409 return synchronized_inner_objective_lower_bound_;
413 absl::MutexLock mutex_lock(&mutex_);
414 return synchronized_inner_objective_upper_bound_;
418 absl::MutexLock mutex_lock(&mutex_);
419 return IntegerValue(best_solution_objective_value_);
423 absl::MutexLock mutex_lock(&mutex_);
424 return gap_integral_;
428 std::function<
void(std::vector<int64_t>*)> postprocessor) {
429 absl::MutexLock mutex_lock(&mutex_);
430 solution_postprocessors_.push_back(postprocessor);
434 std::function<
void(CpSolverResponse*)> postprocessor) {
435 absl::MutexLock mutex_lock(&mutex_);
436 postprocessors_.push_back(postprocessor);
440 std::function<
void(CpSolverResponse*)> postprocessor) {
441 absl::MutexLock mutex_lock(&mutex_);
442 final_postprocessors_.push_back(postprocessor);
446 std::function<
void(
const CpSolverResponse&)>
callback) {
447 absl::MutexLock mutex_lock(&mutex_);
448 const int id = next_callback_id_++;
449 callbacks_.emplace_back(
id, std::move(
callback));
454 absl::MutexLock mutex_lock(&mutex_);
455 for (
int i = 0; i < callbacks_.size(); ++i) {
456 if (callbacks_[i].first == callback_id) {
457 callbacks_.erase(callbacks_.begin() + i);
461 LOG(DFATAL) <<
"Callback id " << callback_id <<
" not registered.";
464 CpSolverResponse SharedResponseManager::GetResponseInternal(
465 absl::Span<const int64_t> variable_values,
466 const std::string& solution_info) {
467 CpSolverResponse result;
468 result.set_status(best_status_);
469 if (!unsat_cores_.empty()) {
471 result.mutable_sufficient_assumptions_for_infeasibility()->Assign(
472 unsat_cores_.begin(), unsat_cores_.end());
474 FillObjectiveValuesInResponse(&result);
475 result.set_solution_info(solution_info);
484 result.mutable_solution()->Assign(variable_values.begin(),
485 variable_values.end());
490 if (!subsolver_responses_.empty()) {
491 result.MergeFrom(subsolver_responses_.front());
497 std::vector<int64_t> solution(result.solution().begin(),
498 result.solution().end());
499 for (
int i = solution_postprocessors_.size(); --i >= 0;) {
500 solution_postprocessors_[i](&solution);
502 result.mutable_solution()->Assign(solution.begin(), solution.end());
506 for (
int i = postprocessors_.size(); --i >= 0;) {
507 postprocessors_[i](&result);
513 absl::MutexLock mutex_lock(&mutex_);
514 CpSolverResponse result =
515 solutions_.NumSolutions() == 0
516 ? GetResponseInternal({},
"")
517 : GetResponseInternal(solutions_.GetSolution(0).variable_values,
518 solutions_.GetSolution(0).info);
521 if (parameters_.fill_additional_solutions_in_response()) {
522 std::vector<int64_t> temp;
523 for (
int i = 0; i < solutions_.NumSolutions(); ++i) {
524 temp = solutions_.GetSolution(i).variable_values;
525 for (
int i = solution_postprocessors_.size(); --i >= 0;) {
526 solution_postprocessors_[i](&temp);
528 result.add_additional_solutions()->mutable_values()->Assign(temp.begin(),
535 for (
int i = final_postprocessors_.size(); --i >= 0;) {
536 final_postprocessors_[i](&result);
544 absl::MutexLock mutex_lock(&mutex_);
545 return subsolver_responses_.push_back(
response);
548 void SharedResponseManager::FillObjectiveValuesInResponse(
550 if (objective_or_null_ ==
nullptr)
return;
551 const CpObjectiveProto& obj = *objective_or_null_;
555 response->clear_best_objective_bound();
556 response->clear_inner_objective_lower_bound();
562 if (best_status_ == CpSolverStatus::UNKNOWN) {
571 response->set_inner_objective_lower_bound(
577 response->set_gap_integral(gap_integral_);
581 absl::Span<const int64_t> solution_values,
const std::string& solution_info,
583 absl::MutexLock mutex_lock(&mutex_);
587 if (objective_or_null_ ==
nullptr) {
589 solution.variable_values.assign(solution_values.begin(),
590 solution_values.end());
591 solution.info = solution_info;
593 solutions_.
Add(solution);
596 if (objective_or_null_ !=
nullptr) {
601 if (!solution_values.empty()) {
603 solution.variable_values.assign(solution_values.begin(),
604 solution_values.end());
606 solution.info = solution_info;
607 solutions_.
Add(solution);
628 if (always_synchronize_) {
629 solutions_.Synchronize();
630 first_solution_solvers_should_stop_ =
true;
635 if (objective_or_null_ ==
nullptr && !parameters_.enumerate_all_solutions()) {
642 if (objective_or_null_ !=
nullptr &&
643 inner_objective_lower_bound_ > inner_objective_upper_bound_) {
651 std::string solution_message = solution_info;
652 if (
model !=
nullptr) {
654 const int64_t num_fixed =
model->Get<
SatSolver>()->NumFixedVariables();
655 absl::StrAppend(&solution_message,
" fixed_bools:", num_fixed,
"/",
659 if (objective_or_null_ !=
nullptr) {
660 const CpObjectiveProto& obj = *objective_or_null_;
665 if (obj.scaling_factor() < 0) {
668 RegisterSolutionFound(solution_message);
669 SOLVER_LOG(logger_, ProgressMessage(absl::StrCat(num_solutions_),
670 wall_timer_.
Get(), best, lb, ub,
674 SatProgressMessage(absl::StrCat(num_solutions_),
675 wall_timer_.
Get(), solution_message));
681 TestGapLimitsIfNeeded();
682 if (!callbacks_.empty()) {
683 CpSolverResponse copy = GetResponseInternal(solution_values, solution_info);
685 for (
const auto& pair : callbacks_) {
690 #if !defined(__PORTABLE_PLATFORM__)
694 absl::GetFlag(FLAGS_cp_model_dump_solutions)) {
695 const std::string
file =
696 absl::StrCat(dump_prefix_,
"solution_", num_solutions_,
".pb.txt");
697 LOG(INFO) <<
"Dumping solution to '" <<
file <<
"'.";
702 response.mutable_solution()->Assign(solution_values.begin(),
703 solution_values.end());
710 absl::MutexLock mutex_lock(&mutex_);
715 void SharedResponseManager::UpdateBestStatus(
const CpSolverStatus&
status) {
717 if (always_synchronize_) {
718 synchronized_best_status_ =
status;
723 if (improvement_info.empty())
return "";
726 for (
int i = 0; i < improvement_info.size(); ++i) {
727 if (!std::isalnum(improvement_info[i]) && improvement_info[i] !=
'_') {
728 return improvement_info.substr(0, i);
732 return improvement_info;
735 void SharedResponseManager::RegisterSolutionFound(
736 const std::string& improvement_info) {
737 if (improvement_info.empty())
return;
741 void SharedResponseManager::RegisterObjectiveBoundImprovement(
742 const std::string& improvement_info) {
743 if (improvement_info.empty() || improvement_info ==
"initial domain")
return;
748 absl::MutexLock mutex_lock(&mutex_);
749 if (!primal_improvements_count_.empty()) {
751 SOLVER_LOG(logger_,
"Solutions found per subsolver:");
752 for (
const auto& entry : primal_improvements_count_) {
753 SOLVER_LOG(logger_,
" '", entry.first,
"': ", entry.second);
756 if (!dual_improvements_count_.empty()) {
758 SOLVER_LOG(logger_,
"Objective bounds found per subsolver:");
759 for (
const auto& entry : dual_improvements_count_) {
760 SOLVER_LOG(logger_,
" '", entry.first,
"': ", entry.second);
768 lower_bounds_(num_variables_, std::numeric_limits<int64_t>::
min()),
769 upper_bounds_(num_variables_, std::numeric_limits<int64_t>::
max()),
770 synchronized_lower_bounds_(num_variables_,
771 std::numeric_limits<int64_t>::
min()),
772 synchronized_upper_bounds_(num_variables_,
773 std::numeric_limits<int64_t>::
max()) {
774 changed_variables_since_last_synchronize_.ClearAndResize(num_variables_);
775 for (
int i = 0; i < num_variables_; ++i) {
776 lower_bounds_[i] =
model_proto.variables(i).domain(0);
777 const int domain_size =
model_proto.variables(i).domain_size();
778 upper_bounds_[i] =
model_proto.variables(i).domain(domain_size - 1);
779 synchronized_lower_bounds_[i] = lower_bounds_[i];
780 synchronized_upper_bounds_[i] = upper_bounds_[i];
785 const std::string& worker_name,
const std::vector<int>& variables,
786 const std::vector<int64_t>& new_lower_bounds,
787 const std::vector<int64_t>& new_upper_bounds) {
788 CHECK_EQ(variables.size(), new_lower_bounds.size());
789 CHECK_EQ(variables.size(), new_upper_bounds.size());
790 int num_improvements = 0;
792 absl::MutexLock mutex_lock(&mutex_);
793 for (
int i = 0; i < variables.size(); ++i) {
794 const int var = variables[i];
795 if (
var >= num_variables_)
continue;
796 const int64_t old_lb = lower_bounds_[
var];
797 const int64_t old_ub = upper_bounds_[
var];
798 const int64_t new_lb = new_lower_bounds[i];
799 const int64_t new_ub = new_upper_bounds[i];
800 const bool changed_lb = new_lb > old_lb;
801 const bool changed_ub = new_ub < old_ub;
802 if (!changed_lb && !changed_ub)
continue;
804 VLOG(3) << worker_name <<
" var=" <<
var <<
" [" << old_lb <<
"," << old_ub
805 <<
"] -> [" << new_lb <<
"," << new_ub <<
"]";
809 CHECK_LE(new_lb, debug_solution_[
var]) << worker_name <<
" var=" <<
var;
811 lower_bounds_[
var] = new_lb;
815 CHECK_GE(new_ub, debug_solution_[
var]) << worker_name <<
" var=" <<
var;
817 upper_bounds_[
var] = new_ub;
819 changed_variables_since_last_synchronize_.Set(
var);
822 if (num_improvements > 0) {
823 bounds_exported_[worker_name] += num_improvements;
831 const std::vector<int64_t>& solution,
832 const std::vector<int>& variables_to_fix) {
833 absl::MutexLock mutex_lock(&mutex_);
839 for (
const int var : variables_to_fix) {
840 const int64_t
value = solution[
var];
842 VLOG(1) <<
"Incompatibility in FixVariablesFromPartialSolution() "
843 <<
"var: " <<
var <<
" value: " <<
value <<
" bounds: ["
844 << lower_bounds_[
var] <<
"," << upper_bounds_[
var] <<
"]";
850 for (
const int var : variables_to_fix) {
851 const int64_t old_lb = lower_bounds_[
var];
852 const int64_t old_ub = upper_bounds_[
var];
853 const bool changed_lb = solution[
var] > old_lb;
854 const bool changed_ub = solution[
var] < old_ub;
855 if (!changed_lb && !changed_ub)
continue;
857 lower_bounds_[
var] = solution[
var];
858 upper_bounds_[
var] = solution[
var];
859 changed_variables_since_last_synchronize_.Set(
var);
865 if (solution[
var] != debug_solution_[
var]) {
866 LOG(INFO) <<
"Fixing to a different solution for var=" <<
var
867 <<
" debug=" << debug_solution_[
var]
868 <<
" partial=" << solution[
var];
869 lower_bounds_[
var] = debug_solution_[
var];
870 upper_bounds_[
var] = debug_solution_[
var];
877 absl::MutexLock mutex_lock(&mutex_);
879 changed_variables_since_last_synchronize_.PositionsSetAtLeastOnce()) {
880 synchronized_lower_bounds_[
var] = lower_bounds_[
var];
881 synchronized_upper_bounds_[
var] = upper_bounds_[
var];
882 for (
int j = 0; j < id_to_changed_variables_.size(); ++j) {
883 id_to_changed_variables_[j].Set(
var);
886 changed_variables_since_last_synchronize_.ClearAll();
890 absl::MutexLock mutex_lock(&mutex_);
891 const int id = id_to_changed_variables_.size();
892 id_to_changed_variables_.resize(
id + 1);
893 id_to_changed_variables_[id].ClearAndResize(num_variables_);
894 for (
int var = 0;
var < num_variables_; ++
var) {
895 const int64_t lb = model_proto_.variables(
var).domain(0);
896 const int domain_size = model_proto_.variables(
var).domain_size();
897 const int64_t ub = model_proto_.variables(
var).domain(domain_size - 1);
898 if (lb != synchronized_lower_bounds_[
var] ||
899 ub != synchronized_upper_bounds_[
var]) {
900 id_to_changed_variables_[id].Set(
var);
907 int id, std::vector<int>* variables, std::vector<int64_t>* new_lower_bounds,
908 std::vector<int64_t>* new_upper_bounds) {
910 new_lower_bounds->clear();
911 new_upper_bounds->clear();
913 absl::MutexLock mutex_lock(&mutex_);
914 for (
const int var : id_to_changed_variables_[
id].PositionsSetAtLeastOnce()) {
915 variables->push_back(
var);
916 new_lower_bounds->push_back(synchronized_lower_bounds_[
var]);
917 new_upper_bounds->push_back(synchronized_upper_bounds_[
var]);
919 id_to_changed_variables_[id].ClearAll();
923 absl::MutexLock mutex_lock(&mutex_);
924 if (!bounds_exported_.empty()) {
926 SOLVER_LOG(logger,
"Improving variable bounds shared per subsolver:");
927 for (
const auto& entry : bounds_exported_) {
928 SOLVER_LOG(logger,
" '", entry.first,
"': ", entry.second);
934 absl::MutexLock mutex_lock(&mutex_);
935 const auto it = bounds_exported_.find(worker_name);
936 if (it == bounds_exported_.end())
return 0;
941 : always_synchronize_(always_synchronize) {}
944 absl::MutexLock mutex_lock(&mutex_);
945 const int id = id_to_last_processed_binary_clause_.size();
946 id_to_last_processed_binary_clause_.resize(
id + 1, 0);
947 id_to_clauses_exported_.resize(
id + 1, 0);
952 const std::string& worker_name) {
953 absl::MutexLock mutex_lock(&mutex_);
954 id_to_worker_name_[id] = worker_name;
958 absl::MutexLock mutex_lock(&mutex_);
961 const auto p = std::make_pair(lit1, lit2);
962 const auto [unused_it, inserted] = added_binary_clauses_set_.insert(p);
964 added_binary_clauses_.push_back(p);
965 if (always_synchronize_) ++last_visible_clause_;
966 id_to_clauses_exported_[id]++;
969 if (id_to_last_processed_binary_clause_[
id] ==
970 added_binary_clauses_.size() - 1) {
971 id_to_last_processed_binary_clause_[id]++;
977 int id, std::vector<std::pair<int, int>>* new_clauses) {
978 new_clauses->clear();
979 absl::MutexLock mutex_lock(&mutex_);
980 const int last_binary_clause_seen = id_to_last_processed_binary_clause_[id];
984 if (last_binary_clause_seen >= last_visible_clause_)
return;
986 new_clauses->assign(added_binary_clauses_.begin() + last_binary_clause_seen,
987 added_binary_clauses_.begin() + last_visible_clause_);
988 id_to_last_processed_binary_clause_[id] = last_visible_clause_;
992 absl::MutexLock mutex_lock(&mutex_);
993 absl::btree_map<std::string, int64_t> name_to_clauses;
994 for (
int id = 0;
id < id_to_clauses_exported_.size(); ++id) {
995 if (id_to_clauses_exported_[
id] == 0)
continue;
996 name_to_clauses[id_to_worker_name_[id]] = id_to_clauses_exported_[id];
998 if (!name_to_clauses.empty()) {
1000 SOLVER_LOG(logger,
"Clauses shared per subsolver:");
1001 for (
const auto& entry : name_to_clauses) {
1002 SOLVER_LOG(logger,
" '", entry.first,
"': ", entry.second);
1008 absl::MutexLock mutex_lock(&mutex_);
1009 last_visible_clause_ = added_binary_clauses_.size();
1014 absl::Span<
const std::pair<std::string, int64_t>> stats) {
1015 absl::MutexLock mutex_lock(&mutex_);
1016 for (
const auto& [key, count] : stats) {
1017 stats_[key] += count;
1022 absl::MutexLock mutex_lock(&mutex_);
1023 if (stats_.empty())
return;
1026 SOLVER_LOG(logger,
"Stats across workers (summed):");
1027 std::vector<std::pair<std::string, int64_t>> to_sort_;
1028 for (
const auto& [key, count] : stats_) {
1029 to_sort_.push_back({key, count});
1031 std::sort(to_sort_.begin(), to_sort_.end());
1032 for (
const auto& [key, count] : to_sort_) {
We call domain any subset of Int64 = [kint64min, kint64max].
int64_t Min() const
Returns the min value of the domain.
bool IsEmpty() const
Returns true if this is the empty set.
int64_t Max() const
Returns the max value of the domain.
double GetElapsedDeterministicTime() const
bool LoggingIsEnabled() const
Class that owns everything related to a particular optimization model.
void ReportPotentialNewBounds(const std::string &worker_name, const std::vector< int > &variables, const std::vector< int64_t > &new_lower_bounds, const std::vector< int64_t > &new_upper_bounds)
SharedBoundsManager(const CpModelProto &model_proto)
void LogStatistics(SolverLogger *logger)
void FixVariablesFromPartialSolution(const std::vector< int64_t > &solution, const std::vector< int > &variables_to_fix)
int NumBoundsExported(const std::string &worker_name)
void GetChangedBounds(int id, std::vector< int > *variables, std::vector< int64_t > *new_lower_bounds, std::vector< int64_t > *new_upper_bounds)
void LogStatistics(SolverLogger *logger)
void AddBinaryClause(int id, int lit1, int lit2)
SharedClausesManager(bool always_synchronize)
void GetUnseenBinaryClauses(int id, std::vector< std::pair< int, int >> *new_clauses)
void SetWorkerNameForId(int id, const std::string &worker_name)
void AddNewSolution(const std::vector< double > &lp_solution)
std::vector< double > GetNewSolution()
bool HasNewSolution() const
void NewLPSolution(std::vector< double > lp_solution)
void NewRelaxationSolution(absl::Span< const int64_t > solution_values, IntegerValue inner_objective_value)
bool ProblemIsSolved() const
void InitializeObjective(const CpModelProto &cp_model)
CpSolverResponse GetResponse()
void LogPeriodicMessage(const std::string &prefix, const std::string &message, double frequency_seconds, absl::Time *last_logging_time)
void AddSolutionPostprocessor(std::function< void(std::vector< int64_t > *)> postprocessor)
void AddFinalResponsePostprocessor(std::function< void(CpSolverResponse *)> postprocessor)
IntegerValue GetInnerObjectiveUpperBound()
IntegerValue SynchronizedInnerObjectiveUpperBound()
IntegerValue SynchronizedInnerObjectiveLowerBound()
void DisplayImprovementStatistics()
double GapIntegral() const
void NotifyThatImprovingProblemIsInfeasible(const std::string &worker_info)
void SetSynchronizationMode(bool always_synchronize)
void SetUpdateGapIntegralOnEachChange(bool set)
IntegerValue BestSolutionInnerObjectiveValue()
void AddUnsatCore(const std::vector< int > &core)
void SetGapLimitsFromParameters(const SatParameters ¶meters)
void AppendResponseToBeMerged(const CpSolverResponse &response)
void AddResponsePostprocessor(std::function< void(CpSolverResponse *)> postprocessor)
int AddSolutionCallback(std::function< void(const CpSolverResponse &)> callback)
void NewSolution(absl::Span< const int64_t > solution_values, const std::string &solution_info, Model *model=nullptr)
void LogMessage(const std::string &prefix, const std::string &message)
IntegerValue GetInnerObjectiveLowerBound()
void UnregisterCallback(int callback_id)
SharedResponseManager(Model *model)
void UpdateInnerObjectiveBounds(const std::string &update_info, IntegerValue lb, IntegerValue ub)
void Add(const Solution &solution)
void AddInternal(const Solution &solution) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_)
void Log(SolverLogger *logger)
void AddStats(absl::Span< const std::pair< std::string, int64_t >> stats)
CpModelProto const * model_proto
SharedResponseManager * response
absl::Status SetTextProto(const absl::string_view &filename, const google::protobuf::Message &proto, int flags)
int NumVariables(const VariablesProto &variables)
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
double ScaleObjectiveValue(const CpObjectiveProto &proto, int64_t value)
std::string ExtractSubSolverName(const std::string &improvement_info)
std::string FormatCounter(int64_t num)
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
int64_t ComputeInnerObjective(const CpObjectiveProto &objective, absl::Span< const int64_t > solution)
void FillSolveStatsInResponse(Model *model, CpSolverResponse *response)
int64_t ScaleInnerObjectiveValue(const CpObjectiveProto &proto, int64_t value)
Collection of objects used to extend the Constraint Solver library.
std::vector< std::function< void(CpSolverResponse *)> > callbacks
ABSL_FLAG(bool, cp_model_dump_solutions, false, "DEBUG ONLY. If true, all the intermediate solution will be dumped " "under '\"FLAGS_cp_model_dump_prefix\" + \"solution_xxx.pb.txt\"'.")
#define SOLVER_LOG(logger,...)
#define VLOG(verboselevel)