28#include "absl/container/btree_map.h"
31#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"
46#include "ortools/sat/cp_model.pb.h"
53#include "ortools/sat/sat_parameters.pb.h"
63 "DEBUG ONLY. If true, all the intermediate solution will be dumped "
64 "under '\"FLAGS_cp_model_dump_prefix\" + \"solution_xxx.pb.txt\"'.");
67 std::string, cp_model_load_debug_solution,
"",
68 "DEBUG ONLY. When this is set to a non-empty file name, "
69 "we will interpret this as an internal solution which can be used for "
70 "debugging. For instance we use it to identify wrong cuts/reasons.");
79 if (
response.solution().empty())
return;
83 solution.variable_values.assign(
response.solution().begin(),
90 solution.rank = -
response.best_objective_bound();
96 std::vector<double> lp_solution) {
97 if (lp_solution.empty())
return;
101 solution.variable_values = std::move(lp_solution);
104 absl::MutexLock mutex_lock(&
mutex_);
105 solution.rank = -num_synchronization_;
110 absl::MutexLock mutex_lock(&mutex_);
111 return !solutions_.empty();
115 absl::MutexLock mutex_lock(&mutex_);
116 std::vector<double> solution;
117 if (solutions_.empty())
return solution;
119 solution = std::move(solutions_.back());
120 solutions_.pop_back();
125 const std::vector<double>& lp_solution) {
126 absl::MutexLock mutex_lock(&mutex_);
127 solutions_.push_back(lp_solution);
131 : parameters_(*
model->GetOrCreate<SatParameters>()),
134 solutions_(parameters_.solution_pool_size()),
139std::string ProgressMessage(
const std::string& event_or_solution_count,
140 double time_in_seconds,
double obj_best,
141 double obj_lb,
double obj_ub,
142 const std::string& solution_info) {
143 const std::string obj_next =
144 obj_lb <= obj_ub ? absl::StrFormat(
"next:[%.9g,%.9g]", obj_lb, obj_ub)
146 return absl::StrFormat(
"#%-5s %6.2fs best:%-5.9g %-15s %s",
147 event_or_solution_count, time_in_seconds, obj_best,
148 obj_next, solution_info);
151std::string SatProgressMessage(
const std::string& event_or_solution_count,
152 double time_in_seconds,
153 const std::string& solution_info) {
154 return absl::StrFormat(
"#%-5s %6.2fs %s", event_or_solution_count,
155 time_in_seconds, solution_info);
162 absl::MutexLock mutex_lock(&mutex_);
163 SOLVER_LOG(logger_, absl::StrFormat(
"#%-5s %6.2fs %s", prefix,
169 absl::Time* last_logging_time) {
170 const double freq = parameters_.log_frequency_in_seconds();
171 if (freq <= 0.0 || last_logging_time ==
nullptr)
return;
172 const absl::Time now = absl::Now();
173 if (now - *last_logging_time < absl::Seconds(freq)) {
177 absl::MutexLock mutex_lock(&mutex_);
178 *last_logging_time = now;
179 SOLVER_LOG(logger_, absl::StrFormat(
"#%-5s %6.2fs %s", prefix,
184 if (cp_model.has_objective()) {
185 objective_or_null_ = &cp_model.objective();
189 IntegerValue(domain.
Max()));
192 objective_or_null_ =
nullptr;
197 absl::MutexLock mutex_lock(&mutex_);
198 update_integral_on_each_change_ = set;
202 absl::MutexLock mutex_lock(&mutex_);
203 UpdateGapIntegralInternal();
206void SharedResponseManager::UpdateGapIntegralInternal() {
207 if (objective_or_null_ ==
nullptr)
return;
210 const double time_delta = current_time - last_gap_integral_time_stamp_;
217 const CpObjectiveProto& obj = *objective_or_null_;
218 const double factor =
219 obj.scaling_factor() != 0.0 ? std::abs(obj.scaling_factor()) : 1.0;
220 const double bounds_delta = std::log(1 + factor * last_absolute_gap_);
221 gap_integral_ += time_delta * bounds_delta;
224 last_gap_integral_time_stamp_ = current_time;
226 std::max(0.0,
static_cast<double>(inner_objective_upper_bound_) -
227 static_cast<double>(inner_objective_lower_bound_));
232 absl::MutexLock mutex_lock(&mutex_);
233 if (objective_or_null_ ==
nullptr)
return;
234 absolute_gap_limit_ =
parameters.absolute_gap_limit();
235 relative_gap_limit_ =
parameters.relative_gap_limit();
238void SharedResponseManager::TestGapLimitsIfNeeded() {
242 if (update_integral_on_each_change_) UpdateGapIntegralInternal();
246 if (absolute_gap_limit_ == 0 && relative_gap_limit_ == 0)
return;
249 if (inner_objective_lower_bound_ > inner_objective_upper_bound_)
return;
251 const CpObjectiveProto& obj = *objective_or_null_;
252 const double user_best =
254 const double user_bound =
256 const double gap = std::abs(user_best - user_bound);
257 if (gap <= absolute_gap_limit_) {
258 SOLVER_LOG(logger_,
"Absolute gap limit of ", absolute_gap_limit_,
260 best_response_.set_status(CpSolverStatus::OPTIMAL);
265 shared_time_limit_->
Stop();
267 if (gap /
std::max(1.0, std::abs(user_best)) < relative_gap_limit_) {
268 SOLVER_LOG(logger_,
"Relative gap limit of ", relative_gap_limit_,
270 best_response_.set_status(CpSolverStatus::OPTIMAL);
273 shared_time_limit_->
Stop();
278 const std::string& update_info, IntegerValue lb, IntegerValue ub) {
279 absl::MutexLock mutex_lock(&mutex_);
280 CHECK(objective_or_null_ !=
nullptr);
287 if (inner_objective_lower_bound_ > inner_objective_upper_bound_) {
292 (lb > inner_objective_lower_bound_ || ub < inner_objective_upper_bound_);
293 if (lb > inner_objective_lower_bound_) {
298 DCHECK_LE(inner_objective_upper_bound_, best_solution_objective_value_);
299 inner_objective_lower_bound_ =
300 std::min(best_solution_objective_value_, lb.value());
302 if (ub < inner_objective_upper_bound_) {
303 inner_objective_upper_bound_ = ub.value();
305 if (inner_objective_lower_bound_ > inner_objective_upper_bound_) {
306 if (best_response_.status() == CpSolverStatus::FEASIBLE ||
307 best_response_.status() == CpSolverStatus::OPTIMAL) {
308 best_response_.set_status(CpSolverStatus::OPTIMAL);
310 best_response_.set_status(CpSolverStatus::INFEASIBLE);
312 if (update_integral_on_each_change_) UpdateGapIntegralInternal();
314 SatProgressMessage(
"Done", wall_timer_.
Get(), update_info));
318 const CpObjectiveProto& obj = *objective_or_null_;
323 if (obj.scaling_factor() < 0) {
326 RegisterObjectiveBoundImprovement(update_info);
327 SOLVER_LOG(logger_, ProgressMessage(
"Bound", wall_timer_.
Get(), best,
328 new_lb, new_ub, update_info));
330 if (change) TestGapLimitsIfNeeded();
337 const std::string& worker_info) {
338 absl::MutexLock mutex_lock(&mutex_);
339 if (best_response_.status() == CpSolverStatus::FEASIBLE ||
340 best_response_.status() == CpSolverStatus::OPTIMAL) {
343 best_response_.set_status(CpSolverStatus::OPTIMAL);
347 inner_objective_lower_bound_ = best_solution_objective_value_;
348 if (update_integral_on_each_change_) UpdateGapIntegralInternal();
351 best_response_.set_status(CpSolverStatus::INFEASIBLE);
354 SatProgressMessage(
"Done", wall_timer_.
Get(), worker_info));
358 absl::MutexLock mutex_lock(&mutex_);
359 best_response_.clear_sufficient_assumptions_for_infeasibility();
360 for (
const int ref : core) {
361 best_response_.add_sufficient_assumptions_for_infeasibility(ref);
366 absl::MutexLock mutex_lock(&mutex_);
367 return IntegerValue(inner_objective_lower_bound_);
371 absl::MutexLock mutex_lock(&mutex_);
372 return IntegerValue(inner_objective_upper_bound_);
376 absl::MutexLock mutex_lock(&mutex_);
377 synchronized_inner_objective_lower_bound_ =
378 IntegerValue(inner_objective_lower_bound_);
379 synchronized_inner_objective_upper_bound_ =
380 IntegerValue(inner_objective_upper_bound_);
384 absl::MutexLock mutex_lock(&mutex_);
385 return synchronized_inner_objective_lower_bound_;
389 absl::MutexLock mutex_lock(&mutex_);
390 return synchronized_inner_objective_upper_bound_;
394 absl::MutexLock mutex_lock(&mutex_);
395 return IntegerValue(best_solution_objective_value_);
399 absl::MutexLock mutex_lock(&mutex_);
400 return gap_integral_;
404 std::function<
void(std::vector<int64_t>*)> postprocessor) {
405 absl::MutexLock mutex_lock(&mutex_);
406 solution_postprocessors_.push_back(postprocessor);
410 std::function<
void(CpSolverResponse*)> postprocessor) {
411 absl::MutexLock mutex_lock(&mutex_);
412 postprocessors_.push_back(postprocessor);
416 std::function<
void(CpSolverResponse*)> postprocessor) {
417 absl::MutexLock mutex_lock(&mutex_);
418 final_postprocessors_.push_back(postprocessor);
422 std::function<
void(
const CpSolverResponse&)>
callback) {
423 absl::MutexLock mutex_lock(&mutex_);
424 const int id = next_callback_id_++;
425 callbacks_.emplace_back(
id, std::move(
callback));
430 absl::MutexLock mutex_lock(&mutex_);
431 for (
int i = 0; i < callbacks_.size(); ++i) {
432 if (callbacks_[i].first == callback_id) {
433 callbacks_.erase(callbacks_.begin() + i);
437 LOG(DFATAL) <<
"Callback id " << callback_id <<
" not registered.";
440CpSolverResponse SharedResponseManager::GetResponseInternal() {
441 FillObjectiveValuesInBestResponse();
444 CpSolverResponse result = best_response_;
445 if (result.status() == CpSolverStatus::FEASIBLE ||
446 result.status() == CpSolverStatus::OPTIMAL) {
447 std::vector<int64_t> solution(result.solution().begin(),
448 result.solution().end());
449 for (
int i = solution_postprocessors_.size(); --i >= 0;) {
450 solution_postprocessors_[i](&solution);
452 result.mutable_solution()->Assign(solution.begin(), solution.end());
454 for (
int i = postprocessors_.size(); --i >= 0;) {
455 postprocessors_[i](&result);
461 absl::MutexLock mutex_lock(&mutex_);
462 CpSolverResponse result = GetResponseInternal();
465 if (parameters_.fill_additional_solutions_in_response()) {
466 std::vector<int64_t> temp;
467 for (
int i = 0; i < solutions_.NumSolutions(); ++i) {
468 temp = solutions_.GetSolution(i).variable_values;
469 for (
int i = solution_postprocessors_.size(); --i >= 0;) {
470 solution_postprocessors_[i](&temp);
472 result.add_additional_solutions()->mutable_values()->Assign(
473 temp.begin(), temp.end());
476 for (
int i = final_postprocessors_.size(); --i >= 0;) {
477 final_postprocessors_[i](&result);
483void SharedResponseManager::FillObjectiveValuesInBestResponse() {
484 if (objective_or_null_ ==
nullptr)
return;
485 const CpObjectiveProto& obj = *objective_or_null_;
487 if (best_response_.status() == CpSolverStatus::INFEASIBLE) {
488 best_response_.clear_objective_value();
489 best_response_.clear_best_objective_bound();
490 best_response_.clear_inner_objective_lower_bound();
496 if (best_response_.status() == CpSolverStatus::UNKNOWN) {
497 best_response_.set_objective_value(
500 best_response_.set_objective_value(
505 best_response_.set_inner_objective_lower_bound(
507 best_response_.set_best_objective_bound(
511 best_response_.set_gap_integral(gap_integral_);
516 absl::MutexLock mutex_lock(&mutex_);
519 if (objective_or_null_ ==
nullptr && parameters_.enumerate_all_solutions() &&
520 parameters_.fill_additional_solutions_in_response()) {
522 solution.variable_values.assign(
response.solution().begin(),
524 solutions_.
Add(solution);
527 if (objective_or_null_ !=
nullptr) {
534 solution.variable_values.assign(
response.solution().begin(),
537 solutions_.Add(solution);
559 if (update_integral_on_each_change_) {
560 solutions_.Synchronize();
565 if (objective_or_null_ ==
nullptr && !parameters_.enumerate_all_solutions()) {
566 best_response_.set_status(CpSolverStatus::OPTIMAL);
568 best_response_.set_status(CpSolverStatus::FEASIBLE);
571 best_response_.set_solution_info(
response.solution_info());
572 *best_response_.mutable_solution() =
response.solution();
575 if (objective_or_null_ !=
nullptr &&
576 inner_objective_lower_bound_ > inner_objective_upper_bound_) {
577 best_response_.set_status(CpSolverStatus::OPTIMAL);
583 std::string solution_info =
response.solution_info();
584 if (
model !=
nullptr) {
586 const int64_t num_fixed =
model->Get<
SatSolver>()->NumFixedVariables();
587 absl::StrAppend(&solution_info,
" fixed_bools:", num_fixed,
"/",
591 if (objective_or_null_ !=
nullptr) {
592 const CpObjectiveProto& obj = *objective_or_null_;
597 if (obj.scaling_factor() < 0) {
600 RegisterSolutionFound(solution_info);
601 SOLVER_LOG(logger_, ProgressMessage(absl::StrCat(num_solutions_),
602 wall_timer_.
Get(), best, lb, ub,
605 SOLVER_LOG(logger_, SatProgressMessage(absl::StrCat(num_solutions_),
606 wall_timer_.
Get(), solution_info));
612 TestGapLimitsIfNeeded();
613 if (!callbacks_.empty()) {
614 SetStatsFromModelInternal(
model);
615 const CpSolverResponse copy = GetResponseInternal();
616 for (
const auto& pair : callbacks_) {
621#if !defined(__PORTABLE_PLATFORM__)
624 if (absl::GetFlag(FLAGS_cp_model_dump_solutions)) {
625 const std::string
file =
626 absl::StrCat(dump_prefix_,
"solution_", num_solutions_,
".pb.txt");
627 LOG(
INFO) <<
"Dumping solution to '" <<
file <<
"'.";
634#if !defined(__PORTABLE_PLATFORM__)
635 if (absl::GetFlag(FLAGS_cp_model_load_debug_solution).empty())
return;
639 LOG(
INFO) <<
"Reading solution from '"
640 << absl::GetFlag(FLAGS_cp_model_load_debug_solution) <<
"'.";
646 debug_solution.resize(
648 for (
int i = 0; i <
response.solution().size(); ++i) {
649 if (!mapping.IsInteger(i))
continue;
650 const IntegerVariable
var = mapping.Integer(i);
658 if (objective_def ==
nullptr)
return;
660 const IntegerVariable objective_var = objective_def->
objective_var;
669 absl::MutexLock mutex_lock(&mutex_);
670 SetStatsFromModelInternal(
model);
673void SharedResponseManager::SetStatsFromModelInternal(
Model*
model) {
674 if (
model ==
nullptr)
return;
677 best_response_.set_num_booleans(sat_solver->NumVariables());
678 best_response_.set_num_branches(sat_solver->num_branches());
679 best_response_.set_num_conflicts(sat_solver->num_failures());
680 best_response_.set_num_binary_propagations(sat_solver->num_propagations());
681 best_response_.set_num_restarts(sat_solver->num_restarts());
682 best_response_.set_num_integer_propagations(
683 integer_trail ==
nullptr ? 0 : integer_trail->num_enqueues());
685 best_response_.set_wall_time(
time_limit->GetElapsedTime());
686 best_response_.set_deterministic_time(
689 int64_t num_lp_iters = 0;
692 num_lp_iters += lp->total_num_simplex_iterations();
694 best_response_.set_num_lp_iterations(num_lp_iters);
698 absl::MutexLock mutex_lock(&mutex_);
699 return best_response_.status() == CpSolverStatus::OPTIMAL ||
700 best_response_.status() == CpSolverStatus::INFEASIBLE;
704 if (improvement_info.empty())
return "";
707 for (
int i = 0; i < improvement_info.size(); ++i) {
708 if (!std::isalnum(improvement_info[i]) && improvement_info[i] !=
'_') {
709 return improvement_info.substr(0, i);
713 return improvement_info;
716void SharedResponseManager::RegisterSolutionFound(
717 const std::string& improvement_info) {
718 if (improvement_info.empty())
return;
722void SharedResponseManager::RegisterObjectiveBoundImprovement(
723 const std::string& improvement_info) {
724 if (improvement_info.empty() || improvement_info ==
"initial domain")
return;
729 absl::MutexLock mutex_lock(&mutex_);
730 if (!primal_improvements_count_.empty()) {
732 SOLVER_LOG(logger_,
"Solutions found per subsolver:");
733 for (
const auto& entry : primal_improvements_count_) {
734 SOLVER_LOG(logger_,
" '", entry.first,
"': ", entry.second);
737 if (!dual_improvements_count_.empty()) {
739 SOLVER_LOG(logger_,
"Objective bounds found per subsolver:");
740 for (
const auto& entry : dual_improvements_count_) {
741 SOLVER_LOG(logger_,
" '", entry.first,
"': ", entry.second);
749 lower_bounds_(num_variables_,
std::numeric_limits<int64_t>::
min()),
750 upper_bounds_(num_variables_,
std::numeric_limits<int64_t>::
max()),
751 synchronized_lower_bounds_(num_variables_,
752 std::numeric_limits<int64_t>::
min()),
753 synchronized_upper_bounds_(num_variables_,
754 std::numeric_limits<int64_t>::
max()) {
755 changed_variables_since_last_synchronize_.ClearAndResize(num_variables_);
756 for (
int i = 0; i < num_variables_; ++i) {
757 lower_bounds_[i] =
model_proto.variables(i).domain(0);
758 const int domain_size =
model_proto.variables(i).domain_size();
759 upper_bounds_[i] =
model_proto.variables(i).domain(domain_size - 1);
760 synchronized_lower_bounds_[i] = lower_bounds_[i];
761 synchronized_upper_bounds_[i] = upper_bounds_[i];
766 const CpModelProto&
model_proto,
const std::string& worker_name,
767 const std::vector<int>& variables,
768 const std::vector<int64_t>& new_lower_bounds,
769 const std::vector<int64_t>& new_upper_bounds) {
770 CHECK_EQ(variables.size(), new_lower_bounds.size());
771 CHECK_EQ(variables.size(), new_upper_bounds.size());
772 int num_improvements = 0;
774 absl::MutexLock mutex_lock(&mutex_);
775 for (
int i = 0; i < variables.size(); ++i) {
776 const int var = variables[i];
777 if (
var >= num_variables_)
continue;
778 const int64_t old_lb = lower_bounds_[
var];
779 const int64_t old_ub = upper_bounds_[
var];
780 const int64_t new_lb = new_lower_bounds[i];
781 const int64_t new_ub = new_upper_bounds[i];
782 const bool changed_lb = new_lb > old_lb;
783 const bool changed_ub = new_ub < old_ub;
785 if (!changed_lb && !changed_ub)
continue;
788 lower_bounds_[
var] = new_lb;
791 upper_bounds_[
var] = new_ub;
793 changed_variables_since_last_synchronize_.Set(
var);
796 if (num_improvements > 0) {
797 bounds_exported_[worker_name] += num_improvements;
805 const std::vector<int64_t>& solution,
806 const std::vector<int>& variables_to_fix) {
807 absl::MutexLock mutex_lock(&mutex_);
813 for (
const int var : variables_to_fix) {
814 const int64_t
value = solution[
var];
816 VLOG(1) <<
"Incompatibility in FixVariablesFromPartialSolution() "
817 <<
"var: " <<
var <<
" value: " <<
value <<
" bounds: ["
818 << lower_bounds_[
var] <<
"," << upper_bounds_[
var] <<
"]";
824 for (
const int var : variables_to_fix) {
825 const int64_t old_lb = lower_bounds_[
var];
826 const int64_t old_ub = upper_bounds_[
var];
827 const bool changed_lb = solution[
var] > old_lb;
828 const bool changed_ub = solution[
var] < old_ub;
829 if (!changed_lb && !changed_ub)
continue;
831 lower_bounds_[
var] = solution[
var];
832 upper_bounds_[
var] = solution[
var];
833 changed_variables_since_last_synchronize_.Set(
var);
838 absl::MutexLock mutex_lock(&mutex_);
840 changed_variables_since_last_synchronize_.PositionsSetAtLeastOnce()) {
841 synchronized_lower_bounds_[
var] = lower_bounds_[
var];
842 synchronized_upper_bounds_[
var] = upper_bounds_[
var];
843 for (
int j = 0; j < id_to_changed_variables_.size(); ++j) {
844 id_to_changed_variables_[j].Set(
var);
847 changed_variables_since_last_synchronize_.ClearAll();
851 absl::MutexLock mutex_lock(&mutex_);
852 const int id = id_to_changed_variables_.size();
853 id_to_changed_variables_.resize(
id + 1);
854 id_to_changed_variables_[id].ClearAndResize(num_variables_);
855 for (
int var = 0;
var < num_variables_; ++
var) {
856 const int64_t lb = model_proto_.variables(
var).domain(0);
857 const int domain_size = model_proto_.variables(
var).domain_size();
858 const int64_t ub = model_proto_.variables(
var).domain(domain_size - 1);
859 if (lb != synchronized_lower_bounds_[
var] ||
860 ub != synchronized_upper_bounds_[
var]) {
861 id_to_changed_variables_[id].Set(
var);
868 int id, std::vector<int>* variables, std::vector<int64_t>* new_lower_bounds,
869 std::vector<int64_t>* new_upper_bounds) {
871 new_lower_bounds->clear();
872 new_upper_bounds->clear();
874 absl::MutexLock mutex_lock(&mutex_);
875 for (
const int var : id_to_changed_variables_[
id].PositionsSetAtLeastOnce()) {
876 variables->push_back(
var);
877 new_lower_bounds->push_back(synchronized_lower_bounds_[
var]);
878 new_upper_bounds->push_back(synchronized_upper_bounds_[
var]);
880 id_to_changed_variables_[id].ClearAll();
884 absl::MutexLock mutex_lock(&mutex_);
885 if (!bounds_exported_.empty()) {
887 SOLVER_LOG(logger,
"Improving variable bounds shared per subsolver:");
888 for (
const auto& entry : bounds_exported_) {
889 SOLVER_LOG(logger,
" '", entry.first,
"': ", entry.second);
895 absl::MutexLock mutex_lock(&mutex_);
896 const auto it = bounds_exported_.find(worker_name);
897 if (it == bounds_exported_.end())
return 0;
902 absl::MutexLock mutex_lock(&mutex_);
903 const int id = id_to_last_processed_binary_clause_.size();
904 id_to_last_processed_binary_clause_.resize(
id + 1, 0);
905 id_to_clauses_exported_.resize(
id + 1, 0);
910 const std::string& worker_name) {
911 absl::MutexLock mutex_lock(&mutex_);
912 id_to_worker_name_[id] = worker_name;
916 absl::MutexLock mutex_lock(&mutex_);
919 const auto p = std::make_pair(lit1, lit2);
920 const auto [unused_it, inserted] = added_binary_clauses_set_.insert(p);
922 added_binary_clauses_.push_back(p);
923 id_to_clauses_exported_[id]++;
926 if (id_to_last_processed_binary_clause_[
id] ==
927 added_binary_clauses_.size() - 1) {
928 id_to_last_processed_binary_clause_[id]++;
934 int id, std::vector<std::pair<int, int>>* new_clauses) {
935 new_clauses->clear();
936 absl::MutexLock mutex_lock(&mutex_);
937 const int last_binary_clause_seen = id_to_last_processed_binary_clause_[id];
938 new_clauses->assign(added_binary_clauses_.begin() + last_binary_clause_seen,
939 added_binary_clauses_.end());
940 id_to_last_processed_binary_clause_[id] = added_binary_clauses_.size();
944 absl::MutexLock mutex_lock(&mutex_);
945 absl::btree_map<std::string, int64_t> name_to_clauses;
946 for (
int id = 0;
id < id_to_clauses_exported_.size(); ++id) {
947 if (id_to_clauses_exported_[
id] == 0)
continue;
948 name_to_clauses[id_to_worker_name_[id]] = id_to_clauses_exported_[id];
950 if (!name_to_clauses.empty()) {
952 SOLVER_LOG(logger,
"Clauses shared per subsolver:");
953 for (
const auto& entry : name_to_clauses) {
954 SOLVER_LOG(logger,
" '", entry.first,
"': ", entry.second);
#define DCHECK_LE(val1, val2)
#define CHECK_EQ(val1, val2)
#define CHECK_GE(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK_LT(val1, val2)
#define VLOG(verboselevel)
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
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
IntegerVariable NumIntegerVariables() const
Class that owns everything related to a particular optimization model.
SharedBoundsManager(const CpModelProto &model_proto)
void ReportPotentialNewBounds(const CpModelProto &model_proto, 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)
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 GetUnseenBinaryClauses(int id, std::vector< std::pair< int, int > > *new_clauses)
void LogStatistics(SolverLogger *logger)
void AddBinaryClause(int id, int lit1, int lit2)
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(const CpSolverResponse &response)
bool ProblemIsSolved() const
void InitializeObjective(const CpModelProto &cp_model)
void SetStatsFromModel(Model *model)
CpSolverResponse GetResponse(bool full_response=true)
void AddSolutionPostprocessor(std::function< void(std::vector< int64_t > *)> postprocessor)
void AddFinalResponsePostprocessor(std::function< void(CpSolverResponse *)> postprocessor)
IntegerValue GetInnerObjectiveUpperBound()
void LogPeriodicMessage(const std::string &prefix, const std::string &message, absl::Time *last_logging_time)
IntegerValue SynchronizedInnerObjectiveUpperBound()
IntegerValue SynchronizedInnerObjectiveLowerBound()
void NewSolution(const CpSolverResponse &response, Model *model)
void DisplayImprovementStatistics()
double GapIntegral() const
void NotifyThatImprovingProblemIsInfeasible(const std::string &worker_info)
void SetUpdateGapIntegralOnEachChange(bool set)
IntegerValue BestSolutionInnerObjectiveValue()
void AddUnsatCore(const std::vector< int > &core)
void SetGapLimitsFromParameters(const SatParameters ¶meters)
void AddResponsePostprocessor(std::function< void(CpSolverResponse *)> postprocessor)
int AddSolutionCallback(std::function< void(const CpSolverResponse &)> callback)
void LogMessage(const std::string &prefix, const std::string &message)
void LoadDebugSolution(Model *)
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_)
CpModelProto const * model_proto
SharedResponseManager * response
ModelSharedTimeLimit * time_limit
absl::Status GetTextProto(const absl::string_view &filename, google::protobuf::Message *proto, int flags)
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)
int64_t ComputeInnerObjective(const CpObjectiveProto &objective, const CpSolverResponse &response)
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::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
int64_t ScaleInnerObjectiveValue(const CpObjectiveProto &proto, int64_t value)
Collection of objects used to extend the Constraint Solver library.
IntegerVariable objective_var
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,...)