OR-Tools  9.0
sat_solver.cc
Go to the documentation of this file.
1 // Copyright 2010-2021 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #include "ortools/sat/sat_solver.h"
15 
16 #include <algorithm>
17 #include <cstddef>
18 #include <cstdint>
19 #include <memory>
20 #include <random>
21 #include <string>
22 #include <type_traits>
23 #include <vector>
24 
25 #include "absl/strings/str_format.h"
27 #include "ortools/base/logging.h"
28 #include "ortools/base/map_util.h"
29 #include "ortools/base/stl_util.h"
31 #include "ortools/port/sysinfo.h"
32 #include "ortools/sat/util.h"
34 
35 namespace operations_research {
36 namespace sat {
37 
39  owned_model_.reset(model_);
40  model_->Register<SatSolver>(this);
41 }
42 
44  : model_(model),
45  binary_implication_graph_(model->GetOrCreate<BinaryImplicationGraph>()),
46  clauses_propagator_(model->GetOrCreate<LiteralWatchers>()),
47  pb_constraints_(model->GetOrCreate<PbConstraints>()),
48  track_binary_clauses_(false),
49  trail_(model->GetOrCreate<Trail>()),
50  time_limit_(model->GetOrCreate<TimeLimit>()),
51  parameters_(model->GetOrCreate<SatParameters>()),
52  restart_(model->GetOrCreate<RestartPolicy>()),
53  decision_policy_(model->GetOrCreate<SatDecisionPolicy>()),
54  clause_activity_increment_(1.0),
55  same_reason_identifier_(*trail_),
56  is_relevant_for_core_computation_(true),
57  problem_is_pure_sat_(true),
58  drat_proof_handler_(nullptr),
59  stats_("SatSolver") {
60  InitializePropagators();
61 }
62 
64 
65 void SatSolver::SetNumVariables(int num_variables) {
66  SCOPED_TIME_STAT(&stats_);
67  CHECK_GE(num_variables, num_variables_);
68 
69  num_variables_ = num_variables;
70  binary_implication_graph_->Resize(num_variables);
71  clauses_propagator_->Resize(num_variables);
72  trail_->Resize(num_variables);
73  decision_policy_->IncreaseNumVariables(num_variables);
74  pb_constraints_->Resize(num_variables);
75  same_reason_identifier_.Resize(num_variables);
76 
77  // The +1 is a bit tricky, it is because in
78  // EnqueueDecisionAndBacktrackOnConflict() we artificially enqueue the
79  // decision before checking if it is not already assigned.
80  decisions_.resize(num_variables + 1);
81 }
82 
83 int64_t SatSolver::num_branches() const { return counters_.num_branches; }
84 
85 int64_t SatSolver::num_failures() const { return counters_.num_failures; }
86 
87 int64_t SatSolver::num_propagations() const {
88  return trail_->NumberOfEnqueues() - counters_.num_branches;
89 }
90 
91 int64_t SatSolver::num_restarts() const { return counters_.num_restarts; }
92 
94  // Each of these counters mesure really basic operations. The weight are just
95  // an estimate of the operation complexity. Note that these counters are never
96  // reset to zero once a SatSolver is created.
97  //
98  // TODO(user): Find a better procedure to fix the weight than just educated
99  // guess.
100  return 1e-8 * (8.0 * trail_->NumberOfEnqueues() +
101  1.0 * binary_implication_graph_->num_inspections() +
102  4.0 * clauses_propagator_->num_inspected_clauses() +
103  1.0 * clauses_propagator_->num_inspected_clause_literals() +
104 
105  // Here there is a factor 2 because of the untrail.
106  20.0 * pb_constraints_->num_constraint_lookups() +
107  2.0 * pb_constraints_->num_threshold_updates() +
108  1.0 * pb_constraints_->num_inspected_constraint_literals());
109 }
110 
111 const SatParameters& SatSolver::parameters() const {
112  SCOPED_TIME_STAT(&stats_);
113  return *parameters_;
114 }
115 
116 void SatSolver::SetParameters(const SatParameters& parameters) {
117  SCOPED_TIME_STAT(&stats_);
118  *parameters_ = parameters;
119  restart_->Reset();
120  time_limit_->ResetLimitFromParameters(parameters);
121 }
122 
123 bool SatSolver::IsMemoryLimitReached() const {
124  const int64_t memory_usage =
126  const int64_t kMegaByte = 1024 * 1024;
127  return memory_usage > kMegaByte * parameters_->max_memory_in_mb();
128 }
129 
130 bool SatSolver::SetModelUnsat() {
131  model_is_unsat_ = true;
132  return false;
133 }
134 
135 bool SatSolver::AddClauseDuringSearch(absl::Span<const Literal> literals) {
136  if (model_is_unsat_) return false;
137  const int index = trail_->Index();
138  if (literals.empty()) return SetModelUnsat();
139  if (literals.size() == 1) return AddUnitClause(literals[0]);
140  if (literals.size() == 2) {
141  const bool init = binary_implication_graph_->num_implications() == 0;
142  if (!binary_implication_graph_->AddBinaryClauseDuringSearch(literals[0],
143  literals[1])) {
145  return SetModelUnsat();
146  }
147  if (init) {
148  // This is needed because we just added the first binary clause.
149  InitializePropagators();
150  }
151  } else {
152  if (!clauses_propagator_->AddClause(literals)) {
154  return SetModelUnsat();
155  }
156  }
157 
158  // Tricky: Even if nothing new is propagated, calling Propagate() might, via
159  // the LP, deduce new things. This is problematic because some code assumes
160  // that when we create newly associated literals, nothing else changes.
161  if (trail_->Index() == index) return true;
162  return FinishPropagation();
163 }
164 
165 bool SatSolver::AddUnitClause(Literal true_literal) {
166  SCOPED_TIME_STAT(&stats_);
168  if (model_is_unsat_) return false;
169  if (trail_->Assignment().LiteralIsFalse(true_literal)) return SetModelUnsat();
170  if (trail_->Assignment().LiteralIsTrue(true_literal)) return true;
171  if (drat_proof_handler_ != nullptr) {
172  // Note that we will output problem unit clauses twice, but that is a small
173  // price to pay for having a single variable fixing API.
174  drat_proof_handler_->AddClause({true_literal});
175  }
176  trail_->EnqueueWithUnitReason(true_literal);
177  if (!Propagate()) return SetModelUnsat();
178  return true;
179 }
180 
182  SCOPED_TIME_STAT(&stats_);
183  tmp_pb_constraint_.clear();
184  tmp_pb_constraint_.push_back(LiteralWithCoeff(a, 1));
185  tmp_pb_constraint_.push_back(LiteralWithCoeff(b, 1));
186  return AddLinearConstraint(
187  /*use_lower_bound=*/true, /*lower_bound=*/Coefficient(1),
188  /*use_upper_bound=*/false, /*upper_bound=*/Coefficient(0),
189  &tmp_pb_constraint_);
190 }
191 
193  SCOPED_TIME_STAT(&stats_);
194  tmp_pb_constraint_.clear();
195  tmp_pb_constraint_.push_back(LiteralWithCoeff(a, 1));
196  tmp_pb_constraint_.push_back(LiteralWithCoeff(b, 1));
197  tmp_pb_constraint_.push_back(LiteralWithCoeff(c, 1));
198  return AddLinearConstraint(
199  /*use_lower_bound=*/true, /*lower_bound=*/Coefficient(1),
200  /*use_upper_bound=*/false, /*upper_bound=*/Coefficient(0),
201  &tmp_pb_constraint_);
202 }
203 
204 bool SatSolver::AddProblemClause(absl::Span<const Literal> literals) {
205  SCOPED_TIME_STAT(&stats_);
206 
207  // TODO(user): To avoid duplication, we currently just call
208  // AddLinearConstraint(). Make a faster specific version if that becomes a
209  // performance issue.
210  tmp_pb_constraint_.clear();
211  for (Literal lit : literals) {
212  tmp_pb_constraint_.push_back(LiteralWithCoeff(lit, 1));
213  }
214  return AddLinearConstraint(
215  /*use_lower_bound=*/true, /*lower_bound=*/Coefficient(1),
216  /*use_upper_bound=*/false, /*upper_bound=*/Coefficient(0),
217  &tmp_pb_constraint_);
218 }
219 
220 bool SatSolver::AddProblemClauseInternal(absl::Span<const Literal> literals) {
221  SCOPED_TIME_STAT(&stats_);
223 
224  // Deals with clause of size 0 (always false) and 1 (set a literal) right away
225  // so we guarantee that a SatClause is always of size greater than one. This
226  // simplifies the code.
227  CHECK_GT(literals.size(), 0);
228  if (literals.size() == 1) {
229  if (trail_->Assignment().LiteralIsFalse(literals[0])) return false;
230  if (trail_->Assignment().LiteralIsTrue(literals[0])) return true;
231  trail_->EnqueueWithUnitReason(literals[0]); // Not assigned.
232  return true;
233  }
234 
235  if (parameters_->treat_binary_clauses_separately() && literals.size() == 2) {
236  AddBinaryClauseInternal(literals[0], literals[1]);
237  } else {
238  if (!clauses_propagator_->AddClause(literals, trail_)) {
239  return SetModelUnsat();
240  }
241  }
242  return true;
243 }
244 
245 bool SatSolver::AddLinearConstraintInternal(
246  const std::vector<LiteralWithCoeff>& cst, Coefficient rhs,
247  Coefficient max_value) {
248  SCOPED_TIME_STAT(&stats_);
250  if (rhs < 0) return SetModelUnsat(); // Unsatisfiable constraint.
251  if (rhs >= max_value) return true; // Always satisfied constraint.
252 
253  // The case "rhs = 0" will just fix variables, so there is no need to
254  // updates the weighted sign.
255  if (rhs > 0) decision_policy_->UpdateWeightedSign(cst, rhs);
256 
257  // Since the constraint is in canonical form, the coefficients are sorted.
258  const Coefficient min_coeff = cst.front().coefficient;
259  const Coefficient max_coeff = cst.back().coefficient;
260 
261  // A linear upper bounded constraint is a clause if the only problematic
262  // assignment is the one where all the literals are true.
263  if (max_value - min_coeff <= rhs) {
264  // This constraint is actually a clause. It is faster to treat it as one.
265  literals_scratchpad_.clear();
266  for (const LiteralWithCoeff& term : cst) {
267  literals_scratchpad_.push_back(term.literal.Negated());
268  }
269  return AddProblemClauseInternal(literals_scratchpad_);
270  }
271 
272  // Detect at most one constraints. Note that this use the fact that the
273  // coefficient are sorted.
274  if (parameters_->treat_binary_clauses_separately() &&
275  !parameters_->use_pb_resolution() && max_coeff <= rhs &&
276  2 * min_coeff > rhs) {
277  literals_scratchpad_.clear();
278  for (const LiteralWithCoeff& term : cst) {
279  literals_scratchpad_.push_back(term.literal);
280  }
281  if (!binary_implication_graph_->AddAtMostOne(literals_scratchpad_)) {
282  return SetModelUnsat();
283  }
284 
285  // In case this is the first constraint in the binary_implication_graph_.
286  // TODO(user): refactor so this is not needed!
287  InitializePropagators();
288  return true;
289  }
290 
291  problem_is_pure_sat_ = false;
292 
293  // TODO(user): If this constraint forces all its literal to false (when rhs is
294  // zero for instance), we still add it. Optimize this?
295  const bool result = pb_constraints_->AddConstraint(cst, rhs, trail_);
296  InitializePropagators();
297  return result;
298 }
299 
300 bool SatSolver::AddLinearConstraint(bool use_lower_bound,
301  Coefficient lower_bound,
302  bool use_upper_bound,
303  Coefficient upper_bound,
304  std::vector<LiteralWithCoeff>* cst) {
305  SCOPED_TIME_STAT(&stats_);
307  if (model_is_unsat_) return false;
308 
309  // This block removes assigned literals from the constraint.
310  Coefficient fixed_variable_shift(0);
311  {
312  int index = 0;
313  for (const LiteralWithCoeff& term : *cst) {
314  if (trail_->Assignment().LiteralIsFalse(term.literal)) continue;
315  if (trail_->Assignment().LiteralIsTrue(term.literal)) {
316  CHECK(SafeAddInto(-term.coefficient, &fixed_variable_shift));
317  continue;
318  }
319  (*cst)[index] = term;
320  ++index;
321  }
322  cst->resize(index);
323  }
324 
325  // Canonicalize the constraint.
326  // TODO(user): fix variables that must be true/false and remove them.
327  Coefficient bound_shift;
328  Coefficient max_value;
330  &max_value));
331  CHECK(SafeAddInto(fixed_variable_shift, &bound_shift));
332 
333  if (use_upper_bound) {
334  const Coefficient rhs =
335  ComputeCanonicalRhs(upper_bound, bound_shift, max_value);
336  if (!AddLinearConstraintInternal(*cst, rhs, max_value)) {
337  return SetModelUnsat();
338  }
339  }
340  if (use_lower_bound) {
341  // We transform the constraint into an upper-bounded one.
342  for (int i = 0; i < cst->size(); ++i) {
343  (*cst)[i].literal = (*cst)[i].literal.Negated();
344  }
345  const Coefficient rhs =
346  ComputeNegatedCanonicalRhs(lower_bound, bound_shift, max_value);
347  if (!AddLinearConstraintInternal(*cst, rhs, max_value)) {
348  return SetModelUnsat();
349  }
350  }
351 
352  // Tricky: The PropagationIsDone() condition shouldn't change anything for a
353  // pure SAT problem, however in the CP-SAT context, calling Propagate() can
354  // tigger computation (like the LP) even if no domain changed since the last
355  // call. We do not want to do that.
356  if (!PropagationIsDone() && !Propagate()) {
357  return SetModelUnsat();
358  }
359  return true;
360 }
361 
362 int SatSolver::AddLearnedClauseAndEnqueueUnitPropagation(
363  const std::vector<Literal>& literals, bool is_redundant) {
364  SCOPED_TIME_STAT(&stats_);
365 
366  if (literals.size() == 1) {
367  // A length 1 clause fix a literal for all the search.
368  // ComputeBacktrackLevel() should have returned 0.
370  trail_->EnqueueWithUnitReason(literals[0]);
371  return /*lbd=*/1;
372  }
373 
374  if (literals.size() == 2 && parameters_->treat_binary_clauses_separately()) {
375  if (track_binary_clauses_) {
376  CHECK(binary_clauses_.Add(BinaryClause(literals[0], literals[1])));
377  }
378  CHECK(binary_implication_graph_->AddBinaryClauseDuringSearch(literals[0],
379  literals[1]));
380  // In case this is the first binary clauses.
381  InitializePropagators();
382  return /*lbd=*/2;
383  }
384 
385  CleanClauseDatabaseIfNeeded();
386 
387  // Important: Even though the only literal at the last decision level has
388  // been unassigned, its level was not modified, so ComputeLbd() works.
389  const int lbd = ComputeLbd(literals);
390  if (is_redundant && lbd > parameters_->clause_cleanup_lbd_bound()) {
391  --num_learned_clause_before_cleanup_;
392 
393  SatClause* clause =
394  clauses_propagator_->AddRemovableClause(literals, trail_);
395 
396  // BumpClauseActivity() must be called after clauses_info_[clause] has
397  // been created or it will have no effect.
398  (*clauses_propagator_->mutable_clauses_info())[clause].lbd = lbd;
399  BumpClauseActivity(clause);
400  } else {
401  CHECK(clauses_propagator_->AddClause(literals, trail_));
402  }
403  return lbd;
404 }
405 
408  problem_is_pure_sat_ = false;
409  trail_->RegisterPropagator(propagator);
410  external_propagators_.push_back(propagator);
411  InitializePropagators();
412 }
413 
416  CHECK(last_propagator_ == nullptr);
417  problem_is_pure_sat_ = false;
418  trail_->RegisterPropagator(propagator);
419  last_propagator_ = propagator;
420  InitializePropagators();
421 }
422 
423 UpperBoundedLinearConstraint* SatSolver::ReasonPbConstraintOrNull(
424  BooleanVariable var) const {
425  // It is important to deal properly with "SameReasonAs" variables here.
427  const AssignmentInfo& info = trail_->Info(var);
428  if (trail_->AssignmentType(var) == pb_constraints_->PropagatorId()) {
429  return pb_constraints_->ReasonPbConstraint(info.trail_index);
430  }
431  return nullptr;
432 }
433 
434 SatClause* SatSolver::ReasonClauseOrNull(BooleanVariable var) const {
436  const AssignmentInfo& info = trail_->Info(var);
437  if (trail_->AssignmentType(var) == clauses_propagator_->PropagatorId()) {
438  return clauses_propagator_->ReasonClause(info.trail_index);
439  }
440  return nullptr;
441 }
442 
444  debug_assignment_.Resize(num_variables_.value());
445  for (BooleanVariable i(0); i < num_variables_; ++i) {
446  debug_assignment_.AssignFromTrueLiteral(
448  }
449 }
450 
451 void SatSolver::AddBinaryClauseInternal(Literal a, Literal b) {
452  if (!track_binary_clauses_ || binary_clauses_.Add(BinaryClause(a, b))) {
453  binary_implication_graph_->AddBinaryClause(a, b);
454 
455  // In case this is the first binary clauses.
456  InitializePropagators();
457  }
458 }
459 
460 bool SatSolver::ClauseIsValidUnderDebugAssignement(
461  const std::vector<Literal>& clause) const {
462  for (Literal l : clause) {
463  if (l.Variable() >= debug_assignment_.NumberOfVariables() ||
464  debug_assignment_.LiteralIsTrue(l)) {
465  return true;
466  }
467  }
468  return false;
469 }
470 
471 bool SatSolver::PBConstraintIsValidUnderDebugAssignment(
472  const std::vector<LiteralWithCoeff>& cst, const Coefficient rhs) const {
473  Coefficient sum(0.0);
474  for (LiteralWithCoeff term : cst) {
475  if (term.literal.Variable() >= debug_assignment_.NumberOfVariables()) {
476  continue;
477  }
478  if (debug_assignment_.LiteralIsTrue(term.literal)) {
479  sum += term.coefficient;
480  }
481  }
482  return sum <= rhs;
483 }
484 
485 namespace {
486 
487 // Returns true iff 'b' is subsumed by 'a' (i.e 'a' is included in 'b').
488 // This is slow and only meant to be used in DCHECKs.
489 bool ClauseSubsumption(const std::vector<Literal>& a, SatClause* b) {
490  std::vector<Literal> superset(b->begin(), b->end());
491  std::vector<Literal> subset(a.begin(), a.end());
492  std::sort(superset.begin(), superset.end());
493  std::sort(subset.begin(), subset.end());
494  return std::includes(superset.begin(), superset.end(), subset.begin(),
495  subset.end());
496 }
497 
498 } // namespace
499 
501  SCOPED_TIME_STAT(&stats_);
502  if (model_is_unsat_) return kUnsatTrailIndex;
503  CHECK(PropagationIsDone());
504  EnqueueNewDecision(true_literal);
505  while (!PropagateAndStopAfterOneConflictResolution()) {
506  if (model_is_unsat_) return kUnsatTrailIndex;
507  }
508  CHECK(PropagationIsDone());
509  return last_decision_or_backtrack_trail_index_;
510 }
511 
513  if (model_is_unsat_) return false;
514  if (CurrentDecisionLevel() > assumption_level_) {
515  Backtrack(assumption_level_);
516  return true;
517  }
518  if (!FinishPropagation()) return false;
520 }
521 
523  if (model_is_unsat_) return false;
524  while (!PropagateAndStopAfterOneConflictResolution()) {
525  if (model_is_unsat_) return false;
526  }
527  return true;
528 }
529 
531  if (model_is_unsat_) return false;
532  assumption_level_ = 0;
533  Backtrack(0);
534  return FinishPropagation();
535 }
536 
538  const std::vector<Literal>& assumptions) {
539  if (!ResetToLevelZero()) return false;
540 
541  // Assuming there is no duplicate in assumptions, but they can be a literal
542  // and its negation (weird corner case), there will always be a conflict if we
543  // enqueue stricly more assumptions than the number of variables, so there is
544  // no point considering the end of the list. Note that there is no overflow
545  // since decisions_.size() == num_variables_ + 1;
546  assumption_level_ =
547  std::min<int>(assumptions.size(), num_variables_.value() + 1);
548  for (int i = 0; i < assumption_level_; ++i) {
549  decisions_[i].literal = assumptions[i];
550  }
552 }
553 
554 // Note that we do not count these as "branches" for a reporting purpose.
556  if (model_is_unsat_) return false;
557  if (CurrentDecisionLevel() >= assumption_level_) return true;
558 
559  int unused = 0;
560  const int64_t old_num_branches = counters_.num_branches;
561  const SatSolver::Status status =
562  ReapplyDecisionsUpTo(assumption_level_ - 1, &unused);
563  counters_.num_branches = old_num_branches;
564  assumption_level_ = CurrentDecisionLevel();
565  return (status == SatSolver::FEASIBLE);
566 }
567 
568 bool SatSolver::PropagateAndStopAfterOneConflictResolution() {
569  SCOPED_TIME_STAT(&stats_);
570  if (Propagate()) return true;
571 
572  ++counters_.num_failures;
573  const int conflict_trail_index = trail_->Index();
574  const int conflict_decision_level = current_decision_level_;
575 
576  // A conflict occurred, compute a nice reason for this failure.
577  same_reason_identifier_.Clear();
578  const int max_trail_index = ComputeMaxTrailIndex(trail_->FailingClause());
579  ComputeFirstUIPConflict(max_trail_index, &learned_conflict_,
580  &reason_used_to_infer_the_conflict_,
581  &subsumed_clauses_);
582 
583  // An empty conflict means that the problem is UNSAT.
584  if (learned_conflict_.empty()) return SetModelUnsat();
585  DCHECK(IsConflictValid(learned_conflict_));
586  DCHECK(ClauseIsValidUnderDebugAssignement(learned_conflict_));
587 
588  // Update the activity of all the variables in the first UIP clause.
589  // Also update the activity of the last level variables expanded (and
590  // thus discarded) during the first UIP computation. Note that both
591  // sets are disjoint.
592  decision_policy_->BumpVariableActivities(learned_conflict_);
593  decision_policy_->BumpVariableActivities(reason_used_to_infer_the_conflict_);
594  if (parameters_->also_bump_variables_in_conflict_reasons()) {
595  ComputeUnionOfReasons(learned_conflict_, &extra_reason_literals_);
596  decision_policy_->BumpVariableActivities(extra_reason_literals_);
597  }
598 
599  // Bump the clause activities.
600  // Note that the activity of the learned clause will be bumped too
601  // by AddLearnedClauseAndEnqueueUnitPropagation().
602  if (trail_->FailingSatClause() != nullptr) {
603  BumpClauseActivity(trail_->FailingSatClause());
604  }
605  BumpReasonActivities(reason_used_to_infer_the_conflict_);
606 
607  // Decay the activities.
608  decision_policy_->UpdateVariableActivityIncrement();
609  UpdateClauseActivityIncrement();
610  pb_constraints_->UpdateActivityIncrement();
611 
612  // Hack from Glucose that seems to perform well.
613  const int period = parameters_->glucose_decay_increment_period();
614  const double max_decay = parameters_->glucose_max_decay();
615  if (counters_.num_failures % period == 0 &&
616  parameters_->variable_activity_decay() < max_decay) {
617  parameters_->set_variable_activity_decay(
618  parameters_->variable_activity_decay() +
619  parameters_->glucose_decay_increment());
620  }
621 
622  // PB resolution.
623  // There is no point using this if the conflict and all the reasons involved
624  // in its resolution were clauses.
625  bool compute_pb_conflict = false;
626  if (parameters_->use_pb_resolution()) {
627  compute_pb_conflict = (pb_constraints_->ConflictingConstraint() != nullptr);
628  if (!compute_pb_conflict) {
629  for (Literal lit : reason_used_to_infer_the_conflict_) {
630  if (ReasonPbConstraintOrNull(lit.Variable()) != nullptr) {
631  compute_pb_conflict = true;
632  break;
633  }
634  }
635  }
636  }
637 
638  // TODO(user): Note that we use the clause above to update the variable
639  // activities and not the pb conflict. Experiment.
640  if (compute_pb_conflict) {
641  pb_conflict_.ClearAndResize(num_variables_.value());
642  Coefficient initial_slack(-1);
643  if (pb_constraints_->ConflictingConstraint() == nullptr) {
644  // Generic clause case.
645  Coefficient num_literals(0);
646  for (Literal literal : trail_->FailingClause()) {
647  pb_conflict_.AddTerm(literal.Negated(), Coefficient(1.0));
648  ++num_literals;
649  }
650  pb_conflict_.AddToRhs(num_literals - 1);
651  } else {
652  // We have a pseudo-Boolean conflict, so we start from there.
653  pb_constraints_->ConflictingConstraint()->AddToConflict(&pb_conflict_);
654  pb_constraints_->ClearConflictingConstraint();
655  initial_slack =
656  pb_conflict_.ComputeSlackForTrailPrefix(*trail_, max_trail_index + 1);
657  }
658 
659  int pb_backjump_level;
660  ComputePBConflict(max_trail_index, initial_slack, &pb_conflict_,
661  &pb_backjump_level);
662  if (pb_backjump_level == -1) return SetModelUnsat();
663 
664  // Convert the conflict into the vector<LiteralWithCoeff> form.
665  std::vector<LiteralWithCoeff> cst;
666  pb_conflict_.CopyIntoVector(&cst);
667  DCHECK(PBConstraintIsValidUnderDebugAssignment(cst, pb_conflict_.Rhs()));
668 
669  // Check if the learned PB conflict is just a clause:
670  // all its coefficient must be 1, and the rhs must be its size minus 1.
671  bool conflict_is_a_clause = (pb_conflict_.Rhs() == cst.size() - 1);
672  if (conflict_is_a_clause) {
673  for (LiteralWithCoeff term : cst) {
674  if (term.coefficient != Coefficient(1)) {
675  conflict_is_a_clause = false;
676  break;
677  }
678  }
679  }
680 
681  if (!conflict_is_a_clause) {
682  // Use the PB conflict.
683  // Note that we don't need to call InitializePropagators() since when we
684  // are here, we are sure we have at least one pb constraint.
685  DCHECK_GT(pb_constraints_->NumberOfConstraints(), 0);
686  CHECK_LT(pb_backjump_level, CurrentDecisionLevel());
687  Backtrack(pb_backjump_level);
688  CHECK(pb_constraints_->AddLearnedConstraint(cst, pb_conflict_.Rhs(),
689  trail_));
690  CHECK_GT(trail_->Index(), last_decision_or_backtrack_trail_index_);
691  counters_.num_learned_pb_literals += cst.size();
692  return false;
693  }
694 
695  // Continue with the normal clause flow, but use the PB conflict clause
696  // if it has a lower backjump level.
697  if (pb_backjump_level < ComputeBacktrackLevel(learned_conflict_)) {
698  subsumed_clauses_.clear(); // Because the conflict changes.
699  learned_conflict_.clear();
700  is_marked_.ClearAndResize(num_variables_);
701  int max_level = 0;
702  int max_index = 0;
703  for (LiteralWithCoeff term : cst) {
704  DCHECK(Assignment().LiteralIsTrue(term.literal));
705  DCHECK_EQ(term.coefficient, 1);
706  const int level = trail_->Info(term.literal.Variable()).level;
707  if (level == 0) continue;
708  if (level > max_level) {
709  max_level = level;
710  max_index = learned_conflict_.size();
711  }
712  learned_conflict_.push_back(term.literal.Negated());
713 
714  // The minimization functions below expect the conflict to be marked!
715  // TODO(user): This is error prone, find a better way?
716  is_marked_.Set(term.literal.Variable());
717  }
718  CHECK(!learned_conflict_.empty());
719  std::swap(learned_conflict_.front(), learned_conflict_[max_index]);
720  DCHECK(IsConflictValid(learned_conflict_));
721  }
722  }
723 
724  // Minimizing the conflict with binary clauses first has two advantages.
725  // First, there is no need to compute a reason for the variables eliminated
726  // this way. Second, more variables may be marked (in is_marked_) and
727  // MinimizeConflict() can take advantage of that. Because of this, the
728  // LBD of the learned conflict can change.
729  DCHECK(ClauseIsValidUnderDebugAssignement(learned_conflict_));
730  if (!binary_implication_graph_->IsEmpty()) {
731  if (parameters_->binary_minimization_algorithm() ==
732  SatParameters::BINARY_MINIMIZATION_FIRST) {
733  binary_implication_graph_->MinimizeConflictFirst(
734  *trail_, &learned_conflict_, &is_marked_);
735  } else if (parameters_->binary_minimization_algorithm() ==
736  SatParameters::
737  BINARY_MINIMIZATION_FIRST_WITH_TRANSITIVE_REDUCTION) {
738  binary_implication_graph_->MinimizeConflictFirstWithTransitiveReduction(
739  *trail_, &learned_conflict_, &is_marked_,
740  *model_->GetOrCreate<ModelRandomGenerator>());
741  }
742  DCHECK(IsConflictValid(learned_conflict_));
743  }
744 
745  // Minimize the learned conflict.
746  MinimizeConflict(&learned_conflict_, &reason_used_to_infer_the_conflict_);
747 
748  // Minimize it further with binary clauses?
749  if (!binary_implication_graph_->IsEmpty()) {
750  // Note that on the contrary to the MinimizeConflict() above that
751  // just uses the reason graph, this minimization can change the
752  // clause LBD and even the backtracking level.
753  switch (parameters_->binary_minimization_algorithm()) {
754  case SatParameters::NO_BINARY_MINIMIZATION:
755  ABSL_FALLTHROUGH_INTENDED;
756  case SatParameters::BINARY_MINIMIZATION_FIRST:
757  ABSL_FALLTHROUGH_INTENDED;
758  case SatParameters::BINARY_MINIMIZATION_FIRST_WITH_TRANSITIVE_REDUCTION:
759  break;
760  case SatParameters::BINARY_MINIMIZATION_WITH_REACHABILITY:
761  binary_implication_graph_->MinimizeConflictWithReachability(
762  &learned_conflict_);
763  break;
764  case SatParameters::EXPERIMENTAL_BINARY_MINIMIZATION:
765  binary_implication_graph_->MinimizeConflictExperimental(
766  *trail_, &learned_conflict_);
767  break;
768  }
769  DCHECK(IsConflictValid(learned_conflict_));
770  }
771 
772  // We notify the decision before backtracking so that we can save the phase.
773  // The current heuristic is to try to take a trail prefix for which there is
774  // currently no conflict (hence just before the last decision was taken).
775  //
776  // TODO(user): It is unclear what the best heuristic is here. Both the current
777  // trail index or the trail before the current decision perform well, but
778  // using the full trail seems slightly better even though it will contain the
779  // current conflicting literal.
780  decision_policy_->BeforeConflict(trail_->Index());
781 
782  // Backtrack and add the reason to the set of learned clause.
783  counters_.num_literals_learned += learned_conflict_.size();
784  Backtrack(ComputeBacktrackLevel(learned_conflict_));
785  DCHECK(ClauseIsValidUnderDebugAssignement(learned_conflict_));
786 
787  // Note that we need to output the learned clause before cleaning the clause
788  // database. This is because we already backtracked and some of the clauses
789  // that were needed to infer the conflict may not be "reasons" anymore and
790  // may be deleted.
791  if (drat_proof_handler_ != nullptr) {
792  drat_proof_handler_->AddClause(learned_conflict_);
793  }
794 
795  // Detach any subsumed clause. They will actually be deleted on the next
796  // clause cleanup phase.
797  bool is_redundant = true;
798  if (!subsumed_clauses_.empty() &&
799  parameters_->subsumption_during_conflict_analysis()) {
800  for (SatClause* clause : subsumed_clauses_) {
801  DCHECK(ClauseSubsumption(learned_conflict_, clause));
802  if (!clauses_propagator_->IsRemovable(clause)) {
803  is_redundant = false;
804  }
805  clauses_propagator_->LazyDetach(clause);
806  }
807  clauses_propagator_->CleanUpWatchers();
808  counters_.num_subsumed_clauses += subsumed_clauses_.size();
809  }
810 
811  // Create and attach the new learned clause.
812  const int conflict_lbd = AddLearnedClauseAndEnqueueUnitPropagation(
813  learned_conflict_, is_redundant);
814  restart_->OnConflict(conflict_trail_index, conflict_decision_level,
815  conflict_lbd);
816  return false;
817 }
818 
819 SatSolver::Status SatSolver::ReapplyDecisionsUpTo(
820  int max_level, int* first_propagation_index) {
821  SCOPED_TIME_STAT(&stats_);
822  int decision_index = current_decision_level_;
823  while (decision_index <= max_level) {
824  DCHECK_GE(decision_index, current_decision_level_);
825  const Literal previous_decision = decisions_[decision_index].literal;
826  ++decision_index;
827  if (Assignment().LiteralIsTrue(previous_decision)) {
828  // Note that this particular position in decisions_ will be overridden,
829  // but that is fine since this is a consequence of the previous decision,
830  // so we will never need to take it into account again.
831  continue;
832  }
833  if (Assignment().LiteralIsFalse(previous_decision)) {
834  // Update decision so that GetLastIncompatibleDecisions() works.
835  decisions_[current_decision_level_].literal = previous_decision;
836  return ASSUMPTIONS_UNSAT;
837  }
838 
839  // Not assigned, we try to take it.
840  const int old_level = current_decision_level_;
841  const int index = EnqueueDecisionAndBackjumpOnConflict(previous_decision);
842  *first_propagation_index = std::min(*first_propagation_index, index);
843  if (index == kUnsatTrailIndex) return INFEASIBLE;
844  if (current_decision_level_ <= old_level) {
845  // A conflict occurred which backjumped to an earlier decision level.
846  // We potentially backjumped over some valid decisions, so we need to
847  // continue the loop and try to re-enqueue them.
848  //
849  // Note that there is no need to update max_level, because when we will
850  // try to reapply the current "previous_decision" it will result in a
851  // conflict. IMPORTANT: we can't actually optimize this and abort the loop
852  // earlier though, because we need to check that it is conflicting because
853  // it is already propagated to false. There is no guarantee of this
854  // because we learn the first-UIP conflict. If it is not the case, we will
855  // then learn a new conflict, backjump, and continue the loop.
856  decision_index = current_decision_level_;
857  }
858  }
859  return FEASIBLE;
860 }
861 
863  SCOPED_TIME_STAT(&stats_);
864  CHECK(PropagationIsDone());
865 
866  if (model_is_unsat_) return kUnsatTrailIndex;
867  DCHECK_LT(CurrentDecisionLevel(), decisions_.size());
868  decisions_[CurrentDecisionLevel()].literal = true_literal;
869  int first_propagation_index = trail_->Index();
870  ReapplyDecisionsUpTo(CurrentDecisionLevel(), &first_propagation_index);
871  return first_propagation_index;
872 }
873 
875  SCOPED_TIME_STAT(&stats_);
876  CHECK(PropagationIsDone());
877 
878  if (model_is_unsat_) return kUnsatTrailIndex;
879  const int current_level = CurrentDecisionLevel();
880  EnqueueNewDecision(true_literal);
881  if (Propagate()) {
882  return true;
883  } else {
884  Backtrack(current_level);
885  return false;
886  }
887 }
888 
889 void SatSolver::Backtrack(int target_level) {
890  SCOPED_TIME_STAT(&stats_);
891  // TODO(user): The backtrack method should not be called when the model is
892  // unsat. Add a DCHECK to prevent that, but before fix the
893  // bop::BopOptimizerBase architecture.
894 
895  // Do nothing if the CurrentDecisionLevel() is already correct.
896  // This is needed, otherwise target_trail_index below will remain at zero and
897  // that will cause some problems. Note that we could forbid a user to call
898  // Backtrack() with the current level, but that is annoying when you just
899  // want to reset the solver with Backtrack(0).
900  if (CurrentDecisionLevel() == target_level) return;
901  DCHECK_GE(target_level, 0);
902  DCHECK_LE(target_level, CurrentDecisionLevel());
903 
904  // Any backtrack to the root from a positive one is counted as a restart.
905  if (target_level == 0) counters_.num_restarts++;
906 
907  // Per the SatPropagator interface, this is needed before calling Untrail.
908  trail_->SetDecisionLevel(target_level);
909 
910  int target_trail_index = 0;
911  while (current_decision_level_ > target_level) {
912  --current_decision_level_;
913  target_trail_index = decisions_[current_decision_level_].trail_index;
914  }
915  Untrail(target_trail_index);
916  last_decision_or_backtrack_trail_index_ = trail_->Index();
917 }
918 
919 bool SatSolver::AddBinaryClauses(const std::vector<BinaryClause>& clauses) {
920  SCOPED_TIME_STAT(&stats_);
922  for (BinaryClause c : clauses) {
923  if (trail_->Assignment().LiteralIsFalse(c.a) &&
924  trail_->Assignment().LiteralIsFalse(c.b)) {
925  return SetModelUnsat();
926  }
927  AddBinaryClauseInternal(c.a, c.b);
928  }
929  if (!Propagate()) return SetModelUnsat();
930  return true;
931 }
932 
933 const std::vector<BinaryClause>& SatSolver::NewlyAddedBinaryClauses() {
934  return binary_clauses_.newly_added();
935 }
936 
938  binary_clauses_.ClearNewlyAdded();
939 }
940 
941 namespace {
942 // Return the next value that is a multiple of interval.
943 int64_t NextMultipleOf(int64_t value, int64_t interval) {
944  return interval * (1 + value / interval);
945 }
946 } // namespace
947 
949  const std::vector<Literal>& assumptions) {
950  SCOPED_TIME_STAT(&stats_);
951  if (!ResetWithGivenAssumptions(assumptions)) return UnsatStatus();
952  return SolveInternal(time_limit_);
953 }
954 
955 SatSolver::Status SatSolver::StatusWithLog(Status status) {
956  if (parameters_->log_search_progress()) {
957  LOG(INFO) << RunningStatisticsString();
958  LOG(INFO) << StatusString(status);
959  }
960  return status;
961 }
962 
963 void SatSolver::SetAssumptionLevel(int assumption_level) {
964  CHECK_GE(assumption_level, 0);
965  CHECK_LE(assumption_level, CurrentDecisionLevel());
966  assumption_level_ = assumption_level;
967 }
968 
970  return SolveInternal(time_limit == nullptr ? time_limit_ : time_limit);
971 }
972 
973 SatSolver::Status SatSolver::Solve() { return SolveInternal(time_limit_); }
974 
975 void SatSolver::KeepAllClauseUsedToInfer(BooleanVariable variable) {
976  CHECK(Assignment().VariableIsAssigned(variable));
977  if (trail_->Info(variable).level == 0) return;
978  int trail_index = trail_->Info(variable).trail_index;
979  std::vector<bool> is_marked(trail_index + 1, false); // move to local member.
980  is_marked[trail_index] = true;
981  int num = 1;
982  for (; num > 0 && trail_index >= 0; --trail_index) {
983  if (!is_marked[trail_index]) continue;
984  is_marked[trail_index] = false;
985  --num;
986 
987  const BooleanVariable var = (*trail_)[trail_index].Variable();
988  SatClause* clause = ReasonClauseOrNull(var);
989  if (clause != nullptr) {
990  clauses_propagator_->mutable_clauses_info()->erase(clause);
991  }
992  for (const Literal l : trail_->Reason(var)) {
993  const AssignmentInfo& info = trail_->Info(l.Variable());
994  if (info.level == 0) continue;
995  if (!is_marked[info.trail_index]) {
996  is_marked[info.trail_index] = true;
997  ++num;
998  }
999  }
1000  }
1001 }
1002 
1003 // TODO(user): this is really an in-processing stuff and should be moved out
1004 // of here. I think the name for that (or similar) technique is called vivify.
1005 // Ideally this should be scheduled after other faster in-processing technique.
1006 void SatSolver::TryToMinimizeClause(SatClause* clause) {
1008  ++counters_.minimization_num_clauses;
1009 
1010  std::set<LiteralIndex> moved_last;
1011  std::vector<Literal> candidate(clause->begin(), clause->end());
1012  while (!model_is_unsat_) {
1013  // We want each literal in candidate to appear last once in our propagation
1014  // order. We want to do that while maximizing the reutilization of the
1015  // current assignment prefix, that is minimizing the number of
1016  // decision/progagation we need to perform.
1017  const int target_level = MoveOneUnprocessedLiteralLast(
1018  moved_last, CurrentDecisionLevel(), &candidate);
1019  if (target_level == -1) break;
1020  Backtrack(target_level);
1021  while (CurrentDecisionLevel() < candidate.size()) {
1022  const int level = CurrentDecisionLevel();
1023  const Literal literal = candidate[level];
1024  if (Assignment().LiteralIsFalse(literal)) {
1025  candidate.erase(candidate.begin() + level);
1026  continue;
1027  } else if (Assignment().LiteralIsTrue(literal)) {
1028  const int variable_level =
1029  LiteralTrail().Info(literal.Variable()).level;
1030  if (variable_level == 0) {
1031  ProcessNewlyFixedVariablesForDratProof();
1032  counters_.minimization_num_true++;
1033  counters_.minimization_num_removed_literals += clause->size();
1034  Backtrack(0);
1035  clauses_propagator_->Detach(clause);
1036  return;
1037  }
1038 
1039  // If literal (at true) wasn't propagated by this clause, then we
1040  // know that this clause is subsumed by other clauses in the database,
1041  // so we can remove it. Note however that we need to make sure we will
1042  // never remove the clauses that subsumes it later.
1043  if (ReasonClauseOrNull(literal.Variable()) != clause) {
1044  counters_.minimization_num_subsumed++;
1045  counters_.minimization_num_removed_literals += clause->size();
1046 
1047  // TODO(user): do not do that if it make us keep too many clauses?
1048  KeepAllClauseUsedToInfer(literal.Variable());
1049  Backtrack(0);
1050  clauses_propagator_->Detach(clause);
1051  return;
1052  } else {
1053  // Simplify. Note(user): we could only keep in clause the literals
1054  // responsible for the propagation, but because of the subsumption
1055  // above, this is not needed.
1056  if (variable_level + 1 < candidate.size()) {
1057  candidate.resize(variable_level);
1058  candidate.push_back(literal);
1059  }
1060  }
1061  break;
1062  } else {
1063  ++counters_.minimization_num_decisions;
1065  if (!clause->IsAttached()) {
1066  Backtrack(0);
1067  return;
1068  }
1069  if (model_is_unsat_) return;
1070  }
1071  }
1072  if (candidate.empty()) {
1073  model_is_unsat_ = true;
1074  return;
1075  }
1076  moved_last.insert(candidate.back().Index());
1077  }
1078 
1079  // Returns if we don't have any minimization.
1080  Backtrack(0);
1081  if (candidate.size() == clause->size()) return;
1082 
1083  if (candidate.size() == 1) {
1084  if (drat_proof_handler_ != nullptr) {
1085  drat_proof_handler_->AddClause(candidate);
1086  }
1087  if (!Assignment().VariableIsAssigned(candidate[0].Variable())) {
1088  counters_.minimization_num_removed_literals += clause->size();
1089  trail_->EnqueueWithUnitReason(candidate[0]);
1091  }
1092  return;
1093  }
1094 
1095  if (parameters_->treat_binary_clauses_separately() && candidate.size() == 2) {
1096  counters_.minimization_num_removed_literals += clause->size() - 2;
1097 
1098  // The order is important for the drat proof.
1099  AddBinaryClauseInternal(candidate[0], candidate[1]);
1100  clauses_propagator_->Detach(clause);
1101 
1102  // This is needed in the corner case where this was the first binary clause
1103  // of the problem so that PropagationIsDone() returns true on the newly
1104  // created BinaryImplicationGraph.
1106  return;
1107  }
1108 
1109  counters_.minimization_num_removed_literals +=
1110  clause->size() - candidate.size();
1111 
1112  // TODO(user): If the watched literal didn't change, we could just rewrite
1113  // the clause while keeping the two watched literals at the beginning.
1114  if (!clauses_propagator_->InprocessingRewriteClause(clause, candidate)) {
1115  model_is_unsat_ = true;
1116  }
1117 }
1118 
1119 SatSolver::Status SatSolver::SolveInternal(TimeLimit* time_limit) {
1120  SCOPED_TIME_STAT(&stats_);
1121  if (model_is_unsat_) return INFEASIBLE;
1122 
1123  // TODO(user): Because the counter are not reset to zero, this cause the
1124  // metrics / sec to be completely broken except when the solver is used
1125  // for exactly one Solve().
1126  timer_.Restart();
1127 
1128  // Display initial statistics.
1129  if (parameters_->log_search_progress()) {
1130  LOG(INFO) << "Initial memory usage: " << MemoryUsage();
1131  LOG(INFO) << "Number of variables: " << num_variables_;
1132  LOG(INFO) << "Number of clauses (size > 2): "
1133  << clauses_propagator_->num_clauses();
1134  LOG(INFO) << "Number of binary clauses: "
1135  << binary_implication_graph_->num_implications();
1136  LOG(INFO) << "Number of linear constraints: "
1137  << pb_constraints_->NumberOfConstraints();
1138  LOG(INFO) << "Number of fixed variables: " << trail_->Index();
1139  LOG(INFO) << "Number of watched clauses: "
1140  << clauses_propagator_->num_watched_clauses();
1141  LOG(INFO) << "Parameters: " << ProtobufShortDebugString(*parameters_);
1142  }
1143 
1144  // Used to trigger clause minimization via propagation.
1145  int64_t next_minimization_num_restart =
1146  restart_->NumRestarts() +
1147  parameters_->minimize_with_propagation_restart_period();
1148 
1149  // Variables used to show the search progress.
1150  const int64_t kDisplayFrequency = 10000;
1151  int64_t next_display = parameters_->log_search_progress()
1152  ? NextMultipleOf(num_failures(), kDisplayFrequency)
1153  : std::numeric_limits<int64_t>::max();
1154 
1155  // Variables used to check the memory limit every kMemoryCheckFrequency.
1156  const int64_t kMemoryCheckFrequency = 10000;
1157  int64_t next_memory_check =
1158  NextMultipleOf(num_failures(), kMemoryCheckFrequency);
1159 
1160  // The max_number_of_conflicts is per solve but the counter is for the whole
1161  // solver.
1162  const int64_t kFailureLimit =
1163  parameters_->max_number_of_conflicts() ==
1166  : counters_.num_failures + parameters_->max_number_of_conflicts();
1167 
1168  // Starts search.
1169  for (;;) {
1170  // Test if a limit is reached.
1171  if (time_limit != nullptr) {
1173  if (time_limit->LimitReached()) {
1174  if (parameters_->log_search_progress()) {
1175  LOG(INFO) << "The time limit has been reached. Aborting.";
1176  }
1177  return StatusWithLog(LIMIT_REACHED);
1178  }
1179  }
1180  if (num_failures() >= kFailureLimit) {
1181  if (parameters_->log_search_progress()) {
1182  LOG(INFO) << "The conflict limit has been reached. Aborting.";
1183  }
1184  return StatusWithLog(LIMIT_REACHED);
1185  }
1186 
1187  // The current memory checking takes time, so we only execute it every
1188  // kMemoryCheckFrequency conflict. We use >= because counters_.num_failures
1189  // may augment by more than one at each iteration.
1190  //
1191  // TODO(user): Find a better way.
1192  if (counters_.num_failures >= next_memory_check) {
1193  next_memory_check = NextMultipleOf(num_failures(), kMemoryCheckFrequency);
1194  if (IsMemoryLimitReached()) {
1195  if (parameters_->log_search_progress()) {
1196  LOG(INFO) << "The memory limit has been reached. Aborting.";
1197  }
1198  return StatusWithLog(LIMIT_REACHED);
1199  }
1200  }
1201 
1202  // Display search progression. We use >= because counters_.num_failures may
1203  // augment by more than one at each iteration.
1204  if (counters_.num_failures >= next_display) {
1205  LOG(INFO) << RunningStatisticsString();
1206  next_display = NextMultipleOf(num_failures(), kDisplayFrequency);
1207  }
1208 
1209  if (!PropagateAndStopAfterOneConflictResolution()) {
1210  // A conflict occurred, continue the loop.
1211  if (model_is_unsat_) return StatusWithLog(INFEASIBLE);
1212  } else {
1213  // We need to reapply any assumptions that are not currently applied.
1214  if (!ReapplyAssumptionsIfNeeded()) return StatusWithLog(UnsatStatus());
1215 
1216  // At a leaf?
1217  if (trail_->Index() == num_variables_.value()) {
1218  return StatusWithLog(FEASIBLE);
1219  }
1220 
1221  if (restart_->ShouldRestart()) {
1222  Backtrack(assumption_level_);
1223  }
1224 
1225  // Clause minimization using propagation.
1226  if (CurrentDecisionLevel() == 0 &&
1227  restart_->NumRestarts() >= next_minimization_num_restart) {
1228  next_minimization_num_restart =
1229  restart_->NumRestarts() +
1230  parameters_->minimize_with_propagation_restart_period();
1232  parameters_->minimize_with_propagation_num_decisions());
1233 
1234  // Corner case: the minimization above being based on propagation may
1235  // fix the remaining variables or prove UNSAT.
1236  if (model_is_unsat_) return StatusWithLog(INFEASIBLE);
1237  if (trail_->Index() == num_variables_.value()) {
1238  return StatusWithLog(FEASIBLE);
1239  }
1240  }
1241 
1242  DCHECK_GE(CurrentDecisionLevel(), assumption_level_);
1243  EnqueueNewDecision(decision_policy_->NextBranch());
1244  }
1245  }
1246 }
1247 
1248 void SatSolver::MinimizeSomeClauses(int decisions_budget) {
1249  // Tricky: we don't want TryToMinimizeClause() to delete to_minimize
1250  // while we are processing it.
1251  block_clause_deletion_ = true;
1252 
1253  const int64_t target_num_branches = counters_.num_branches + decisions_budget;
1254  while (counters_.num_branches < target_num_branches &&
1255  (time_limit_ == nullptr || !time_limit_->LimitReached())) {
1256  SatClause* to_minimize = clauses_propagator_->NextClauseToMinimize();
1257  if (to_minimize != nullptr) {
1258  TryToMinimizeClause(to_minimize);
1259  if (model_is_unsat_) return;
1260  } else {
1261  if (to_minimize == nullptr) {
1262  VLOG(1) << "Minimized all clauses, restarting from first one.";
1263  clauses_propagator_->ResetToMinimizeIndex();
1264  }
1265  break;
1266  }
1267  }
1268 
1269  block_clause_deletion_ = false;
1270  clauses_propagator_->DeleteRemovedClauses();
1271 }
1272 
1274  SCOPED_TIME_STAT(&stats_);
1275  const Literal false_assumption = decisions_[CurrentDecisionLevel()].literal;
1276  std::vector<Literal> unsat_assumptions;
1277  if (!trail_->Assignment().LiteralIsFalse(false_assumption)) {
1278  // This can only happen in some corner cases where: we enqueued
1279  // false_assumption, it leads to a conflict, but after re-enqueing the
1280  // decisions that were backjumped over, there is no conflict anymore. This
1281  // can only happen in the presence of propagators that are non-monotonic
1282  // and do not propagate the same thing when there is more literal on the
1283  // trail.
1284  //
1285  // In this case, we simply return all the decisions since we know that is
1286  // a valid conflict. Since this should be rare, it is okay to not "minimize"
1287  // what we return like we do below.
1288  //
1289  // TODO(user): unit-test this case with a mock propagator.
1290  unsat_assumptions.reserve(CurrentDecisionLevel());
1291  for (int i = 0; i < CurrentDecisionLevel(); ++i) {
1292  unsat_assumptions.push_back(decisions_[i].literal);
1293  }
1294  return unsat_assumptions;
1295  }
1296 
1297  unsat_assumptions.push_back(false_assumption);
1298 
1299  // This will be used to mark all the literals inspected while we process the
1300  // false_assumption and the reasons behind each of its variable assignments.
1301  is_marked_.ClearAndResize(num_variables_);
1302  is_marked_.Set(false_assumption.Variable());
1303 
1304  int trail_index = trail_->Info(false_assumption.Variable()).trail_index;
1305  const int limit =
1306  CurrentDecisionLevel() > 0 ? decisions_[0].trail_index : trail_->Index();
1307  CHECK_LT(trail_index, trail_->Index());
1308  while (true) {
1309  // Find next marked literal to expand from the trail.
1310  while (trail_index >= 0 && !is_marked_[(*trail_)[trail_index].Variable()]) {
1311  --trail_index;
1312  }
1313  if (trail_index < limit) break;
1314  const Literal marked_literal = (*trail_)[trail_index];
1315  --trail_index;
1316 
1317  if (trail_->AssignmentType(marked_literal.Variable()) ==
1319  unsat_assumptions.push_back(marked_literal);
1320  } else {
1321  // Marks all the literals of its reason.
1322  for (const Literal literal : trail_->Reason(marked_literal.Variable())) {
1323  const BooleanVariable var = literal.Variable();
1324  const int level = DecisionLevel(var);
1325  if (level > 0 && !is_marked_[var]) is_marked_.Set(var);
1326  }
1327  }
1328  }
1329 
1330  // We reverse the assumptions so they are in the same order as the one in
1331  // which the decision were made.
1332  std::reverse(unsat_assumptions.begin(), unsat_assumptions.end());
1333  return unsat_assumptions;
1334 }
1335 
1336 void SatSolver::BumpReasonActivities(const std::vector<Literal>& literals) {
1337  SCOPED_TIME_STAT(&stats_);
1338  for (const Literal literal : literals) {
1339  const BooleanVariable var = literal.Variable();
1340  if (DecisionLevel(var) > 0) {
1341  SatClause* clause = ReasonClauseOrNull(var);
1342  if (clause != nullptr) {
1343  BumpClauseActivity(clause);
1344  } else {
1345  UpperBoundedLinearConstraint* pb_constraint =
1346  ReasonPbConstraintOrNull(var);
1347  if (pb_constraint != nullptr) {
1348  // TODO(user): Because one pb constraint may propagate many literals,
1349  // this may bias the constraint activity... investigate other policy.
1350  pb_constraints_->BumpActivity(pb_constraint);
1351  }
1352  }
1353  }
1354  }
1355 }
1356 
1357 void SatSolver::BumpClauseActivity(SatClause* clause) {
1358  // We only bump the activity of the clauses that have some info. So if we know
1359  // that we will keep a clause forever, we don't need to create its Info. More
1360  // than the speed, this allows to limit as much as possible the activity
1361  // rescaling.
1362  auto it = clauses_propagator_->mutable_clauses_info()->find(clause);
1363  if (it == clauses_propagator_->mutable_clauses_info()->end()) return;
1364 
1365  // Check if the new clause LBD is below our threshold to keep this clause
1366  // indefinitely. Note that we use a +1 here because the LBD of a newly learned
1367  // clause decrease by 1 just after the backjump.
1368  const int new_lbd = ComputeLbd(*clause);
1369  if (new_lbd + 1 <= parameters_->clause_cleanup_lbd_bound()) {
1370  clauses_propagator_->mutable_clauses_info()->erase(clause);
1371  return;
1372  }
1373 
1374  // Eventually protect this clause for the next cleanup phase.
1375  switch (parameters_->clause_cleanup_protection()) {
1376  case SatParameters::PROTECTION_NONE:
1377  break;
1378  case SatParameters::PROTECTION_ALWAYS:
1379  it->second.protected_during_next_cleanup = true;
1380  break;
1381  case SatParameters::PROTECTION_LBD:
1382  // This one is similar to the one used by the Glucose SAT solver.
1383  //
1384  // TODO(user): why the +1? one reason may be that the LBD of a conflict
1385  // decrease by 1 just afer the backjump...
1386  if (new_lbd + 1 < it->second.lbd) {
1387  it->second.protected_during_next_cleanup = true;
1388  it->second.lbd = new_lbd;
1389  }
1390  }
1391 
1392  // Increase the activity.
1393  const double activity = it->second.activity += clause_activity_increment_;
1394  if (activity > parameters_->max_clause_activity_value()) {
1395  RescaleClauseActivities(1.0 / parameters_->max_clause_activity_value());
1396  }
1397 }
1398 
1399 void SatSolver::RescaleClauseActivities(double scaling_factor) {
1400  SCOPED_TIME_STAT(&stats_);
1401  clause_activity_increment_ *= scaling_factor;
1402  for (auto& entry : *clauses_propagator_->mutable_clauses_info()) {
1403  entry.second.activity *= scaling_factor;
1404  }
1405 }
1406 
1407 void SatSolver::UpdateClauseActivityIncrement() {
1408  SCOPED_TIME_STAT(&stats_);
1409  clause_activity_increment_ *= 1.0 / parameters_->clause_activity_decay();
1410 }
1411 
1412 bool SatSolver::IsConflictValid(const std::vector<Literal>& literals) {
1413  SCOPED_TIME_STAT(&stats_);
1414  if (literals.empty()) return false;
1415  const int highest_level = DecisionLevel(literals[0].Variable());
1416  for (int i = 1; i < literals.size(); ++i) {
1417  const int level = DecisionLevel(literals[i].Variable());
1418  if (level <= 0 || level >= highest_level) return false;
1419  }
1420  return true;
1421 }
1422 
1423 int SatSolver::ComputeBacktrackLevel(const std::vector<Literal>& literals) {
1424  SCOPED_TIME_STAT(&stats_);
1426 
1427  // We want the highest decision level among literals other than the first one.
1428  // Note that this level will always be smaller than that of the first literal.
1429  //
1430  // Note(user): if the learned clause is of size 1, we backtrack all the way to
1431  // the beginning. It may be possible to follow another behavior, but then the
1432  // code require some special cases in
1433  // AddLearnedClauseAndEnqueueUnitPropagation() to fix the literal and not
1434  // backtrack over it. Also, subsequent propagated variables may not have a
1435  // correct level in this case.
1436  int backtrack_level = 0;
1437  for (int i = 1; i < literals.size(); ++i) {
1438  const int level = DecisionLevel(literals[i].Variable());
1439  backtrack_level = std::max(backtrack_level, level);
1440  }
1441  DCHECK_LT(backtrack_level, DecisionLevel(literals[0].Variable()));
1442  DCHECK_LE(DecisionLevel(literals[0].Variable()), CurrentDecisionLevel());
1443  return backtrack_level;
1444 }
1445 
1446 template <typename LiteralList>
1447 int SatSolver::ComputeLbd(const LiteralList& literals) {
1448  SCOPED_TIME_STAT(&stats_);
1449  const int limit =
1450  parameters_->count_assumption_levels_in_lbd() ? 0 : assumption_level_;
1451 
1452  // We know that the first literal is always of the highest level.
1453  is_level_marked_.ClearAndResize(
1454  SatDecisionLevel(DecisionLevel(literals.begin()->Variable()) + 1));
1455  for (const Literal literal : literals) {
1456  const SatDecisionLevel level(DecisionLevel(literal.Variable()));
1457  DCHECK_GE(level, 0);
1458  if (level > limit && !is_level_marked_[level]) {
1459  is_level_marked_.Set(level);
1460  }
1461  }
1462  return is_level_marked_.NumberOfSetCallsWithDifferentArguments();
1463 }
1464 
1465 std::string SatSolver::StatusString(Status status) const {
1466  const double time_in_s = timer_.Get();
1467  return absl::StrFormat("\n status: %s\n", SatStatusString(status)) +
1468  absl::StrFormat(" time: %fs\n", time_in_s) +
1469  absl::StrFormat(" memory: %s\n", MemoryUsage()) +
1470  absl::StrFormat(
1471  " num failures: %d (%.0f /sec)\n", counters_.num_failures,
1472  static_cast<double>(counters_.num_failures) / time_in_s) +
1473  absl::StrFormat(
1474  " num branches: %d (%.0f /sec)\n", counters_.num_branches,
1475  static_cast<double>(counters_.num_branches) / time_in_s) +
1476  absl::StrFormat(" num propagations: %d (%.0f /sec)\n",
1477  num_propagations(),
1478  static_cast<double>(num_propagations()) / time_in_s) +
1479  absl::StrFormat(" num binary propagations: %d\n",
1480  binary_implication_graph_->num_propagations()) +
1481  absl::StrFormat(" num binary inspections: %d\n",
1482  binary_implication_graph_->num_inspections()) +
1483  absl::StrFormat(
1484  " num binary redundant implications: %d\n",
1485  binary_implication_graph_->num_redundant_implications()) +
1486  absl::StrFormat(
1487  " num classic minimizations: %d"
1488  " (literals removed: %d)\n",
1489  counters_.num_minimizations, counters_.num_literals_removed) +
1490  absl::StrFormat(
1491  " num binary minimizations: %d"
1492  " (literals removed: %d)\n",
1493  binary_implication_graph_->num_minimization(),
1494  binary_implication_graph_->num_literals_removed()) +
1495  absl::StrFormat(" num inspected clauses: %d\n",
1496  clauses_propagator_->num_inspected_clauses()) +
1497  absl::StrFormat(" num inspected clause_literals: %d\n",
1498  clauses_propagator_->num_inspected_clause_literals()) +
1499  absl::StrFormat(
1500  " num learned literals: %d (avg: %.1f /clause)\n",
1501  counters_.num_literals_learned,
1502  1.0 * counters_.num_literals_learned / counters_.num_failures) +
1503  absl::StrFormat(
1504  " num learned PB literals: %d (avg: %.1f /clause)\n",
1505  counters_.num_learned_pb_literals,
1506  1.0 * counters_.num_learned_pb_literals / counters_.num_failures) +
1507  absl::StrFormat(" num subsumed clauses: %d\n",
1508  counters_.num_subsumed_clauses) +
1509  absl::StrFormat(" minimization_num_clauses: %d\n",
1510  counters_.minimization_num_clauses) +
1511  absl::StrFormat(" minimization_num_decisions: %d\n",
1512  counters_.minimization_num_decisions) +
1513  absl::StrFormat(" minimization_num_true: %d\n",
1514  counters_.minimization_num_true) +
1515  absl::StrFormat(" minimization_num_subsumed: %d\n",
1516  counters_.minimization_num_subsumed) +
1517  absl::StrFormat(" minimization_num_removed_literals: %d\n",
1518  counters_.minimization_num_removed_literals) +
1519  absl::StrFormat(" pb num threshold updates: %d\n",
1520  pb_constraints_->num_threshold_updates()) +
1521  absl::StrFormat(" pb num constraint lookups: %d\n",
1522  pb_constraints_->num_constraint_lookups()) +
1523  absl::StrFormat(" pb num inspected constraint literals: %d\n",
1524  pb_constraints_->num_inspected_constraint_literals()) +
1525  restart_->InfoString() +
1526  absl::StrFormat(" deterministic time: %f\n", deterministic_time());
1527 }
1528 
1529 std::string SatSolver::RunningStatisticsString() const {
1530  const double time_in_s = timer_.Get();
1531  return absl::StrFormat(
1532  "%6.2fs, mem:%s, fails:%d, depth:%d, clauses:%d, tmp:%d, bin:%u, "
1533  "restarts:%d, vars:%d",
1534  time_in_s, MemoryUsage(), counters_.num_failures, CurrentDecisionLevel(),
1535  clauses_propagator_->num_clauses() -
1536  clauses_propagator_->num_removable_clauses(),
1537  clauses_propagator_->num_removable_clauses(),
1538  binary_implication_graph_->num_implications(), restart_->NumRestarts(),
1539  num_variables_.value() - num_processed_fixed_variables_);
1540 }
1541 
1542 void SatSolver::ProcessNewlyFixedVariablesForDratProof() {
1543  if (drat_proof_handler_ == nullptr) return;
1544  if (CurrentDecisionLevel() != 0) return;
1545 
1546  // We need to output the literals that are fixed so we can remove all
1547  // clauses that contains them. Note that this doesn't seems to be needed
1548  // for drat-trim.
1549  //
1550  // TODO(user): Ideally we could output such literal as soon as they are fixed,
1551  // but this is not that easy to do. Spend some time to find a cleaner
1552  // alternative? Currently this works, but:
1553  // - We will output some fixed literals twice since we already output learnt
1554  // clauses of size one.
1555  // - We need to call this function when needed.
1556  Literal temp;
1557  for (; drat_num_processed_fixed_variables_ < trail_->Index();
1558  ++drat_num_processed_fixed_variables_) {
1559  temp = (*trail_)[drat_num_processed_fixed_variables_];
1560  drat_proof_handler_->AddClause({&temp, 1});
1561  }
1562 }
1563 
1565  SCOPED_TIME_STAT(&stats_);
1567  int num_detached_clauses = 0;
1568  int num_binary = 0;
1569 
1570  ProcessNewlyFixedVariablesForDratProof();
1571 
1572  // We remove the clauses that are always true and the fixed literals from the
1573  // others. Note that none of the clause should be all false because we should
1574  // have detected a conflict before this is called.
1575  for (SatClause* clause : clauses_propagator_->AllClausesInCreationOrder()) {
1576  if (!clause->IsAttached()) continue;
1577 
1578  const size_t old_size = clause->size();
1579  if (clause->RemoveFixedLiteralsAndTestIfTrue(trail_->Assignment())) {
1580  // The clause is always true, detach it.
1581  clauses_propagator_->LazyDetach(clause);
1582  ++num_detached_clauses;
1583  continue;
1584  }
1585 
1586  const size_t new_size = clause->size();
1587  if (new_size == old_size) continue;
1588 
1589  if (drat_proof_handler_ != nullptr) {
1590  CHECK_GT(new_size, 0);
1591  drat_proof_handler_->AddClause({clause->begin(), new_size});
1592  drat_proof_handler_->DeleteClause({clause->begin(), old_size});
1593  }
1594 
1595  if (new_size == 2 && parameters_->treat_binary_clauses_separately()) {
1596  // This clause is now a binary clause, treat it separately. Note that
1597  // it is safe to do that because this clause can't be used as a reason
1598  // since we are at level zero and the clause is not satisfied.
1599  AddBinaryClauseInternal(clause->FirstLiteral(), clause->SecondLiteral());
1600  clauses_propagator_->LazyDetach(clause);
1601  ++num_binary;
1602  continue;
1603  }
1604  }
1605 
1606  // Note that we will only delete the clauses during the next database cleanup.
1607  clauses_propagator_->CleanUpWatchers();
1608  if (num_detached_clauses > 0 || num_binary > 0) {
1609  VLOG(1) << trail_->Index() << " fixed variables at level 0. "
1610  << "Detached " << num_detached_clauses << " clauses. " << num_binary
1611  << " converted to binary.";
1612  }
1613 
1614  // We also clean the binary implication graph.
1615  binary_implication_graph_->RemoveFixedVariables();
1616  num_processed_fixed_variables_ = trail_->Index();
1617  deterministic_time_of_last_fixed_variables_cleanup_ = deterministic_time();
1618 }
1619 
1620 // TODO(user): Support propagating only the "first" propagators. That can
1621 // be useful for probing/in-processing, so we can control if we do only the SAT
1622 // part or the full integer part...
1624  SCOPED_TIME_STAT(&stats_);
1625  while (true) {
1626  // The idea here is to abort the inspection as soon as at least one
1627  // propagation occurs so we can loop over and test again the highest
1628  // priority constraint types using the new information.
1629  //
1630  // Note that the first propagators_ should be the binary_implication_graph_
1631  // and that its Propagate() functions will not abort on the first
1632  // propagation to be slightly more efficient.
1633  const int old_index = trail_->Index();
1634  for (SatPropagator* propagator : propagators_) {
1635  DCHECK(propagator->PropagatePreconditionsAreSatisfied(*trail_));
1636  if (!propagator->Propagate(trail_)) return false;
1637  if (trail_->Index() > old_index) break;
1638  }
1639  if (trail_->Index() == old_index) break;
1640  }
1641  return true;
1642 }
1643 
1644 void SatSolver::InitializePropagators() {
1645  propagators_.clear();
1646 
1647  // To make Propagate() as fast as possible, we only add the
1648  // binary_implication_graph_/pb_constraints_ propagators if there is anything
1649  // to propagate. Because of this, it is important to call
1650  // InitializePropagators() after the first constraint of this kind is added.
1651  //
1652  // TODO(user): uses the Model classes here to only call
1653  // model.GetOrCreate<BinaryImplicationGraph>() when the first binary
1654  // constraint is needed, and have a mecanism to always make this propagator
1655  // first. Same for the linear constraints.
1656  if (!binary_implication_graph_->IsEmpty()) {
1657  propagators_.push_back(binary_implication_graph_);
1658  }
1659  propagators_.push_back(clauses_propagator_);
1660  if (pb_constraints_->NumberOfConstraints() > 0) {
1661  propagators_.push_back(pb_constraints_);
1662  }
1663  for (int i = 0; i < external_propagators_.size(); ++i) {
1664  propagators_.push_back(external_propagators_[i]);
1665  }
1666  if (last_propagator_ != nullptr) {
1667  propagators_.push_back(last_propagator_);
1668  }
1669 }
1670 
1671 bool SatSolver::PropagationIsDone() const {
1672  for (SatPropagator* propagator : propagators_) {
1673  if (!propagator->PropagationIsDone(*trail_)) return false;
1674  }
1675  return true;
1676 }
1677 
1678 bool SatSolver::ResolvePBConflict(BooleanVariable var,
1679  MutableUpperBoundedLinearConstraint* conflict,
1680  Coefficient* slack) {
1681  const int trail_index = trail_->Info(var).trail_index;
1682 
1683  // This is the slack of the conflict < trail_index
1684  DCHECK_EQ(*slack, conflict->ComputeSlackForTrailPrefix(*trail_, trail_index));
1685 
1686  // Pseudo-Boolean case.
1687  UpperBoundedLinearConstraint* pb_reason = ReasonPbConstraintOrNull(var);
1688  if (pb_reason != nullptr) {
1689  pb_reason->ResolvePBConflict(*trail_, var, conflict, slack);
1690  return false;
1691  }
1692 
1693  // Generic clause case.
1694  Coefficient multiplier(1);
1695 
1696  // TODO(user): experiment and choose the "best" algo.
1697  const int algorithm = 1;
1698  switch (algorithm) {
1699  case 1:
1700  // We reduce the conflict slack to 0 before adding the clause.
1701  // The advantage of this method is that the coefficients stay small.
1702  conflict->ReduceSlackTo(*trail_, trail_index, *slack, Coefficient(0));
1703  break;
1704  case 2:
1705  // No reduction, we add the lower possible multiple.
1706  multiplier = *slack + 1;
1707  break;
1708  default:
1709  // No reduction, the multiple is chosen to cancel var.
1710  multiplier = conflict->GetCoefficient(var);
1711  }
1712 
1713  Coefficient num_literals(1);
1714  conflict->AddTerm(
1716  multiplier);
1717  for (Literal literal : trail_->Reason(var)) {
1718  DCHECK_NE(literal.Variable(), var);
1719  DCHECK(Assignment().LiteralIsFalse(literal));
1720  conflict->AddTerm(literal.Negated(), multiplier);
1721  ++num_literals;
1722  }
1723  conflict->AddToRhs((num_literals - 1) * multiplier);
1724 
1725  // All the algorithms above result in a new slack of -1.
1726  *slack = -1;
1727  DCHECK_EQ(*slack, conflict->ComputeSlackForTrailPrefix(*trail_, trail_index));
1728  return true;
1729 }
1730 
1731 void SatSolver::EnqueueNewDecision(Literal literal) {
1732  SCOPED_TIME_STAT(&stats_);
1733  CHECK(!Assignment().VariableIsAssigned(literal.Variable()));
1734 
1735  // We are back at level 0. This can happen because of a restart, or because
1736  // we proved that some variables must take a given value in any satisfiable
1737  // assignment. Trigger a simplification of the clauses if there is new fixed
1738  // variables. Note that for efficiency reason, we don't do that too often.
1739  //
1740  // TODO(user): Do more advanced preprocessing?
1741  if (CurrentDecisionLevel() == 0) {
1742  const double kMinDeterministicTimeBetweenCleanups = 1.0;
1743  if (num_processed_fixed_variables_ < trail_->Index() &&
1744  deterministic_time() >
1745  deterministic_time_of_last_fixed_variables_cleanup_ +
1746  kMinDeterministicTimeBetweenCleanups) {
1748  }
1749  }
1750 
1751  counters_.num_branches++;
1752  last_decision_or_backtrack_trail_index_ = trail_->Index();
1753  decisions_[current_decision_level_] = Decision(trail_->Index(), literal);
1754  ++current_decision_level_;
1755  trail_->SetDecisionLevel(current_decision_level_);
1756  trail_->EnqueueSearchDecision(literal);
1757 }
1758 
1759 void SatSolver::Untrail(int target_trail_index) {
1760  SCOPED_TIME_STAT(&stats_);
1761  DCHECK_LT(target_trail_index, trail_->Index());
1762  for (SatPropagator* propagator : propagators_) {
1763  propagator->Untrail(*trail_, target_trail_index);
1764  }
1765  decision_policy_->Untrail(target_trail_index);
1766  trail_->Untrail(target_trail_index);
1767 }
1768 
1769 std::string SatSolver::DebugString(const SatClause& clause) const {
1770  std::string result;
1771  for (const Literal literal : clause) {
1772  if (!result.empty()) {
1773  result.append(" || ");
1774  }
1775  const std::string value =
1776  trail_->Assignment().LiteralIsTrue(literal)
1777  ? "true"
1778  : (trail_->Assignment().LiteralIsFalse(literal) ? "false"
1779  : "undef");
1780  result.append(absl::StrFormat("%s(%s)", literal.DebugString(), value));
1781  }
1782  return result;
1783 }
1784 
1785 int SatSolver::ComputeMaxTrailIndex(absl::Span<const Literal> clause) const {
1786  SCOPED_TIME_STAT(&stats_);
1787  int trail_index = -1;
1788  for (const Literal literal : clause) {
1789  trail_index =
1790  std::max(trail_index, trail_->Info(literal.Variable()).trail_index);
1791  }
1792  return trail_index;
1793 }
1794 
1795 // This method will compute a first UIP conflict
1796 // http://www.cs.tau.ac.il/~msagiv/courses/ATP/iccad2001_final.pdf
1797 // http://gauss.ececs.uc.edu/SAT/articles/FAIA185-0131.pdf
1798 void SatSolver::ComputeFirstUIPConflict(
1799  int max_trail_index, std::vector<Literal>* conflict,
1800  std::vector<Literal>* reason_used_to_infer_the_conflict,
1801  std::vector<SatClause*>* subsumed_clauses) {
1802  SCOPED_TIME_STAT(&stats_);
1803 
1804  // This will be used to mark all the literals inspected while we process the
1805  // conflict and the reasons behind each of its variable assignments.
1806  is_marked_.ClearAndResize(num_variables_);
1807 
1808  conflict->clear();
1809  reason_used_to_infer_the_conflict->clear();
1810  subsumed_clauses->clear();
1811  if (max_trail_index == -1) return;
1812 
1813  // max_trail_index is the maximum trail index appearing in the failing_clause
1814  // and its level (Which is almost always equals to the CurrentDecisionLevel(),
1815  // except for symmetry propagation).
1816  DCHECK_EQ(max_trail_index, ComputeMaxTrailIndex(trail_->FailingClause()));
1817  int trail_index = max_trail_index;
1818  const int highest_level = DecisionLevel((*trail_)[trail_index].Variable());
1819  if (highest_level == 0) return;
1820 
1821  // To find the 1-UIP conflict clause, we start by the failing_clause, and
1822  // expand each of its literal using the reason for this literal assignement to
1823  // false. The is_marked_ set allow us to never expand the same literal twice.
1824  //
1825  // The expansion is not done (i.e. stop) for literals that were assigned at a
1826  // decision level below the current one. If the level of such literal is not
1827  // zero, it is added to the conflict clause.
1828  //
1829  // Now, the trick is that we use the trail to expand the literal of the
1830  // current level in a very specific order. Namely the reverse order of the one
1831  // in which they were inferred. We stop as soon as
1832  // num_literal_at_highest_level_that_needs_to_be_processed is exactly one.
1833  //
1834  // This last literal will be the first UIP because by definition all the
1835  // propagation done at the current level will pass though it at some point.
1836  absl::Span<const Literal> clause_to_expand = trail_->FailingClause();
1837  SatClause* sat_clause = trail_->FailingSatClause();
1838  DCHECK(!clause_to_expand.empty());
1839  int num_literal_at_highest_level_that_needs_to_be_processed = 0;
1840  while (true) {
1841  int num_new_vars_at_positive_level = 0;
1842  int num_vars_at_positive_level_in_clause_to_expand = 0;
1843  for (const Literal literal : clause_to_expand) {
1844  const BooleanVariable var = literal.Variable();
1845  const int level = DecisionLevel(var);
1846  if (level > 0) ++num_vars_at_positive_level_in_clause_to_expand;
1847  if (!is_marked_[var]) {
1848  is_marked_.Set(var);
1849  if (level == highest_level) {
1850  ++num_new_vars_at_positive_level;
1851  ++num_literal_at_highest_level_that_needs_to_be_processed;
1852  } else if (level > 0) {
1853  ++num_new_vars_at_positive_level;
1854  // Note that all these literals are currently false since the clause
1855  // to expand was used to infer the value of a literal at this level.
1857  conflict->push_back(literal);
1858  } else {
1859  reason_used_to_infer_the_conflict->push_back(literal);
1860  }
1861  }
1862  }
1863 
1864  // If there is new variables, then all the previously subsumed clauses are
1865  // not subsumed anymore.
1866  if (num_new_vars_at_positive_level > 0) {
1867  // TODO(user): We could still replace all these clauses with the current
1868  // conflict.
1869  subsumed_clauses->clear();
1870  }
1871 
1872  // This check if the new conflict is exactly equal to clause_to_expand.
1873  // Since we just performed an union, comparing the size is enough. When this
1874  // is true, then the current conflict subsumes the reason whose underlying
1875  // clause is given by sat_clause.
1876  if (sat_clause != nullptr &&
1877  num_vars_at_positive_level_in_clause_to_expand ==
1878  conflict->size() +
1879  num_literal_at_highest_level_that_needs_to_be_processed) {
1880  subsumed_clauses->push_back(sat_clause);
1881  }
1882 
1883  // Find next marked literal to expand from the trail.
1884  DCHECK_GT(num_literal_at_highest_level_that_needs_to_be_processed, 0);
1885  while (!is_marked_[(*trail_)[trail_index].Variable()]) {
1886  --trail_index;
1887  DCHECK_GE(trail_index, 0);
1888  DCHECK_EQ(DecisionLevel((*trail_)[trail_index].Variable()),
1889  highest_level);
1890  }
1891 
1892  if (num_literal_at_highest_level_that_needs_to_be_processed == 1) {
1893  // We have the first UIP. Add its negation to the conflict clause.
1894  // This way, after backtracking to the proper level, the conflict clause
1895  // will be unit, and infer the negation of the UIP that caused the fail.
1896  conflict->push_back((*trail_)[trail_index].Negated());
1897 
1898  // To respect the function API move the first UIP in the first position.
1899  std::swap(conflict->back(), conflict->front());
1900  break;
1901  }
1902 
1903  const Literal literal = (*trail_)[trail_index];
1904  reason_used_to_infer_the_conflict->push_back(literal);
1905 
1906  // If we already encountered the same reason, we can just skip this literal
1907  // which is what setting clause_to_expand to the empty clause do.
1908  if (same_reason_identifier_.FirstVariableWithSameReason(
1909  literal.Variable()) != literal.Variable()) {
1910  clause_to_expand = {};
1911  } else {
1912  clause_to_expand = trail_->Reason(literal.Variable());
1913  }
1914  sat_clause = ReasonClauseOrNull(literal.Variable());
1915 
1916  --num_literal_at_highest_level_that_needs_to_be_processed;
1917  --trail_index;
1918  }
1919 }
1920 
1921 void SatSolver::ComputeUnionOfReasons(const std::vector<Literal>& input,
1922  std::vector<Literal>* literals) {
1923  tmp_mark_.ClearAndResize(num_variables_);
1924  literals->clear();
1925  for (const Literal l : input) tmp_mark_.Set(l.Variable());
1926  for (const Literal l : input) {
1927  for (const Literal r : trail_->Reason(l.Variable())) {
1928  if (!tmp_mark_[r.Variable()]) {
1929  tmp_mark_.Set(r.Variable());
1930  literals->push_back(r);
1931  }
1932  }
1933  }
1934  for (const Literal l : input) tmp_mark_.Clear(l.Variable());
1935  for (const Literal l : *literals) tmp_mark_.Clear(l.Variable());
1936 }
1937 
1938 // TODO(user): Remove the literals assigned at level 0.
1939 void SatSolver::ComputePBConflict(int max_trail_index,
1940  Coefficient initial_slack,
1941  MutableUpperBoundedLinearConstraint* conflict,
1942  int* pb_backjump_level) {
1943  SCOPED_TIME_STAT(&stats_);
1944  int trail_index = max_trail_index;
1945 
1946  // First compute the slack of the current conflict for the assignment up to
1947  // trail_index. It must be negative since this is a conflict.
1948  Coefficient slack = initial_slack;
1949  DCHECK_EQ(slack,
1950  conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1));
1951  CHECK_LT(slack, 0) << "We don't have a conflict!";
1952 
1953  // Iterate backward over the trail.
1954  int backjump_level = 0;
1955  while (true) {
1956  const BooleanVariable var = (*trail_)[trail_index].Variable();
1957  --trail_index;
1958 
1959  if (conflict->GetCoefficient(var) > 0 &&
1960  trail_->Assignment().LiteralIsTrue(conflict->GetLiteral(var))) {
1961  if (parameters_->minimize_reduction_during_pb_resolution()) {
1962  // When this parameter is true, we don't call ReduceCoefficients() at
1963  // every loop. However, it is still important to reduce the "current"
1964  // variable coefficient, because this can impact the value of the new
1965  // slack below.
1966  conflict->ReduceGivenCoefficient(var);
1967  }
1968 
1969  // This is the slack one level before (< Info(var).trail_index).
1970  slack += conflict->GetCoefficient(var);
1971 
1972  // This can't happen at the beginning, but may happen later.
1973  // It means that even without var assigned, we still have a conflict.
1974  if (slack < 0) continue;
1975 
1976  // At this point, just removing the last assignment lift the conflict.
1977  // So we can abort if the true assignment before that is at a lower level
1978  // TODO(user): Somewhat inefficient.
1979  // TODO(user): We could abort earlier...
1980  const int current_level = DecisionLevel(var);
1981  int i = trail_index;
1982  while (i >= 0) {
1983  const BooleanVariable previous_var = (*trail_)[i].Variable();
1984  if (conflict->GetCoefficient(previous_var) > 0 &&
1985  trail_->Assignment().LiteralIsTrue(
1986  conflict->GetLiteral(previous_var))) {
1987  break;
1988  }
1989  --i;
1990  }
1991  if (i < 0 || DecisionLevel((*trail_)[i].Variable()) < current_level) {
1992  backjump_level = i < 0 ? 0 : DecisionLevel((*trail_)[i].Variable());
1993  break;
1994  }
1995 
1996  // We can't abort, So resolve the current variable.
1998  const bool clause_used = ResolvePBConflict(var, conflict, &slack);
1999 
2000  // At this point, we have a negative slack. Note that ReduceCoefficients()
2001  // will not change it. However it may change the slack value of the next
2002  // iteration (when we will no longer take into account the true literal
2003  // with highest trail index).
2004  //
2005  // Note that the trail_index has already been decremented, it is why
2006  // we need the +1 in the slack computation.
2007  const Coefficient slack_only_for_debug =
2008  DEBUG_MODE
2009  ? conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1)
2010  : Coefficient(0);
2011 
2012  if (clause_used) {
2013  // If a clause was used, we know that slack has the correct value.
2014  if (!parameters_->minimize_reduction_during_pb_resolution()) {
2015  conflict->ReduceCoefficients();
2016  }
2017  } else {
2018  // TODO(user): The function below can take most of the running time on
2019  // some instances. The goal is to have slack updated to its new value
2020  // incrementally, but we are not here yet.
2021  if (parameters_->minimize_reduction_during_pb_resolution()) {
2022  slack =
2023  conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1);
2024  } else {
2025  slack = conflict->ReduceCoefficientsAndComputeSlackForTrailPrefix(
2026  *trail_, trail_index + 1);
2027  }
2028  }
2029  DCHECK_EQ(slack, slack_only_for_debug);
2030  CHECK_LT(slack, 0);
2031  if (conflict->Rhs() < 0) {
2032  *pb_backjump_level = -1;
2033  return;
2034  }
2035  }
2036  }
2037 
2038  // Reduce the conflit coefficients if it is not already done.
2039  // This is important to avoid integer overflow.
2040  if (!parameters_->minimize_reduction_during_pb_resolution()) {
2041  conflict->ReduceCoefficients();
2042  }
2043 
2044  // Double check.
2045  // The sum of the literal with level <= backjump_level must propagate.
2046  std::vector<Coefficient> sum_for_le_level(backjump_level + 2, Coefficient(0));
2047  std::vector<Coefficient> max_coeff_for_ge_level(backjump_level + 2,
2048  Coefficient(0));
2049  int size = 0;
2050  Coefficient max_sum(0);
2051  for (BooleanVariable var : conflict->PossibleNonZeros()) {
2052  const Coefficient coeff = conflict->GetCoefficient(var);
2053  if (coeff == 0) continue;
2054  max_sum += coeff;
2055  ++size;
2056  if (!trail_->Assignment().VariableIsAssigned(var) ||
2057  DecisionLevel(var) > backjump_level) {
2058  max_coeff_for_ge_level[backjump_level + 1] =
2059  std::max(max_coeff_for_ge_level[backjump_level + 1], coeff);
2060  } else {
2061  const int level = DecisionLevel(var);
2062  if (trail_->Assignment().LiteralIsTrue(conflict->GetLiteral(var))) {
2063  sum_for_le_level[level] += coeff;
2064  }
2065  max_coeff_for_ge_level[level] =
2066  std::max(max_coeff_for_ge_level[level], coeff);
2067  }
2068  }
2069 
2070  // Compute the cumulative version.
2071  for (int i = 1; i < sum_for_le_level.size(); ++i) {
2072  sum_for_le_level[i] += sum_for_le_level[i - 1];
2073  }
2074  for (int i = max_coeff_for_ge_level.size() - 2; i >= 0; --i) {
2075  max_coeff_for_ge_level[i] =
2076  std::max(max_coeff_for_ge_level[i], max_coeff_for_ge_level[i + 1]);
2077  }
2078 
2079  // Compute first propagation level. -1 means that the problem is UNSAT.
2080  // Note that the first propagation level may be < backjump_level!
2081  if (sum_for_le_level[0] > conflict->Rhs()) {
2082  *pb_backjump_level = -1;
2083  return;
2084  }
2085  for (int i = 0; i <= backjump_level; ++i) {
2086  const Coefficient level_sum = sum_for_le_level[i];
2087  CHECK_LE(level_sum, conflict->Rhs());
2088  if (conflict->Rhs() - level_sum < max_coeff_for_ge_level[i + 1]) {
2089  *pb_backjump_level = i;
2090  return;
2091  }
2092  }
2093  LOG(FATAL) << "The code should never reach here.";
2094 }
2095 
2096 void SatSolver::MinimizeConflict(
2097  std::vector<Literal>* conflict,
2098  std::vector<Literal>* reason_used_to_infer_the_conflict) {
2099  SCOPED_TIME_STAT(&stats_);
2100 
2101  const int old_size = conflict->size();
2102  switch (parameters_->minimization_algorithm()) {
2103  case SatParameters::NONE:
2104  return;
2105  case SatParameters::SIMPLE: {
2106  MinimizeConflictSimple(conflict);
2107  break;
2108  }
2109  case SatParameters::RECURSIVE: {
2110  MinimizeConflictRecursively(conflict);
2111  break;
2112  }
2113  case SatParameters::EXPERIMENTAL: {
2114  MinimizeConflictExperimental(conflict);
2115  break;
2116  }
2117  }
2118  if (conflict->size() < old_size) {
2119  ++counters_.num_minimizations;
2120  counters_.num_literals_removed += old_size - conflict->size();
2121  }
2122 }
2123 
2124 // This simple version just looks for any literal that is directly infered by
2125 // other literals of the conflict. It is directly infered if the literals of its
2126 // reason clause are either from level 0 or from the conflict itself.
2127 //
2128 // Note that because of the assignement structure, there is no need to process
2129 // the literals of the conflict in order. While exploring the reason for a
2130 // literal assignement, there will be no cycles.
2131 void SatSolver::MinimizeConflictSimple(std::vector<Literal>* conflict) {
2132  SCOPED_TIME_STAT(&stats_);
2133  const int current_level = CurrentDecisionLevel();
2134 
2135  // Note that is_marked_ is already initialized and that we can start at 1
2136  // since the first literal of the conflict is the 1-UIP literal.
2137  int index = 1;
2138  for (int i = 1; i < conflict->size(); ++i) {
2139  const BooleanVariable var = (*conflict)[i].Variable();
2140  bool can_be_removed = false;
2141  if (DecisionLevel(var) != current_level) {
2142  // It is important not to call Reason(var) when it can be avoided.
2143  const absl::Span<const Literal> reason = trail_->Reason(var);
2144  if (!reason.empty()) {
2145  can_be_removed = true;
2146  for (Literal literal : reason) {
2147  if (DecisionLevel(literal.Variable()) == 0) continue;
2148  if (!is_marked_[literal.Variable()]) {
2149  can_be_removed = false;
2150  break;
2151  }
2152  }
2153  }
2154  }
2155  if (!can_be_removed) {
2156  (*conflict)[index] = (*conflict)[i];
2157  ++index;
2158  }
2159  }
2160  conflict->erase(conflict->begin() + index, conflict->end());
2161 }
2162 
2163 // This is similar to MinimizeConflictSimple() except that for each literal of
2164 // the conflict, the literals of its reason are recursively expanded using their
2165 // reason and so on. The recusion stop until we show that the initial literal
2166 // can be infered from the conflict variables alone, or if we show that this is
2167 // not the case. The result of any variable expansion will be cached in order
2168 // not to be expended again.
2169 void SatSolver::MinimizeConflictRecursively(std::vector<Literal>* conflict) {
2170  SCOPED_TIME_STAT(&stats_);
2171 
2172  // is_marked_ will contains all the conflict literals plus the literals that
2173  // have been shown to depends only on the conflict literals. is_independent_
2174  // will contains the literals that have been shown NOT to depends only on the
2175  // conflict literals. The too set are exclusive for non-conflict literals, but
2176  // a conflict literal (which is always marked) can be independent if we showed
2177  // that it can't be removed from the clause.
2178  //
2179  // Optimization: There is no need to call is_marked_.ClearAndResize() or to
2180  // mark the conflict literals since this was already done by
2181  // ComputeFirstUIPConflict().
2182  is_independent_.ClearAndResize(num_variables_);
2183 
2184  // min_trail_index_per_level_ will always be reset to all
2185  // std::numeric_limits<int>::max() at the end. This is used to prune the
2186  // search because any literal at a given level with an index smaller or equal
2187  // to min_trail_index_per_level_[level] can't be redundant.
2188  if (CurrentDecisionLevel() >= min_trail_index_per_level_.size()) {
2189  min_trail_index_per_level_.resize(CurrentDecisionLevel() + 1,
2191  }
2192 
2193  // Compute the number of variable at each decision levels. This will be used
2194  // to pruned the DFS because we know that the minimized conflict will have at
2195  // least one variable of each decision levels. Because such variable can't be
2196  // eliminated using lower decision levels variable otherwise it will have been
2197  // propagated.
2198  //
2199  // Note(user): Because is_marked_ may actually contains literals that are
2200  // implied if the 1-UIP literal is false, we can't just iterate on the
2201  // variables of the conflict here.
2202  for (BooleanVariable var : is_marked_.PositionsSetAtLeastOnce()) {
2203  const int level = DecisionLevel(var);
2204  min_trail_index_per_level_[level] = std::min(
2205  min_trail_index_per_level_[level], trail_->Info(var).trail_index);
2206  }
2207 
2208  // Remove the redundant variable from the conflict. That is the ones that can
2209  // be infered by some other variables in the conflict.
2210  // Note that we can skip the first position since this is the 1-UIP.
2211  int index = 1;
2212  for (int i = 1; i < conflict->size(); ++i) {
2213  const BooleanVariable var = (*conflict)[i].Variable();
2214  if (time_limit_->LimitReached() ||
2215  trail_->Info(var).trail_index <=
2216  min_trail_index_per_level_[DecisionLevel(var)] ||
2217  !CanBeInferedFromConflictVariables(var)) {
2218  // Mark the conflict variable as independent. Note that is_marked_[var]
2219  // will still be true.
2220  is_independent_.Set(var);
2221  (*conflict)[index] = (*conflict)[i];
2222  ++index;
2223  }
2224  }
2225  conflict->resize(index);
2226 
2227  // Reset min_trail_index_per_level_. We use the sparse version only if it
2228  // involves less than half the size of min_trail_index_per_level_.
2229  const int threshold = min_trail_index_per_level_.size() / 2;
2230  if (is_marked_.PositionsSetAtLeastOnce().size() < threshold) {
2231  for (BooleanVariable var : is_marked_.PositionsSetAtLeastOnce()) {
2232  min_trail_index_per_level_[DecisionLevel(var)] =
2234  }
2235  } else {
2236  min_trail_index_per_level_.clear();
2237  }
2238 }
2239 
2240 bool SatSolver::CanBeInferedFromConflictVariables(BooleanVariable variable) {
2241  // Test for an already processed variable with the same reason.
2242  {
2243  DCHECK(is_marked_[variable]);
2244  const BooleanVariable v =
2245  same_reason_identifier_.FirstVariableWithSameReason(variable);
2246  if (v != variable) return !is_independent_[v];
2247  }
2248 
2249  // This function implement an iterative DFS from the given variable. It uses
2250  // the reason clause as adjacency lists. dfs_stack_ can be seens as the
2251  // recursive call stack of the variable we are currently processing. All its
2252  // adjacent variable will be pushed into variable_to_process_, and we will
2253  // then dequeue them one by one and process them.
2254  //
2255  // Note(user): As of 03/2014, --cpu_profile seems to indicate that using
2256  // dfs_stack_.assign(1, variable) is slower. My explanation is that the
2257  // function call is not inlined.
2258  dfs_stack_.clear();
2259  dfs_stack_.push_back(variable);
2260  variable_to_process_.clear();
2261  variable_to_process_.push_back(variable);
2262 
2263  // First we expand the reason for the given variable.
2264  for (Literal literal : trail_->Reason(variable)) {
2265  const BooleanVariable var = literal.Variable();
2266  DCHECK_NE(var, variable);
2267  if (is_marked_[var]) continue;
2268  const int level = DecisionLevel(var);
2269  if (level == 0) {
2270  // Note that this is not needed if the solver is not configured to produce
2271  // an unsat proof. However, the (level == 0) test should always be false
2272  // in this case because there will never be literals of level zero in any
2273  // reason when we don't want a proof.
2274  is_marked_.Set(var);
2275  continue;
2276  }
2277  if (trail_->Info(var).trail_index <= min_trail_index_per_level_[level] ||
2278  is_independent_[var]) {
2279  return false;
2280  }
2281  variable_to_process_.push_back(var);
2282  }
2283 
2284  // Then we start the DFS.
2285  while (!variable_to_process_.empty()) {
2286  const BooleanVariable current_var = variable_to_process_.back();
2287  if (current_var == dfs_stack_.back()) {
2288  // We finished the DFS of the variable dfs_stack_.back(), this can be seen
2289  // as a recursive call terminating.
2290  if (dfs_stack_.size() > 1) {
2291  DCHECK(!is_marked_[current_var]);
2292  is_marked_.Set(current_var);
2293  }
2294  variable_to_process_.pop_back();
2295  dfs_stack_.pop_back();
2296  continue;
2297  }
2298 
2299  // If this variable became marked since the we pushed it, we can skip it.
2300  if (is_marked_[current_var]) {
2301  variable_to_process_.pop_back();
2302  continue;
2303  }
2304 
2305  // This case will never be encountered since we abort right away as soon
2306  // as an independent variable is found.
2307  DCHECK(!is_independent_[current_var]);
2308 
2309  // Test for an already processed variable with the same reason.
2310  {
2311  const BooleanVariable v =
2312  same_reason_identifier_.FirstVariableWithSameReason(current_var);
2313  if (v != current_var) {
2314  if (is_independent_[v]) break;
2315  DCHECK(is_marked_[v]);
2316  variable_to_process_.pop_back();
2317  continue;
2318  }
2319  }
2320 
2321  // Expand the variable. This can be seen as making a recursive call.
2322  dfs_stack_.push_back(current_var);
2323  bool abort_early = false;
2324  for (Literal literal : trail_->Reason(current_var)) {
2325  const BooleanVariable var = literal.Variable();
2326  DCHECK_NE(var, current_var);
2327  const int level = DecisionLevel(var);
2328  if (level == 0 || is_marked_[var]) continue;
2329  if (trail_->Info(var).trail_index <= min_trail_index_per_level_[level] ||
2330  is_independent_[var]) {
2331  abort_early = true;
2332  break;
2333  }
2334  variable_to_process_.push_back(var);
2335  }
2336  if (abort_early) break;
2337  }
2338 
2339  // All the variable left on the dfs_stack_ are independent.
2340  for (const BooleanVariable var : dfs_stack_) {
2341  is_independent_.Set(var);
2342  }
2343  return dfs_stack_.empty();
2344 }
2345 
2346 namespace {
2347 
2348 struct WeightedVariable {
2349  WeightedVariable(BooleanVariable v, int w) : var(v), weight(w) {}
2350 
2351  BooleanVariable var;
2352  int weight;
2353 };
2354 
2355 // Lexical order, by larger weight, then by smaller variable number
2356 // to break ties
2357 struct VariableWithLargerWeightFirst {
2358  bool operator()(const WeightedVariable& wv1,
2359  const WeightedVariable& wv2) const {
2360  return (wv1.weight > wv2.weight ||
2361  (wv1.weight == wv2.weight && wv1.var < wv2.var));
2362  }
2363 };
2364 } // namespace.
2365 
2366 // This function allows a conflict variable to be replaced by another variable
2367 // not originally in the conflict. Greater reduction and backtracking can be
2368 // achieved this way, but the effect of this is not clear.
2369 //
2370 // TODO(user): More investigation needed. This seems to help on the Hanoi
2371 // problems, but degrades performance on others.
2372 //
2373 // TODO(user): Find a reference for this? neither minisat nor glucose do that,
2374 // they just do MinimizeConflictRecursively() with a different implementation.
2375 // Note that their behavior also make more sense with the way they (and we) bump
2376 // the variable activities.
2377 void SatSolver::MinimizeConflictExperimental(std::vector<Literal>* conflict) {
2378  SCOPED_TIME_STAT(&stats_);
2379 
2380  // First, sort the variables in the conflict by decreasing decision levels.
2381  // Also initialize is_marked_ to true for all conflict variables.
2382  is_marked_.ClearAndResize(num_variables_);
2383  const int current_level = CurrentDecisionLevel();
2384  std::vector<WeightedVariable> variables_sorted_by_level;
2385  for (Literal literal : *conflict) {
2386  const BooleanVariable var = literal.Variable();
2387  is_marked_.Set(var);
2388  const int level = DecisionLevel(var);
2389  if (level < current_level) {
2390  variables_sorted_by_level.push_back(WeightedVariable(var, level));
2391  }
2392  }
2393  std::sort(variables_sorted_by_level.begin(), variables_sorted_by_level.end(),
2394  VariableWithLargerWeightFirst());
2395 
2396  // Then process the reason of the variable with highest level first.
2397  std::vector<BooleanVariable> to_remove;
2398  for (WeightedVariable weighted_var : variables_sorted_by_level) {
2399  const BooleanVariable var = weighted_var.var;
2400 
2401  // A nullptr reason means that this was a decision variable from the
2402  // previous levels.
2403  const absl::Span<const Literal> reason = trail_->Reason(var);
2404  if (reason.empty()) continue;
2405 
2406  // Compute how many and which literals from the current reason do not appear
2407  // in the current conflict. Level 0 literals are ignored.
2408  std::vector<Literal> not_contained_literals;
2409  for (const Literal reason_literal : reason) {
2410  const BooleanVariable reason_var = reason_literal.Variable();
2411 
2412  // We ignore level 0 variables.
2413  if (DecisionLevel(reason_var) == 0) continue;
2414 
2415  // We have a reason literal whose variable is not yet seen.
2416  // If there is more than one, break right away, we will not minimize the
2417  // current conflict with this variable.
2418  if (!is_marked_[reason_var]) {
2419  not_contained_literals.push_back(reason_literal);
2420  if (not_contained_literals.size() > 1) break;
2421  }
2422  }
2423  if (not_contained_literals.empty()) {
2424  // This variable will be deleted from the conflict. Note that we don't
2425  // unmark it. This is because this variable can be infered from the other
2426  // variables in the conflict, so it is okay to skip it when processing the
2427  // reasons of other variables.
2428  to_remove.push_back(var);
2429  } else if (not_contained_literals.size() == 1) {
2430  // Replace the literal from variable var with the only
2431  // not_contained_literals from the current reason.
2432  to_remove.push_back(var);
2433  is_marked_.Set(not_contained_literals.front().Variable());
2434  conflict->push_back(not_contained_literals.front());
2435  }
2436  }
2437 
2438  // Unmark the variable that should be removed from the conflict.
2439  for (BooleanVariable var : to_remove) {
2440  is_marked_.Clear(var);
2441  }
2442 
2443  // Remove the now unmarked literals from the conflict.
2444  int index = 0;
2445  for (int i = 0; i < conflict->size(); ++i) {
2446  const Literal literal = (*conflict)[i];
2447  if (is_marked_[literal.Variable()]) {
2448  (*conflict)[index] = literal;
2449  ++index;
2450  }
2451  }
2452  conflict->erase(conflict->begin() + index, conflict->end());
2453 }
2454 
2455 void SatSolver::CleanClauseDatabaseIfNeeded() {
2456  if (num_learned_clause_before_cleanup_ > 0) return;
2457  SCOPED_TIME_STAT(&stats_);
2458 
2459  // Creates a list of clauses that can be deleted. Note that only the clauses
2460  // that appear in clauses_info can potentially be removed.
2461  typedef std::pair<SatClause*, ClauseInfo> Entry;
2462  std::vector<Entry> entries;
2463  auto& clauses_info = *(clauses_propagator_->mutable_clauses_info());
2464  for (auto& entry : clauses_info) {
2465  if (ClauseIsUsedAsReason(entry.first)) continue;
2466  if (entry.second.protected_during_next_cleanup) {
2467  entry.second.protected_during_next_cleanup = false;
2468  continue;
2469  }
2470  entries.push_back(entry);
2471  }
2472  const int num_protected_clauses = clauses_info.size() - entries.size();
2473 
2474  if (parameters_->clause_cleanup_ordering() == SatParameters::CLAUSE_LBD) {
2475  // Order the clauses by decreasing LBD and then increasing activity.
2476  std::sort(entries.begin(), entries.end(),
2477  [](const Entry& a, const Entry& b) {
2478  if (a.second.lbd == b.second.lbd) {
2479  return a.second.activity < b.second.activity;
2480  }
2481  return a.second.lbd > b.second.lbd;
2482  });
2483  } else {
2484  // Order the clauses by increasing activity and then decreasing LBD.
2485  std::sort(entries.begin(), entries.end(),
2486  [](const Entry& a, const Entry& b) {
2487  if (a.second.activity == b.second.activity) {
2488  return a.second.lbd > b.second.lbd;
2489  }
2490  return a.second.activity < b.second.activity;
2491  });
2492  }
2493 
2494  // The clause we want to keep are at the end of the vector.
2495  int num_kept_clauses = std::min(static_cast<int>(entries.size()),
2496  parameters_->clause_cleanup_target());
2497  int num_deleted_clauses = entries.size() - num_kept_clauses;
2498 
2499  // Tricky: Because the order of the clauses_info iteration is NOT
2500  // deterministic (pointer keys), we also keep all the clauses which have the
2501  // same LBD and activity as the last one so the behavior is deterministic.
2502  while (num_deleted_clauses > 0) {
2503  const ClauseInfo& a = entries[num_deleted_clauses].second;
2504  const ClauseInfo& b = entries[num_deleted_clauses - 1].second;
2505  if (a.activity != b.activity || a.lbd != b.lbd) break;
2506  --num_deleted_clauses;
2507  ++num_kept_clauses;
2508  }
2509  if (num_deleted_clauses > 0) {
2510  entries.resize(num_deleted_clauses);
2511  for (const Entry& entry : entries) {
2512  SatClause* clause = entry.first;
2513  counters_.num_literals_forgotten += clause->size();
2514  clauses_propagator_->LazyDetach(clause);
2515  }
2516  clauses_propagator_->CleanUpWatchers();
2517 
2518  // TODO(user): If the need arise, we could avoid this linear scan on the
2519  // full list of clauses by not keeping the clauses from clauses_info there.
2520  if (!block_clause_deletion_) {
2521  clauses_propagator_->DeleteRemovedClauses();
2522  }
2523  }
2524 
2525  num_learned_clause_before_cleanup_ = parameters_->clause_cleanup_period();
2526  VLOG(1) << "Database cleanup, #protected:" << num_protected_clauses
2527  << " #kept:" << num_kept_clauses
2528  << " #deleted:" << num_deleted_clauses;
2529 }
2530 
2531 std::string SatStatusString(SatSolver::Status status) {
2532  switch (status) {
2533  case SatSolver::ASSUMPTIONS_UNSAT:
2534  return "ASSUMPTIONS_UNSAT";
2535  case SatSolver::INFEASIBLE:
2536  return "INFEASIBLE";
2537  case SatSolver::FEASIBLE:
2538  return "FEASIBLE";
2539  case SatSolver::LIMIT_REACHED:
2540  return "LIMIT_REACHED";
2541  }
2542  // Fallback. We don't use "default:" so the compiler will return an error
2543  // if we forgot one enum case above.
2544  LOG(DFATAL) << "Invalid SatSolver::Status " << status;
2545  return "UNKNOWN";
2546 }
2547 
2548 void MinimizeCore(SatSolver* solver, std::vector<Literal>* core) {
2549  std::vector<Literal> temp = *core;
2550  std::reverse(temp.begin(), temp.end());
2551  solver->Backtrack(0);
2552  solver->SetAssumptionLevel(0);
2553 
2554  // Note that this Solve() is really fast, since the solver should detect that
2555  // the assumptions are unsat with unit propagation only. This is just a
2556  // convenient way to remove assumptions that are propagated by the one before
2557  // them.
2558  const SatSolver::Status status =
2559  solver->ResetAndSolveWithGivenAssumptions(temp);
2560  if (status != SatSolver::ASSUMPTIONS_UNSAT) {
2561  if (status != SatSolver::LIMIT_REACHED) {
2562  CHECK_NE(status, SatSolver::FEASIBLE);
2563  // This should almost never happen, but it is not impossible. The reason
2564  // is that the solver may delete some learned clauses required by the unit
2565  // propagation to show that the core is unsat.
2566  LOG(WARNING) << "This should only happen rarely! otherwise, investigate. "
2567  << "Returned status is " << SatStatusString(status);
2568  }
2569  return;
2570  }
2571  temp = solver->GetLastIncompatibleDecisions();
2572  if (temp.size() < core->size()) {
2573  VLOG(1) << "minimization " << core->size() << " -> " << temp.size();
2574  std::reverse(temp.begin(), temp.end());
2575  *core = temp;
2576  }
2577 }
2578 
2579 } // namespace sat
2580 } // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
#define CHECK(condition)
Definition: base/logging.h:498
#define DCHECK_LE(val1, val2)
Definition: base/logging.h:895
#define DCHECK_NE(val1, val2)
Definition: base/logging.h:894
#define CHECK_LT(val1, val2)
Definition: base/logging.h:708
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:705
#define CHECK_GE(val1, val2)
Definition: base/logging.h:709
#define CHECK_GT(val1, val2)
Definition: base/logging.h:710
#define DCHECK_GE(val1, val2)
Definition: base/logging.h:897
#define CHECK_NE(val1, val2)
Definition: base/logging.h:706
#define DCHECK_GT(val1, val2)
Definition: base/logging.h:898
#define DCHECK_LT(val1, val2)
Definition: base/logging.h:896
#define LOG(severity)
Definition: base/logging.h:423
#define DCHECK(condition)
Definition: base/logging.h:892
#define CHECK_LE(val1, val2)
Definition: base/logging.h:707
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:893
#define VLOG(verboselevel)
Definition: base/logging.h:986
void Restart()
Definition: timer.h:35
double Get() const
Definition: timer.h:45
const std::vector< IntegerType > & PositionsSetAtLeastOnce() const
Definition: bitset.h:814
void Set(IntegerType index)
Definition: bitset.h:804
int NumberOfSetCallsWithDifferentArguments() const
Definition: bitset.h:811
void Clear(IntegerType index)
Definition: bitset.h:810
void ClearAndResize(IntegerType size)
Definition: bitset.h:779
std::string StatString() const
Definition: stats.cc:71
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:105
void ResetLimitFromParameters(const Parameters &parameters)
Sets new time limits.
Definition: time_limit.h:505
bool LimitReached()
Returns true when the external limit is true, or the deterministic time is over the deterministic lim...
Definition: time_limit.h:532
const std::vector< BinaryClause > & newly_added() const
Definition: clause.h:404
void AddBinaryClause(Literal a, Literal b)
Definition: clause.cc:492
void MinimizeConflictWithReachability(std::vector< Literal > *c)
Definition: clause.cc:783
bool AddBinaryClauseDuringSearch(Literal a, Literal b)
Definition: clause.cc:509
void MinimizeConflictFirstWithTransitiveReduction(const Trail &trail, std::vector< Literal > *c, SparseBitset< BooleanVariable > *marked, absl::BitGenRef random)
Definition: clause.cc:878
void MinimizeConflictFirst(const Trail &trail, std::vector< Literal > *c, SparseBitset< BooleanVariable > *marked)
Definition: clause.cc:860
ABSL_MUST_USE_RESULT bool AddAtMostOne(absl::Span< const Literal > at_most_one)
Definition: clause.cc:532
void MinimizeConflictExperimental(const Trail &trail, std::vector< Literal > *c)
Definition: clause.cc:940
void DeleteClause(absl::Span< const Literal > clause)
void AddClause(absl::Span< const Literal > clause)
BooleanVariable Variable() const
Definition: sat_base.h:81
const std::vector< SatClause * > & AllClausesInCreationOrder() const
Definition: clause.h:212
absl::flat_hash_map< SatClause *, ClauseInfo > * mutable_clauses_info()
Definition: clause.h:224
SatClause * AddRemovableClause(const std::vector< Literal > &literals, Trail *trail)
Definition: clause.cc:213
bool AddClause(absl::Span< const Literal > literals, Trail *trail)
Definition: clause.cc:206
SatClause * ReasonClause(int trail_index) const
Definition: clause.cc:198
bool IsRemovable(SatClause *const clause) const
Definition: clause.h:220
ABSL_MUST_USE_RESULT bool InprocessingRewriteClause(SatClause *clause, absl::Span< const Literal > new_clause)
Definition: clause.cc:368
void LazyDetach(SatClause *clause)
Definition: clause.cc:295
int64_t num_inspected_clause_literals() const
Definition: clause.h:230
void Detach(SatClause *clause)
Definition: clause.cc:302
void Resize(int num_variables)
Definition: clause.cc:70
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:38
void Register(T *non_owned_class)
Register a non-owned class that will be "singleton" in the model.
Definition: sat/model.h:169
T * GetOrCreate()
Returns an object of type T that is unique to this model (like a "local" singleton).
Definition: sat/model.h:106
Coefficient ComputeSlackForTrailPrefix(const Trail &trail, int trail_index) const
void AddTerm(Literal literal, Coefficient coeff)
void CopyIntoVector(std::vector< LiteralWithCoeff > *output)
bool AddConstraint(const std::vector< LiteralWithCoeff > &cst, Coefficient rhs, Trail *trail)
UpperBoundedLinearConstraint * ConflictingConstraint()
UpperBoundedLinearConstraint * ReasonPbConstraint(int trail_index) const
void BumpActivity(UpperBoundedLinearConstraint *constraint)
bool AddLearnedConstraint(const std::vector< LiteralWithCoeff > &cst, Coefficient rhs, Trail *trail)
void OnConflict(int conflict_trail_index, int conflict_decision_level, int conflict_lbd)
Definition: restart.cc:144
void IncreaseNumVariables(int num_variables)
Definition: sat_decision.cc:28
void Untrail(int target_trail_index)
void BumpVariableActivities(const std::vector< Literal > &literals)
void UpdateWeightedSign(const std::vector< LiteralWithCoeff > &terms, Coefficient rhs)
const Trail & LiteralTrail() const
Definition: sat_solver.h:362
bool AddLinearConstraint(bool use_lower_bound, Coefficient lower_bound, bool use_upper_bound, Coefficient upper_bound, std::vector< LiteralWithCoeff > *cst)
Definition: sat_solver.cc:300
bool EnqueueDecisionIfNotConflicting(Literal true_literal)
Definition: sat_solver.cc:874
void SetNumVariables(int num_variables)
Definition: sat_solver.cc:65
bool AddTernaryClause(Literal a, Literal b, Literal c)
Definition: sat_solver.cc:192
void AddLastPropagator(SatPropagator *propagator)
Definition: sat_solver.cc:414
const SatParameters & parameters() const
Definition: sat_solver.cc:111
bool AddClauseDuringSearch(absl::Span< const Literal > literals)
Definition: sat_solver.cc:135
Status SolveWithTimeLimit(TimeLimit *time_limit)
Definition: sat_solver.cc:969
Status ResetAndSolveWithGivenAssumptions(const std::vector< Literal > &assumptions)
Definition: sat_solver.cc:948
void AddPropagator(SatPropagator *propagator)
Definition: sat_solver.cc:406
const std::vector< BinaryClause > & NewlyAddedBinaryClauses()
Definition: sat_solver.cc:933
bool AddBinaryClauses(const std::vector< BinaryClause > &clauses)
Definition: sat_solver.cc:919
void SetAssumptionLevel(int assumption_level)
Definition: sat_solver.cc:963
void AdvanceDeterministicTime(TimeLimit *limit)
Definition: sat_solver.h:423
void MinimizeSomeClauses(int decisions_budget)
Definition: sat_solver.cc:1248
const VariablesAssignment & Assignment() const
Definition: sat_solver.h:363
int EnqueueDecisionAndBackjumpOnConflict(Literal true_literal)
Definition: sat_solver.cc:500
void SetParameters(const SatParameters &parameters)
Definition: sat_solver.cc:116
bool AddBinaryClause(Literal a, Literal b)
Definition: sat_solver.cc:181
int EnqueueDecisionAndBacktrackOnConflict(Literal true_literal)
Definition: sat_solver.cc:862
void Backtrack(int target_level)
Definition: sat_solver.cc:889
std::vector< Literal > GetLastIncompatibleDecisions()
Definition: sat_solver.cc:1273
bool ResetWithGivenAssumptions(const std::vector< Literal > &assumptions)
Definition: sat_solver.cc:537
bool AddProblemClause(absl::Span< const Literal > literals)
Definition: sat_solver.cc:204
bool AddUnitClause(Literal true_literal)
Definition: sat_solver.cc:165
absl::Span< const Literal > FailingClause() const
Definition: sat_base.h:368
void RegisterPropagator(SatPropagator *propagator)
Definition: sat_base.h:552
const AssignmentInfo & Info(BooleanVariable var) const
Definition: sat_base.h:382
int64_t NumberOfEnqueues() const
Definition: sat_base.h:378
SatClause * FailingSatClause() const
Definition: sat_base.h:374
int AssignmentType(BooleanVariable var) const
Definition: sat_base.h:573
absl::Span< const Literal > Reason(BooleanVariable var) const
Definition: sat_base.h:582
BooleanVariable ReferenceVarWithSameReason(BooleanVariable var) const
Definition: sat_base.h:561
const VariablesAssignment & Assignment() const
Definition: sat_base.h:381
void Untrail(int target_trail_index)
Definition: sat_base.h:344
void SetDecisionLevel(int level)
Definition: sat_base.h:355
void Resize(int num_variables)
Definition: sat_base.h:540
void EnqueueWithUnitReason(Literal true_literal)
Definition: sat_base.h:266
void EnqueueSearchDecision(Literal true_literal)
Definition: sat_base.h:261
void AddToConflict(MutableUpperBoundedLinearConstraint *conflict)
BooleanVariable FirstVariableWithSameReason(BooleanVariable var)
bool VariableIsAssigned(BooleanVariable var) const
Definition: sat_base.h:159
bool LiteralIsTrue(Literal literal) const
Definition: sat_base.h:151
void AssignFromTrueLiteral(Literal literal)
Definition: sat_base.h:134
Literal GetTrueLiteralForAssignedVariable(BooleanVariable var) const
Definition: sat_base.h:166
bool LiteralIsFalse(Literal literal) const
Definition: sat_base.h:148
int64_t b
int64_t a
SatParameters parameters
SharedTimeLimit * time_limit
int64_t value
double upper_bound
double lower_bound
GRBmodel * model
const int WARNING
Definition: log_severity.h:31
const int INFO
Definition: log_severity.h:31
const int FATAL
Definition: log_severity.h:32
const bool DEBUG_MODE
Definition: macros.h:24
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
Definition: id_map.h:263
Coefficient ComputeCanonicalRhs(Coefficient upper_bound, Coefficient bound_shift, Coefficient max_value)
int MoveOneUnprocessedLiteralLast(const std::set< LiteralIndex > &processed, int relevant_prefix_size, std::vector< Literal > *literals)
Definition: sat/util.cc:25
Coefficient ComputeNegatedCanonicalRhs(Coefficient lower_bound, Coefficient bound_shift, Coefficient max_value)
void MinimizeCore(SatSolver *solver, std::vector< Literal > *core)
Definition: sat_solver.cc:2548
std::string SatStatusString(SatSolver::Status status)
Definition: sat_solver.cc:2531
bool ComputeBooleanLinearExpressionCanonicalForm(std::vector< LiteralWithCoeff > *cst, Coefficient *bound_shift, Coefficient *max_value)
bool BooleanLinearExpressionIsCanonical(const std::vector< LiteralWithCoeff > &cst)
const int kUnsatTrailIndex
Definition: sat_solver.h:53
Collection of objects used to extend the Constraint Solver library.
std::string ProtobufShortDebugString(const P &message)
std::string MemoryUsage()
Definition: stats.cc:25
bool SafeAddInto(IntegerType a, IntegerType *b)
Literal literal
Definition: optimization.cc:85
int index
Definition: pack.cc:509
static int input(yyscan_t yyscanner)
IntervalVar * interval
Definition: resource.cc:100
BooleanVariable var
Definition: sat_solver.cc:2351
int weight
Definition: sat_solver.cc:2352
#define IF_STATS_ENABLED(instructions)
Definition: stats.h:437
#define SCOPED_TIME_STAT(stats)
Definition: stats.h:438
static constexpr int kSearchDecision
Definition: sat_base.h:224