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