21 #include "absl/container/inlined_vector.h"
22 #include "absl/types/span.h"
31 #include "ortools/sat/sat_parameters.pb.h"
57 std::vector<BooleanVariable> bool_vars;
58 for (BooleanVariable
b(0);
b < num_variables; ++
b) {
64 bool_vars.push_back(
b);
69 bool Prober::ProbeOneVariableInternal(BooleanVariable
b) {
70 new_integer_bounds_.clear();
76 const int saved_index = trail_.
Index();
82 if (trail_.
Index() > saved_index) {
83 if (callback_ !=
nullptr) callback_(decision);
89 for (
int i = saved_index + 1; i < trail_.
Index(); ++i) {
90 const Literal l = trail_[i];
93 if (decision.IsPositive()) {
94 propagated_.
Set(l.Index());
96 if (propagated_[l.Index()]) {
97 to_fix_at_true_.push_back(l);
106 new_binary_clauses_.push_back({decision.Negated(), l});
112 for (
const Literal l : to_fix_at_true_) {
115 to_fix_at_true_.clear();
117 num_new_binary_ += new_binary_clauses_.size();
118 for (
auto binary : new_binary_clauses_) {
121 new_binary_clauses_.clear();
137 std::sort(new_integer_bounds_.begin(), new_integer_bounds_.end(),
138 [](IntegerLiteral
a, IntegerLiteral
b) { return a.var < b.var; });
144 new_integer_bounds_.push_back(IntegerLiteral());
146 for (
int i = 0; i < new_integer_bounds_.size(); ++i) {
147 const IntegerVariable
var = new_integer_bounds_[i].var;
151 if (ub_min + 1 < lb_max) {
156 const Domain old_domain =
159 Domain(ub_min.value() + 1, lb_max.value() - 1).Complement());
160 if (new_domain != old_domain) {
181 if (i == 0 || new_integer_bounds_[i - 1].
var !=
var)
continue;
182 const IntegerValue new_bound =
std::min(new_integer_bounds_[i - 1].
bound,
183 new_integer_bounds_[i].
bound);
185 ++num_new_integer_bounds_;
207 if (!ProbeOneVariableInternal(
b))
return false;
211 num_new_literals_fixed_ += num_fixed - initial_num_fixed;
216 const double deterministic_time_limit,
217 absl::Span<const BooleanVariable> bool_vars) {
224 num_new_integer_bounds_ = 0;
225 num_new_literals_fixed_ = 0;
236 const double initial_deterministic_time =
238 const double limit = initial_deterministic_time + deterministic_time_limit;
240 bool limit_reached =
false;
243 for (
const BooleanVariable
b : bool_vars) {
253 limit_reached =
true;
259 if (!ProbeOneVariableInternal(
b)) {
266 num_new_literals_fixed_ = num_fixed - initial_num_fixed;
270 const double time_diff =
272 SOLVER_LOG(logger_,
"[Probing] deterministic_time: ", time_diff,
273 " (limit: ", deterministic_time_limit,
275 (limit_reached ?
"Aborted " :
""), num_probed,
"/",
276 bool_vars.size(),
")");
277 if (num_new_literals_fixed_ > 0) {
279 "[Probing] - new fixed Boolean: ", num_new_literals_fixed_,
280 " (", num_fixed,
"/", sat_solver_->
NumVariables(),
")");
282 if (num_new_holes_ > 0) {
283 SOLVER_LOG(logger_,
"[Probing] - new integer holes: ", num_new_holes_);
285 if (num_new_integer_bounds_ > 0) {
287 "[Probing] - new integer bounds: ", num_new_integer_bounds_);
289 if (num_new_binary_ > 0) {
290 SOLVER_LOG(logger_,
"[Probing] - new binary clause: ", num_new_binary_);
304 if (!sat_solver->RestoreSolverToAssumptionLevel())
return false;
307 const int initial_num_fixed = sat_solver->LiteralTrail().Index();
312 SatParameters initial_params = *
model->GetOrCreate<SatParameters>();
313 SatParameters new_params = initial_params;
314 new_params.set_log_search_progress(
false);
315 new_params.set_max_number_of_conflicts(1);
316 new_params.set_max_deterministic_time(deterministic_time_limit);
318 double elapsed_dtime = 0.0;
320 const int num_times = 1000;
321 bool limit_reached =
false;
323 for (
int i = 0; i < num_times; ++i) {
325 elapsed_dtime > deterministic_time_limit) {
326 limit_reached =
true;
331 sat_solver->SetParameters(new_params);
332 sat_solver->ResetDecisionHeuristic();
337 SOLVER_LOG(logger,
"Trivial exploration found feasible solution!");
342 if (!sat_solver->RestoreSolverToAssumptionLevel()) {
343 SOLVER_LOG(logger,
"UNSAT during trivial exploration heuristic.");
351 new_params.set_random_seed(i);
352 new_params.set_max_deterministic_time(deterministic_time_limit -
357 sat_solver->SetParameters(initial_params);
358 sat_solver->ResetDecisionHeuristic();
360 if (!sat_solver->RestoreSolverToAssumptionLevel())
return false;
362 if (logger->LoggingIsEnabled()) {
363 const int num_fixed = sat_solver->LiteralTrail().Index();
364 const int num_newly_fixed = num_fixed - initial_num_fixed;
365 const int num_variables = sat_solver->NumVariables();
366 SOLVER_LOG(logger,
"Random exploration.",
" num_fixed: +", num_newly_fixed,
367 " (", num_fixed,
"/", num_variables,
")",
368 " dtime: ", elapsed_dtime,
"/", deterministic_time_limit,
370 (limit_reached ?
" (Aborted)" :
""));
372 return sat_solver->FinishPropagation();
383 if (!sat_solver->RestoreSolverToAssumptionLevel())
return false;
389 if (!implication_graph->DetectEquivalences())
return false;
390 if (!sat_solver->FinishPropagation())
return false;
393 const int initial_num_fixed = sat_solver->LiteralTrail().Index();
394 const double initial_deterministic_time =
398 const int num_variables = sat_solver->NumVariables();
401 int64_t num_probed = 0;
402 int64_t num_explicit_fix = 0;
403 int64_t num_conflicts = 0;
404 int64_t num_new_binary = 0;
405 int64_t num_subsumed = 0;
408 const auto& assignment = trail.Assignment();
411 const int clause_id = clause_manager->PropagatorId();
414 struct SavedNextLiteral {
415 LiteralIndex literal_index;
418 bool operator<(
const SavedNextLiteral& o)
const {
return rank < o.rank; }
420 std::vector<SavedNextLiteral> queue;
429 std::vector<Literal> to_fix;
443 std::vector<LiteralIndex> probing_order =
444 implication_graph->ReverseTopologicalOrder();
446 std::reverse(probing_order.begin(), probing_order.end());
451 position_in_order.
assign(2 * num_variables, -1);
452 for (
int i = 0; i < probing_order.size(); ++i) {
453 position_in_order[probing_order[i]] = i;
463 if (options.
use_queue && sat_solver->CurrentDecisionLevel() > 0) {
468 sat_solver->Decisions()[sat_solver->CurrentDecisionLevel() - 1]
471 implication_graph->Implications(prev_decision.
Negated());
472 const int saved_queue_size = queue.size();
475 if (processed[candidate.
Index()])
continue;
476 if (position_in_order[candidate.
Index()] == -1)
continue;
477 if (assignment.LiteralIsAssigned(candidate)) {
478 if (assignment.LiteralIsFalse(candidate)) {
484 {candidate.
Index(), -position_in_order[candidate.
Index()]});
486 std::sort(queue.begin() + saved_queue_size, queue.end());
489 while (!queue.empty()) {
490 const LiteralIndex
index = queue.back().literal_index;
494 CHECK_GT(sat_solver->CurrentDecisionLevel(), 0);
495 sat_solver->Backtrack(sat_solver->CurrentDecisionLevel() - 1);
499 if (processed[candidate.
Index()])
continue;
500 if (assignment.LiteralIsAssigned(candidate)) {
501 if (assignment.LiteralIsFalse(candidate)) {
506 next_decision = candidate.
Index();
511 if (sat_solver->CurrentDecisionLevel() == 0) {
514 if (!assignment.LiteralIsTrue(
literal)) {
516 sat_solver->AddUnitClause(
literal);
520 if (!sat_solver->FinishPropagation())
return false;
523 for (; order_index < probing_order.size(); ++order_index) {
524 const Literal candidate(probing_order[order_index]);
525 if (processed[candidate.
Index()])
continue;
526 if (assignment.LiteralIsAssigned(candidate))
continue;
527 next_decision = candidate.
Index();
534 const int level = sat_solver->CurrentDecisionLevel();
535 const Literal prev_decision = sat_solver->Decisions()[level - 1].literal;
537 implication_graph->Implications(prev_decision.
Negated());
544 for (
int i = 0; i < list.size(); ++i, ++j) {
547 if (processed[candidate.
Index()])
continue;
548 if (assignment.LiteralIsFalse(candidate)) {
555 if (assignment.LiteralIsTrue(candidate))
continue;
556 next_decision = candidate.
Index();
561 sat_solver->Backtrack(level - 1);
567 processed.
Set(next_decision);
570 const int level = sat_solver->CurrentDecisionLevel();
571 const int first_new_trail_index =
572 sat_solver->EnqueueDecisionAndBackjumpOnConflict(
574 const int new_level = sat_solver->CurrentDecisionLevel();
575 sat_solver->AdvanceDeterministicTime(
time_limit);
576 if (sat_solver->ModelIsUnsat())
return false;
577 if (new_level <= level) {
582 if (new_level == 0) {
585 int queue_level = level + 1;
586 while (queue_level > new_level) {
587 CHECK(!queue.empty());
609 if (sat_solver->CurrentDecisionLevel() != 0 ||
610 assignment.LiteralIsFalse(
Literal(next_decision))) {
611 to_fix.push_back(
Literal(next_decision).Negated());
618 if (new_level == 0)
continue;
620 sat_solver->Decisions()[new_level - 1].literal;
621 int num_new_subsumed = 0;
622 for (
int i = first_new_trail_index; i < trail.Index(); ++i) {
624 if (l == last_decision)
continue;
631 bool subsumed =
false;
633 trail.AssignmentType(l.
Variable()) == clause_id) {
635 if (lit == last_decision.
Negated()) {
643 implication_graph->AddBinaryClause(last_decision.
Negated(), l);
644 const int trail_index = trail.Info(l.
Variable()).trail_index;
648 clause_manager->ReasonClause(trail_index)->AsSpan()) {
649 if (lit == l) ++test;
650 if (lit == last_decision.
Negated()) ++test;
653 clause_manager->LazyDetach(clause_manager->ReasonClause(trail_index));
656 implication_graph->ChangeReason(trail_index, last_decision);
678 if (!subsumed && trail.AssignmentType(l.
Variable()) !=
id) {
680 implication_graph->AddBinaryClause(last_decision.
Negated(), l);
700 clause_manager->WatcherListOnFalse(last_decision.
Negated())) {
701 if (assignment.LiteralIsTrue(w.blocking_literal)) {
702 if (w.clause->empty())
continue;
703 CHECK_NE(w.blocking_literal, last_decision.
Negated());
713 if (trail.AssignmentType(w.blocking_literal.Variable()) !=
id) {
716 const auto& info = trail.Info(w.blocking_literal.Variable());
717 if (info.level > 0) {
719 implication_graph->AddBinaryClause(last_decision.
Negated(),
722 const Literal d = sat_solver->Decisions()[info.level - 1].literal;
723 if (d != w.blocking_literal) {
724 implication_graph->ChangeReason(info.trail_index, d);
730 clause_manager->LazyDetach(w.clause);
735 if (num_new_subsumed > 0) {
739 clause_manager->CleanUpWatchers();
740 num_subsumed += num_new_subsumed;
744 if (!sat_solver->ResetToLevelZero())
return false;
747 sat_solver->AddUnitClause(
literal);
750 if (!sat_solver->FinishPropagation())
return false;
753 const int num_fixed = sat_solver->LiteralTrail().
Index();
754 const int num_newly_fixed = num_fixed - initial_num_fixed;
755 const double time_diff =
761 <<
" num_probed: " << num_probed <<
" num_fixed: +" << num_newly_fixed
762 <<
" (" << num_fixed <<
"/" << num_variables <<
")"
763 <<
" explicit_fix:" << num_explicit_fix
764 <<
" num_conflicts:" << num_conflicts
765 <<
" new_binary_clauses: " << num_new_binary
766 <<
" subsumed: " << num_subsumed <<
" dtime: " << time_diff
767 <<
" wtime: " <<
wall_timer.
Get() << (limit_reached ?
" (Aborted)" :
"");
768 return sat_solver->FinishPropagation();
void assign(size_type n, const value_type &val)
void resize(size_type new_size)
An Assignment is a variable -> domains mapping, used to report solutions to the user.
Domain IntersectionWith(const Domain &domain) const
Returns the intersection of D and domain.
double GetElapsedDeterministicTime() const
bool LimitReached() const
void AdvanceDeterministicTime(double deterministic_duration)
bool LoggingIsEnabled() const
void Set(IntegerType index)
void ClearAndResize(IntegerType size)
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
bool LimitReached()
Returns true when the external limit is true, or the deterministic time is over the deterministic lim...
double GetElapsedDeterministicTime() const
Returns the elapsed deterministic time since the construction of this object.
Literal RepresentativeOf(Literal l) const
bool ProcessIntegerTrail(Literal first_decision)
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
void AppendNewBounds(std::vector< IntegerLiteral > *output) const
IntegerValue LowerBound(IntegerVariable i) const
const Domain & InitialVariableDomain(IntegerVariable var) const
bool UpdateInitialDomain(IntegerVariable var, Domain domain)
LiteralIndex NegatedIndex() const
LiteralIndex Index() const
BooleanVariable Variable() const
Class that owns everything related to a particular optimization model.
bool ProbeOneVariable(BooleanVariable b)
bool ProbeBooleanVariables(double deterministic_time_limit)
void ProcessTrailAtLevelOne()
const Trail & LiteralTrail() const
bool ModelIsUnsat() const
void SetAssumptionLevel(int assumption_level)
void AdvanceDeterministicTime(TimeLimit *limit)
const VariablesAssignment & Assignment() const
int EnqueueDecisionAndBackjumpOnConflict(Literal true_literal)
bool AddBinaryClause(Literal a, Literal b)
bool RestoreSolverToAssumptionLevel()
int CurrentDecisionLevel() const
bool AddUnitClause(Literal true_literal)
int AssignmentType(BooleanVariable var) const
bool LiteralIsAssigned(Literal literal) const
bool VariableIsAssigned(BooleanVariable var) const
ModelSharedTimeLimit * time_limit
void RandomizeDecisionHeuristic(absl::BitGenRef random, SatParameters *parameters)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
bool LookForTrivialSatSolution(double deterministic_time_limit, Model *model)
const LiteralIndex kNoLiteralIndex(-1)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
const IntegerVariable kNoIntegerVariable(-1)
IntegerVariable PositiveVariable(IntegerVariable i)
bool FailedLiteralProbingRound(ProbingOptions options, Model *model)
bool VariableIsPositive(IntegerVariable i)
Collection of objects used to extend the Constraint Solver library.
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
double deterministic_limit
bool subsume_with_binary_clause
bool extract_binary_clauses
#define SOLVER_LOG(logger,...)
#define VLOG_IS_ON(verboselevel)