23#include "absl/container/flat_hash_map.h"
24#include "absl/hash/hash.h"
25#include "absl/log/check.h"
26#include "absl/strings/str_format.h"
27#include "absl/types/span.h"
31#include "ortools/sat/sat_parameters.pb.h"
42bool LiteralComparator(
const LiteralWithCoeff&
a,
const LiteralWithCoeff&
b) {
43 return a.literal.Index() <
b.literal.Index();
46bool CoeffComparator(
const LiteralWithCoeff&
a,
const LiteralWithCoeff&
b) {
47 if (
a.coefficient ==
b.coefficient) {
48 return a.literal.Index() <
b.literal.Index();
50 return a.coefficient <
b.coefficient;
56 std::vector<LiteralWithCoeff>* cst, Coefficient* bound_shift,
57 Coefficient* max_value) {
65 std::sort(cst->begin(), cst->end(), LiteralComparator);
68 for (
int i = 0;
i < cst->size(); ++
i) {
89 (*cst)[
index] = current;
101 for (
int i = 0;
i < cst->size(); ++
i) {
112 std::sort(cst->begin(), cst->end(), CoeffComparator);
113 DCHECK_GE(*max_value, 0);
119 std::vector<LiteralWithCoeff>* cst, Coefficient* bound_shift,
120 Coefficient* max_value) {
122 Coefficient shift_due_to_fixed_variables(0);
124 if (mapping[entry.literal] >= 0) {
129 if (!
SafeAddInto(-entry.coefficient, &shift_due_to_fixed_variables)) {
139 *bound_shift = shift_due_to_fixed_variables;
145 if (!
SafeAddInto(shift_due_to_fixed_variables, bound_shift))
return false;
151 absl::Span<const LiteralWithCoeff> cst) {
152 Coefficient previous(1);
154 if (term.coefficient < previous)
return false;
155 previous = term.coefficient;
163 std::vector<LiteralWithCoeff>* cst, Coefficient* rhs) {
170 if (
x.coefficient > *rhs)
x.coefficient = *rhs + 1;
175 Coefficient bound_shift,
176 Coefficient max_value) {
179 if (bound_shift > 0) {
185 return Coefficient(-1);
188 if (rhs < 0)
return Coefficient(-1);
189 return std::min(max_value, rhs);
193 Coefficient bound_shift,
194 Coefficient max_value) {
199 if (bound_shift > 0) {
201 return Coefficient(-1);
207 if (shifted_lb <= 0) {
212 return max_value - shifted_lb;
216 bool use_lower_bound, Coefficient
lower_bound,
bool use_upper_bound,
217 Coefficient
upper_bound, std::vector<LiteralWithCoeff>* cst) {
219 Coefficient bound_shift;
220 Coefficient max_value;
225 if (use_upper_bound) {
226 const Coefficient rhs =
228 if (!AddConstraint(*cst, max_value, rhs))
return false;
230 if (use_lower_bound) {
232 for (
int i = 0;
i < cst->size(); ++
i) {
233 (*cst)[
i].literal = (*cst)[
i].literal.Negated();
235 const Coefficient rhs =
237 if (!AddConstraint(*cst, max_value, rhs))
return false;
242bool CanonicalBooleanLinearProblem::AddConstraint(
243 absl::Span<const LiteralWithCoeff> cst, Coefficient max_value,
245 if (rhs < 0)
return false;
246 if (rhs >= max_value)
return true;
247 constraints_.emplace_back(cst.begin(), cst.end());
254 if (terms_.size() != num_variables) {
255 terms_.
assign(num_variables, Coefficient(0));
267 terms_[
var] = Coefficient(0);
276 CHECK_LT(rhs_, max_sum_) <<
"Trivially sat.";
277 Coefficient removed_sum(0);
278 const Coefficient
bound = max_sum_ - rhs_;
287 max_sum_ -= removed_sum;
288 DCHECK_EQ(max_sum_, ComputeMaxSum());
294 if (!result.empty()) result +=
" + ";
298 result += absl::StrFormat(
" <= %d", rhs_.value());
305 const Trail& trail,
int trail_index)
const {
306 Coefficient activity(0);
314 return rhs_ - activity;
320 Coefficient activity(0);
321 Coefficient removed_sum(0);
322 const Coefficient
bound = max_sum_ - rhs_;
342 max_sum_ -= removed_sum;
343 DCHECK_EQ(max_sum_, ComputeMaxSum());
344 return rhs_ - activity;
348 const Trail& trail,
int trail_index, Coefficient initial_slack,
349 Coefficient target) {
351 const Coefficient slack = initial_slack;
353 CHECK_LE(target, slack);
358 const Coefficient coeff =
GetCoefficient(trail[trail_index].Variable());
359 CHECK_LT(slack, coeff);
362 if (slack == target)
return;
365 const Coefficient diff = slack - target;
374 terms_[
var] = (terms_[
var] > 0) ? terms_[
var] - diff : terms_[
var] + diff;
381 DCHECK_EQ(max_sum_, ComputeMaxSum());
385 std::vector<LiteralWithCoeff>* output) {
393 std::sort(output->begin(), output->end(), CoeffComparator);
396Coefficient MutableUpperBoundedLinearConstraint::ComputeMaxSum()
const {
397 Coefficient result(0);
405 const std::vector<LiteralWithCoeff>& cst)
406 : is_marked_for_deletion_(false),
408 first_reason_trail_index_(-1),
410 DCHECK(!cst.empty());
411 DCHECK(std::is_sorted(cst.begin(), cst.end(), CoeffComparator));
412 literals_.reserve(cst.size());
419 if (term.coefficient != prev) {
420 prev = term.coefficient;
424 coeffs_.reserve(
size);
425 starts_.reserve(
size + 1);
430 if (term.coefficient != prev) {
431 prev = term.coefficient;
432 coeffs_.push_back(term.coefficient);
433 starts_.push_back(literals_.size());
435 literals_.push_back(term.literal);
439 starts_.push_back(literals_.size());
441 hash_ = absl::Hash<std::vector<LiteralWithCoeff>>()(cst);
446 int literal_index = 0;
451 if (literal_index == starts_[coeff_index + 1]) ++coeff_index;
457 absl::Span<const LiteralWithCoeff> cst) {
458 if (cst.size() != literals_.size())
return false;
459 int literal_index = 0;
462 if (literals_[literal_index] != term.literal)
return false;
463 if (coeffs_[coeff_index] != term.coefficient)
return false;
465 if (literal_index == starts_[coeff_index + 1]) {
473 Coefficient rhs,
int trail_index, Coefficient* threshold,
Trail* trail,
479 Coefficient slack = rhs;
485 std::vector<Coefficient> sum_at_previous_level(last_level + 2,
488 int max_relevant_trail_index = 0;
489 if (trail_index > 0) {
490 int literal_index = 0;
493 const BooleanVariable
var =
literal.Variable();
494 const Coefficient coeff = coeffs_[coeff_index];
497 max_relevant_trail_index =
500 sum_at_previous_level[trail->
Info(
var).
level + 1] += coeff;
503 if (literal_index == starts_[coeff_index + 1]) ++coeff_index;
507 if (slack < 0)
return false;
510 for (
int i = 1;
i < sum_at_previous_level.size(); ++
i) {
511 sum_at_previous_level[
i] += sum_at_previous_level[
i - 1];
516 int literal_index = 0;
519 const BooleanVariable
var =
literal.Variable();
524 CHECK_LE(coeffs_[coeff_index], rhs_ - sum_at_previous_level[level])
525 <<
"var should have been propagated at an earlier level !";
528 if (literal_index == starts_[coeff_index + 1]) ++coeff_index;
538 index_ = coeffs_.size() - 1;
539 already_propagated_end_ = literals_.size();
540 Update(slack, threshold);
541 return *threshold < 0
542 ?
Propagate(max_relevant_trail_index, threshold, trail, helper)
547 int trail_index, Coefficient* threshold,
Trail* trail,
549 DCHECK_LT(*threshold, 0);
550 const Coefficient slack = GetSlackFromThreshold(*threshold);
551 DCHECK_GE(slack, 0) <<
"The constraint is already a conflict!";
552 while (index_ >= 0 && coeffs_[index_] > slack) --index_;
555 BooleanVariable first_propagated_variable(-1);
556 for (
int i = starts_[index_ + 1];
i < already_propagated_end_; ++
i) {
561 FillReason(*trail, trail_index, literals_[
i].Variable(),
563 helper->
conflict.push_back(literals_[
i].Negated());
564 Update(slack, threshold);
569 if (first_propagated_variable < 0) {
570 if (first_reason_trail_index_ == -1) {
571 first_reason_trail_index_ = trail->
Index();
573 helper->
Enqueue(literals_[
i].Negated(), trail_index,
this, trail);
574 first_propagated_variable = literals_[
i].Variable();
580 first_propagated_variable);
584 Update(slack, threshold);
585 DCHECK_GE(*threshold, 0);
590 const Trail& trail,
int source_trail_index,
591 BooleanVariable propagated_variable, std::vector<Literal>* reason) {
597 reason->push_back(trail[source_trail_index].Negated());
604 int last_coeff_index = 0;
610 Coefficient slack = rhs_;
611 Coefficient propagated_variable_coefficient(0);
612 int coeff_index = coeffs_.size() - 1;
613 for (
int i = literals_.size() - 1;
i >= 0; --
i) {
615 if (
literal.Variable() == propagated_variable) {
616 propagated_variable_coefficient = coeffs_[coeff_index];
621 reason->push_back(
literal.Negated());
623 last_coeff_index = coeff_index;
625 slack -= coeffs_[coeff_index];
628 if (
i == starts_[coeff_index]) {
632 DCHECK_GT(propagated_variable_coefficient, slack);
633 DCHECK_GE(propagated_variable_coefficient, 0);
636 if (reason->size() <= 1 || coeffs_.size() == 1)
return;
638 Coefficient limit = propagated_variable_coefficient - slack;
643 coeff_index = last_coeff_index;
644 if (coeffs_[coeff_index] >= limit)
return;
645 for (
int i = last_i;
i < literals_.size(); ++
i) {
647 if (
i == starts_[coeff_index + 1]) {
649 if (coeffs_[coeff_index] >= limit)
break;
651 if (
literal.Negated() != reason->back())
continue;
652 limit -= coeffs_[coeff_index];
654 if (coeffs_[coeff_index] >= limit)
break;
656 DCHECK(!reason->empty());
661 const Trail& trail,
int trail_index,
663 Coefficient result(0);
664 int literal_index = 0;
672 if (literal_index == starts_[coeff_index + 1]) ++coeff_index;
678 const Trail& trail, BooleanVariable
var,
680 Coefficient* conflict_slack) {
686 Coefficient var_coeff(0);
687 int literal_index = 0;
693 var_coeff = coeffs_[coeff_index];
699 if (literal_index == starts_[coeff_index + 1]) ++coeff_index;
720 DCHECK_EQ(*conflict_slack,
726 const Coefficient slack = rhs_ -
activity;
730 DCHECK_EQ(*conflict_slack,
736 const Coefficient cancelation =
745 const Coefficient min_coeffs = std::min(var_coeff, conflict_var_coeff);
746 const Coefficient new_slack_ub = slack + *conflict_slack - min_coeffs;
747 CHECK_LT(*conflict_slack, conflict_var_coeff);
748 CHECK_LT(slack, var_coeff);
749 if (new_slack_ub < 0) {
751 DCHECK_EQ(*conflict_slack + slack - cancelation,
766 Coefficient conflict_diff(0);
769 if (new_slack_ub < std::max(var_coeff, conflict_var_coeff) - min_coeffs) {
770 const Coefficient reduc = new_slack_ub + 1;
771 if (var_coeff < conflict_var_coeff) {
772 conflict_diff += reduc;
781 conflict_diff = *conflict_slack;
785 CHECK_GE(conflict_diff, 0);
786 CHECK_LE(conflict_diff, *conflict_slack);
787 if (conflict_diff > 0) {
788 conflict->
ReduceSlackTo(trail, limit_trail_index, *conflict_slack,
789 *conflict_slack - conflict_diff);
790 *conflict_slack -= conflict_diff;
796 CHECK_LE(diff, slack);
810 const Coefficient new_coeff = coeffs_[coeff_index] - diff;
818 if (literal_index == starts_[coeff_index + 1]) ++coeff_index;
827 const Coefficient slack = GetSlackFromThreshold(*threshold);
828 while (index_ + 1 < coeffs_.size() && coeffs_[index_ + 1] <= slack) ++index_;
829 Update(slack, threshold);
830 if (first_reason_trail_index_ >= trail_index) {
831 first_reason_trail_index_ = -1;
838 Coefficient rhs,
Trail* trail) {
840 DCHECK(!cst.empty());
841 DCHECK(std::is_sorted(cst.begin(), cst.end(), CoeffComparator));
844 if (constraints_.empty()) {
851 std::unique_ptr<UpperBoundedLinearConstraint> c(
853 std::vector<UpperBoundedLinearConstraint*>& duplicate_candidates =
854 possible_duplicates_[c->hash()];
858 if (candidate->HasIdenticalTerms(cst)) {
859 if (rhs < candidate->Rhs()) {
863 ConstraintIndex
i(0);
864 while (
i < constraints_.size() &&
865 constraints_[
i.value()].get() != candidate) {
868 CHECK_LT(
i, constraints_.size());
870 &thresholds_[
i], trail,
881 trail, &enqueue_helper_)) {
882 thresholds_.pop_back();
886 const ConstraintIndex cst_index(constraints_.size());
887 duplicate_candidates.push_back(c.get());
888 constraints_.emplace_back(c.release());
890 DCHECK_LT(term.literal.Index(), to_update_.size());
891 to_update_[term.literal].
push_back(ConstraintIndexWithCoeff(
893 cst_index, term.coefficient));
899 const std::vector<LiteralWithCoeff>& cst, Coefficient rhs,
Trail* trail) {
900 DeleteSomeLearnedConstraintIfNeeded();
901 const int old_num_constraints = constraints_.size();
906 if (result && constraints_.size() > old_num_constraints) {
907 constraints_.back()->set_is_learned(
true);
912bool PbConstraints::PropagateNext(
Trail* trail) {
920 bool conflict =
false;
921 num_threshold_updates_ += to_update_[true_literal].size();
922 for (ConstraintIndexWithCoeff& update : to_update_[true_literal]) {
923 const Coefficient threshold =
924 thresholds_[update.index] - update.coefficient;
925 thresholds_[update.index] = threshold;
926 if (threshold < 0 && !conflict) {
928 constraints_[update.index.value()].get();
929 update.need_untrail_inspection =
true;
930 ++num_constraint_lookups_;
932 if (!cst->
Propagate(source_trail_index, &thresholds_[update.index], trail,
935 conflicting_constraint_index_ = update.index;
941 num_inspected_constraint_literals_ +=
949 const int old_index = trail->
Index();
951 if (!PropagateNext(trail))
return false;
962 for (ConstraintIndexWithCoeff& update : to_update_[
literal]) {
963 thresholds_[update.index] += update.coefficient;
967 if (update.need_untrail_inspection) {
968 update.need_untrail_inspection =
false;
969 to_untrail_.
Set(update.index);
974 constraints_[cst_index.value()]->Untrail(&(thresholds_[cst_index]),
984 enqueue_helper_.
reasons[trail_index];
987 trail[trail_index].Variable(), reason);
992 int trail_index)
const {
994 enqueue_helper_.
reasons[trail_index];
1001void PbConstraints::ComputeNewLearnedConstraintLimit() {
1002 const int num_constraints = constraints_.size();
1003 target_number_of_learned_constraint_ =
1004 num_constraints + parameters_->pb_cleanup_increment();
1005 num_learned_constraint_before_cleanup_ =
1006 static_cast<int>(target_number_of_learned_constraint_ /
1007 parameters_->pb_cleanup_ratio()) -
1011void PbConstraints::DeleteSomeLearnedConstraintIfNeeded() {
1012 if (num_learned_constraint_before_cleanup_ == 0) {
1014 ComputeNewLearnedConstraintLimit();
1017 --num_learned_constraint_before_cleanup_;
1018 if (num_learned_constraint_before_cleanup_ > 0)
return;
1023 std::vector<double> activities;
1024 for (
int i = 0;
i < constraints_.size(); ++
i) {
1025 const UpperBoundedLinearConstraint& constraint = *(constraints_[
i].get());
1026 if (constraint.is_learned() && !constraint.is_used_as_a_reason()) {
1027 activities.push_back(constraint.activity());
1033 std::sort(activities.begin(), activities.end());
1034 const int num_constraints_to_delete =
1035 constraints_.size() - target_number_of_learned_constraint_;
1036 CHECK_GT(num_constraints_to_delete, 0);
1037 if (num_constraints_to_delete >= activities.size()) {
1040 for (
int i = 0;
i < constraints_.size(); ++
i) {
1041 UpperBoundedLinearConstraint& constraint = *(constraints_[
i].get());
1042 if (constraint.is_learned() && !constraint.is_used_as_a_reason()) {
1043 constraint.MarkForDeletion();
1047 const double limit_activity = activities[num_constraints_to_delete];
1048 int num_constraint_at_limit_activity = 0;
1049 for (
int i = num_constraints_to_delete;
i >= 0; --
i) {
1050 if (activities[
i] == limit_activity) {
1051 ++num_constraint_at_limit_activity;
1061 for (
int i = constraints_.size() - 1;
i >= 0; --
i) {
1062 UpperBoundedLinearConstraint& constraint = *(constraints_[
i].get());
1063 if (constraint.is_learned() && !constraint.is_used_as_a_reason()) {
1064 if (constraint.activity() <= limit_activity) {
1065 if (constraint.activity() == limit_activity &&
1066 num_constraint_at_limit_activity > 0) {
1067 --num_constraint_at_limit_activity;
1069 constraint.MarkForDeletion();
1077 DeleteConstraintMarkedForDeletion();
1078 ComputeNewLearnedConstraintLimit();
1083 const double max_activity = parameters_->max_clause_activity_value();
1085 constraint_activity_increment_);
1086 if (constraint->
activity() > max_activity) {
1092 constraint_activity_increment_ *= scaling_factor;
1093 for (
int i = 0;
i < constraints_.size(); ++
i) {
1094 constraints_[
i]->set_activity(constraints_[
i]->activity() * scaling_factor);
1099 const double decay = parameters_->clause_activity_decay();
1100 constraint_activity_increment_ *= 1.0 / decay;
1103void PbConstraints::DeleteConstraintMarkedForDeletion() {
1105 constraints_.size(), ConstraintIndex(-1));
1106 ConstraintIndex new_index(0);
1107 for (ConstraintIndex
i(0);
i < constraints_.size(); ++
i) {
1108 if (!constraints_[
i.value()]->is_marked_for_deletion()) {
1109 index_mapping[
i] = new_index;
1110 if (new_index <
i) {
1111 constraints_[new_index.value()] = std::move(constraints_[
i.value()]);
1112 thresholds_[new_index] = thresholds_[
i];
1117 UpperBoundedLinearConstraint* c = constraints_[
i.value()].get();
1118 std::vector<UpperBoundedLinearConstraint*>& ref =
1119 possible_duplicates_[c->hash()];
1120 for (
int i = 0;
i < ref.size(); ++
i) {
1122 std::swap(ref[
i], ref.back());
1129 constraints_.resize(new_index.value());
1130 thresholds_.
resize(new_index.value());
1134 for (LiteralIndex
lit(0);
lit < to_update_.size(); ++
lit) {
1135 std::vector<ConstraintIndexWithCoeff>& updates = to_update_[
lit];
1137 for (
int i = 0;
i < updates.size(); ++
i) {
1138 const ConstraintIndex m = index_mapping[updates[
i].index];
1140 updates[new_index] = updates[
i];
1141 updates[new_index].index = m;
1145 updates.
resize(new_index);
void ClearAndResize(IntegerType size)
const std::vector< IntegerType > & PositionsSetAtLeastOnce() const
void Set(IntegerType index)
bool AddLinearConstraint(bool use_lower_bound, Coefficient lower_bound, bool use_upper_bound, Coefficient upper_bound, std::vector< LiteralWithCoeff > *cst)
BooleanVariable Variable() const
std::string DebugString()
Returns a string representation of the constraint.
Coefficient ReduceCoefficientsAndComputeSlackForTrailPrefix(const Trail &trail, int trail_index)
Coefficient CancelationAmount(Literal literal, Coefficient coeff) const
Returns the "cancelation" amount of AddTerm(literal, coeff).
void ReduceCoefficients()
Coefficient GetCoefficient(BooleanVariable var) const
Returns the coefficient (>= 0) of the given variable.
Coefficient ComputeSlackForTrailPrefix(const Trail &trail, int trail_index) const
void AddToRhs(Coefficient value)
Adds a non-negative value to this constraint Rhs().
void CopyIntoVector(std::vector< LiteralWithCoeff > *output)
Copies this constraint into a vector<LiteralWithCoeff> representation.
const std::vector< BooleanVariable > & PossibleNonZeros() const
void ReduceSlackTo(const Trail &trail, int trail_index, Coefficient initial_slack, Coefficient target)
void AddTerm(Literal literal, Coefficient coeff)
void ClearAndResize(int num_variables)
Literal GetLiteral(BooleanVariable var) const
void UpdateActivityIncrement()
bool AddConstraint(const std::vector< LiteralWithCoeff > &cst, Coefficient rhs, Trail *trail)
bool Propagate(Trail *trail) final
UpperBoundedLinearConstraint * ReasonPbConstraint(int trail_index) const
absl::Span< const Literal > Reason(const Trail &trail, int trail_index, int64_t conflict_id) const final
void BumpActivity(UpperBoundedLinearConstraint *constraint)
bool AddLearnedConstraint(const std::vector< LiteralWithCoeff > &cst, Coefficient rhs, Trail *trail)
void RescaleActivities(double scaling_factor)
void Untrail(const Trail &trail, int trail_index) final
int propagation_trail_index_
int NumVariables() const
Getters.
std::vector< Literal > * MutableConflict()
void EnqueueWithSameReasonAs(Literal true_literal, BooleanVariable reference_var)
int CurrentDecisionLevel() const
const AssignmentInfo & Info(BooleanVariable var) const
std::vector< Literal > * GetEmptyVectorToStoreReason(int trail_index) const
const VariablesAssignment & Assignment() const
void ResolvePBConflict(const Trail &trail, BooleanVariable var, MutableUpperBoundedLinearConstraint *conflict, Coefficient *conflict_slack)
UpperBoundedLinearConstraint(const std::vector< LiteralWithCoeff > &cst)
Takes a pseudo-Boolean formula in canonical form.
Coefficient ComputeCancelation(const Trail &trail, int trail_index, const MutableUpperBoundedLinearConstraint &conflict)
bool Propagate(int trail_index, Coefficient *threshold, Trail *trail, PbConstraintsEnqueueHelper *helper)
void set_activity(double activity)
void AddToConflict(MutableUpperBoundedLinearConstraint *conflict)
void FillReason(const Trail &trail, int source_trail_index, BooleanVariable propagated_variable, std::vector< Literal > *reason)
void Untrail(Coefficient *threshold, int trail_index)
int already_propagated_end() const
bool HasIdenticalTerms(absl::Span< const LiteralWithCoeff > cst)
Returns true if the given terms are the same as the one in this constraint.
bool InitializeRhs(Coefficient rhs, int trail_index, Coefficient *threshold, Trail *trail, PbConstraintsEnqueueHelper *helper)
bool VariableIsAssigned(BooleanVariable var) const
Returns true iff the given variable is assigned.
bool LiteralIsFalse(Literal literal) const
bool LiteralIsTrue(Literal literal) const
void assign(size_type n, const value_type &val)
void push_back(const value_type &val)
void resize(size_type new_size)
void SimplifyCanonicalBooleanLinearConstraint(std::vector< LiteralWithCoeff > *cst, Coefficient *rhs)
bool ApplyLiteralMapping(const util_intops::StrongVector< LiteralIndex, LiteralIndex > &mapping, std::vector< LiteralWithCoeff > *cst, Coefficient *bound_shift, Coefficient *max_value)
Coefficient ComputeNegatedCanonicalRhs(Coefficient lower_bound, Coefficient bound_shift, Coefficient max_value)
const LiteralIndex kTrueLiteralIndex(-2)
bool BooleanLinearExpressionIsCanonical(absl::Span< const LiteralWithCoeff > cst)
Returns true iff the Boolean linear expression is in canonical form.
const LiteralIndex kFalseLiteralIndex(-3)
Coefficient ComputeCanonicalRhs(Coefficient upper_bound, Coefficient bound_shift, Coefficient max_value)
bool ComputeBooleanLinearExpressionCanonicalForm(std::vector< LiteralWithCoeff > *cst, Coefficient *bound_shift, Coefficient *max_value)
In SWIG mode, we don't want anything besides these top-level includes.
bool SafeAddInto(IntegerType a, IntegerType *b)
#define SCOPED_TIME_STAT(stats)
int32_t trail_index
The index of this assignment in the trail.
Represents a term in a pseudo-Boolean formula.
UpperBoundedLinearConstraint * pb_constraint
void Enqueue(Literal l, int source_trail_index, UpperBoundedLinearConstraint *ct, Trail *trail)
int propagator_id
The propagator id of PbConstraints.
std::vector< Literal > conflict
A temporary vector to store the last conflict.
std::vector< ReasonInfo > reasons