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