46 std::vector<BooleanVariable> bool_vars;
47 for (BooleanVariable
b(0);
b < num_variables; ++
b) {
52 bool_vars.push_back(
b);
57bool Prober::ProbeOneVariableInternal(BooleanVariable
b) {
58 new_integer_bounds_.clear();
59 propagated_.SparseClearAll();
64 const int saved_index = trail_.
Index();
73 for (
int i = saved_index + 1; i < trail_.
Index(); ++i) {
74 const Literal l = trail_[i];
77 if (decision.IsPositive()) {
78 propagated_.Set(l.Index());
80 if (propagated_[l.Index()]) {
81 to_fix_at_true_.push_back(l);
90 new_binary_clauses_.push_back({decision.Negated(), l});
96 for (
const Literal l : to_fix_at_true_) {
99 to_fix_at_true_.clear();
101 num_new_binary_ += new_binary_clauses_.size();
102 for (
auto binary : new_binary_clauses_) {
105 new_binary_clauses_.clear();
121 std::sort(new_integer_bounds_.begin(), new_integer_bounds_.end(),
122 [](IntegerLiteral
a, IntegerLiteral
b) { return a.var < b.var; });
128 new_integer_bounds_.push_back(IntegerLiteral());
130 for (
int i = 0; i < new_integer_bounds_.size(); ++i) {
131 const IntegerVariable
var = new_integer_bounds_[i].var;
135 if (ub_min + 1 < lb_max) {
140 const Domain old_domain =
143 Domain(ub_min.value() + 1, lb_max.value() - 1).Complement());
144 if (new_domain != old_domain) {
165 if (i == 0 || new_integer_bounds_[i - 1].
var !=
var)
continue;
166 const IntegerValue new_bound =
std::min(new_integer_bounds_[i - 1].
bound,
167 new_integer_bounds_[i].
bound);
169 ++num_new_integer_bounds_;
185 num_new_integer_bounds_ = 0;
189 propagated_.ClearAndResize(LiteralIndex(2 * num_variables));
195 return ProbeOneVariableInternal(
b);
199 const double deterministic_time_limit,
200 absl::Span<const BooleanVariable> bool_vars) {
207 num_new_integer_bounds_ = 0;
211 propagated_.ClearAndResize(LiteralIndex(2 * num_variables));
218 const double initial_deterministic_time =
220 const double limit = initial_deterministic_time + deterministic_time_limit;
222 bool limit_reached =
false;
225 for (
const BooleanVariable
b : bool_vars) {
235 limit_reached =
true;
241 if (!ProbeOneVariableInternal(
b)) {
248 const double time_diff =
251 const int num_newly_fixed = num_fixed - initial_num_fixed;
252 SOLVER_LOG(logger_,
"[Probing] deterministic_time: ", time_diff,
253 " (limit: ", deterministic_time_limit,
255 (limit_reached ?
"Aborted " :
""), num_probed,
"/",
256 bool_vars.size(),
")");
257 if (num_newly_fixed > 0) {
258 SOLVER_LOG(logger_,
"[Probing] - new fixed Boolean: ", num_newly_fixed,
259 " (", num_fixed,
"/", sat_solver_->
NumVariables(),
")");
261 if (num_new_holes_ > 0) {
262 SOLVER_LOG(logger_,
"[Probing] - new integer holes: ", num_new_holes_);
264 if (num_new_integer_bounds_ > 0) {
266 "[Probing] - new integer bounds: ", num_new_integer_bounds_);
268 if (num_new_binary_ > 0) {
269 SOLVER_LOG(logger_,
"[Probing] - new binary clause: ", num_new_binary_);
283 if (!sat_solver->RestoreSolverToAssumptionLevel())
return false;
286 const int initial_num_fixed = sat_solver->LiteralTrail().Index();
294 new_params.set_max_number_of_conflicts(1);
295 new_params.set_max_deterministic_time(deterministic_time_limit);
297 double elapsed_dtime = 0.0;
299 const int num_times = 1000;
300 bool limit_reached =
false;
302 for (
int i = 0; i < num_times; ++i) {
304 elapsed_dtime > deterministic_time_limit) {
305 limit_reached =
true;
310 sat_solver->SetParameters(new_params);
311 sat_solver->ResetDecisionHeuristic();
316 SOLVER_LOG(logger,
"Trivial exploration found feasible solution!");
321 if (!sat_solver->RestoreSolverToAssumptionLevel()) {
322 SOLVER_LOG(logger,
"UNSAT during trivial exploration heuristic.");
330 new_params.set_random_seed(i);
331 new_params.set_max_deterministic_time(deterministic_time_limit -
336 sat_solver->SetParameters(initial_params);
337 sat_solver->ResetDecisionHeuristic();
339 if (!sat_solver->RestoreSolverToAssumptionLevel())
return false;
341 if (logger->LoggingIsEnabled()) {
342 const int num_fixed = sat_solver->LiteralTrail().Index();
343 const int num_newly_fixed = num_fixed - initial_num_fixed;
344 const int num_variables = sat_solver->NumVariables();
345 SOLVER_LOG(logger,
"Random exploration.",
" num_fixed: +", num_newly_fixed,
346 " (", num_fixed,
"/", num_variables,
")",
347 " dtime: ", elapsed_dtime,
"/", deterministic_time_limit,
349 (limit_reached ?
" (Aborted)" :
""));
351 return sat_solver->FinishPropagation();
362 if (!sat_solver->RestoreSolverToAssumptionLevel())
return false;
368 if (!implication_graph->DetectEquivalences())
return false;
369 if (!sat_solver->FinishPropagation())
return false;
372 const int initial_num_fixed = sat_solver->LiteralTrail().Index();
373 const double initial_deterministic_time =
377 const int num_variables = sat_solver->NumVariables();
380 int64_t num_probed = 0;
381 int64_t num_explicit_fix = 0;
382 int64_t num_conflicts = 0;
383 int64_t num_new_binary = 0;
384 int64_t num_subsumed = 0;
387 const auto& assignment = trail.Assignment();
390 const int clause_id = clause_manager->PropagatorId();
393 struct SavedNextLiteral {
394 LiteralIndex literal_index;
397 bool operator<(
const SavedNextLiteral& o)
const {
return rank < o.rank; }
399 std::vector<SavedNextLiteral> queue;
408 std::vector<Literal> to_fix;
422 std::vector<LiteralIndex> probing_order =
423 implication_graph->ReverseTopologicalOrder();
425 std::reverse(probing_order.begin(), probing_order.end());
430 position_in_order.
assign(2 * num_variables, -1);
431 for (
int i = 0; i < probing_order.size(); ++i) {
432 position_in_order[probing_order[i]] = i;
442 if (options.
use_queue && sat_solver->CurrentDecisionLevel() > 0) {
447 sat_solver->Decisions()[sat_solver->CurrentDecisionLevel() - 1]
450 implication_graph->Implications(prev_decision.
Negated());
451 const int saved_queue_size = queue.size();
454 if (processed[candidate.
Index()])
continue;
455 if (position_in_order[candidate.
Index()] == -1)
continue;
456 if (assignment.LiteralIsAssigned(candidate)) {
457 if (assignment.LiteralIsFalse(candidate)) {
463 {candidate.
Index(), -position_in_order[candidate.
Index()]});
465 std::sort(queue.begin() + saved_queue_size, queue.end());
468 while (!queue.empty()) {
469 const LiteralIndex
index = queue.back().literal_index;
473 CHECK_GT(sat_solver->CurrentDecisionLevel(), 0);
474 sat_solver->Backtrack(sat_solver->CurrentDecisionLevel() - 1);
478 if (processed[candidate.
Index()])
continue;
479 if (assignment.LiteralIsAssigned(candidate)) {
480 if (assignment.LiteralIsFalse(candidate)) {
485 next_decision = candidate.
Index();
490 if (sat_solver->CurrentDecisionLevel() == 0) {
493 if (!assignment.LiteralIsTrue(
literal)) {
495 sat_solver->AddUnitClause(
literal);
499 if (!sat_solver->FinishPropagation())
return false;
502 for (; order_index < probing_order.size(); ++order_index) {
503 const Literal candidate(probing_order[order_index]);
504 if (processed[candidate.
Index()])
continue;
505 if (assignment.LiteralIsAssigned(candidate))
continue;
506 next_decision = candidate.
Index();
513 const int level = sat_solver->CurrentDecisionLevel();
514 const Literal prev_decision = sat_solver->Decisions()[level - 1].literal;
516 implication_graph->Implications(prev_decision.
Negated());
523 for (
int i = 0; i < list.size(); ++i, ++j) {
526 if (processed[candidate.
Index()])
continue;
527 if (assignment.LiteralIsFalse(candidate)) {
534 if (assignment.LiteralIsTrue(candidate))
continue;
535 next_decision = candidate.
Index();
540 sat_solver->Backtrack(level - 1);
546 processed.
Set(next_decision);
549 const int level = sat_solver->CurrentDecisionLevel();
550 const int first_new_trail_index =
551 sat_solver->EnqueueDecisionAndBackjumpOnConflict(
553 const int new_level = sat_solver->CurrentDecisionLevel();
554 sat_solver->AdvanceDeterministicTime(
time_limit);
555 if (sat_solver->IsModelUnsat())
return false;
556 if (new_level <= level) {
561 if (new_level == 0) {
564 int queue_level = level + 1;
565 while (queue_level > new_level) {
566 CHECK(!queue.empty());
588 if (sat_solver->CurrentDecisionLevel() != 0 ||
589 assignment.LiteralIsFalse(
Literal(next_decision))) {
590 to_fix.push_back(
Literal(next_decision).Negated());
597 if (new_level == 0)
continue;
599 sat_solver->Decisions()[new_level - 1].literal;
600 int num_new_subsumed = 0;
601 for (
int i = first_new_trail_index; i < trail.Index(); ++i) {
603 if (l == last_decision)
continue;
610 bool subsumed =
false;
612 trail.AssignmentType(l.
Variable()) == clause_id) {
614 if (lit == last_decision.
Negated()) {
622 implication_graph->AddBinaryClause(last_decision.
Negated(), l);
623 const int trail_index = trail.Info(l.
Variable()).trail_index;
627 clause_manager->ReasonClause(trail_index)->AsSpan()) {
628 if (lit == l) ++test;
629 if (lit == last_decision.
Negated()) ++test;
632 clause_manager->LazyDetach(clause_manager->ReasonClause(trail_index));
635 implication_graph->ChangeReason(trail_index, last_decision);
657 if (!subsumed && trail.AssignmentType(l.
Variable()) !=
id) {
659 implication_graph->AddBinaryClause(last_decision.
Negated(), l);
679 clause_manager->WatcherListOnFalse(last_decision.
Negated())) {
680 if (assignment.LiteralIsTrue(w.blocking_literal)) {
681 if (w.clause->empty())
continue;
692 if (trail.AssignmentType(w.blocking_literal.Variable()) !=
id) {
694 implication_graph->AddBinaryClause(last_decision.
Negated(),
697 const auto& info = trail.Info(w.blocking_literal.Variable());
698 if (info.level > 0) {
699 const Literal d = sat_solver->Decisions()[info.level - 1].literal;
700 if (d != w.blocking_literal) {
701 implication_graph->ChangeReason(info.trail_index, d);
707 clause_manager->LazyDetach(w.clause);
712 if (num_new_subsumed > 0) {
716 clause_manager->CleanUpWatchers();
717 num_subsumed += num_new_subsumed;
721 if (!sat_solver->ResetToLevelZero())
return false;
724 sat_solver->AddUnitClause(
literal);
727 if (!sat_solver->FinishPropagation())
return false;
730 const int num_fixed = sat_solver->LiteralTrail().
Index();
731 const int num_newly_fixed = num_fixed - initial_num_fixed;
732 const double time_diff =
738 <<
" num_probed: " << num_probed <<
" num_fixed: +" << num_newly_fixed
739 <<
" (" << num_fixed <<
"/" << num_variables <<
")"
740 <<
" explicit_fix:" << num_explicit_fix
741 <<
" num_conflicts:" << num_conflicts
742 <<
" new_binary_clauses: " << num_new_binary
743 <<
" subsumed: " << num_subsumed <<
" dtime: " << time_diff
744 <<
" wtime: " <<
wall_timer.
Get() << (limit_reached ?
" (Aborted)" :
"");
745 return sat_solver->FinishPropagation();
#define LOG_IF(severity, condition)
#define CHECK_EQ(val1, val2)
#define CHECK_GT(val1, val2)
#define CHECK_NE(val1, val2)
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)
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
void 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 set_log_search_progress(bool value)
const Trail & LiteralTrail() const
void SetAssumptionLevel(int assumption_level)
void AdvanceDeterministicTime(TimeLimit *limit)
int EnqueueDecisionAndBackjumpOnConflict(Literal true_literal)
bool AddBinaryClause(Literal a, Literal b)
bool RestoreSolverToAssumptionLevel()
bool IsModelUnsat() const
int CurrentDecisionLevel() const
bool AddUnitClause(Literal true_literal)
int AssignmentType(BooleanVariable var) const
bool LiteralIsAssigned(Literal literal) const
ModelSharedTimeLimit * time_limit
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)
const IntegerVariable kNoIntegerVariable(-1)
IntegerVariable PositiveVariable(IntegerVariable i)
bool FailedLiteralProbingRound(ProbingOptions options, Model *model)
bool VariableIsPositive(IntegerVariable i)
void RandomizeDecisionHeuristic(URBG *random, SatParameters *parameters)
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)