25#include "absl/container/flat_hash_map.h"
26#include "absl/hash/hash.h"
27#include "absl/log/check.h"
28#include "absl/strings/str_format.h"
29#include "absl/types/span.h"
46 return a.literal.Index() <
b.literal.Index();
50 if (a.coefficient ==
b.coefficient) {
51 return a.literal.Index() <
b.literal.Index();
53 return a.coefficient <
b.coefficient;
59 std::vector<LiteralWithCoeff>* cst, Coefficient* bound_shift,
60 Coefficient* max_value) {
68 std::sort(cst->begin(), cst->end(), LiteralComparator);
71 for (
int i = 0;
i < cst->size(); ++
i) {
74 if (representative !=
nullptr &&
89 if (representative !=
nullptr && representative->
coefficient == 0) {
92 (*cst)[index] = current;
93 representative = &((*cst)[index]);
97 if (representative !=
nullptr && representative->
coefficient == 0) {
104 for (
int i = 0;
i < cst->size(); ++
i) {
111 if (!
SafeAddInto((*cst)[
i].coefficient, max_value))
return false;
115 std::sort(cst->begin(), cst->end(), CoeffComparator);
116 DCHECK_GE(*max_value, 0);
122 std::vector<LiteralWithCoeff>* cst, Coefficient* bound_shift,
123 Coefficient* max_value) {
125 Coefficient shift_due_to_fixed_variables(0);
127 if (mapping[entry.literal] >= 0) {
132 if (!
SafeAddInto(-entry.coefficient, &shift_due_to_fixed_variables)) {
142 *bound_shift = shift_due_to_fixed_variables;
148 if (!
SafeAddInto(shift_due_to_fixed_variables, bound_shift))
return false;
154 absl::Span<const Literal> enforcement_literals,
155 absl::Span<const LiteralWithCoeff> cst) {
156 if (!std::is_sorted(enforcement_literals.begin(),
157 enforcement_literals.end())) {
160 Coefficient previous(1);
162 if (term.coefficient < previous)
return false;
163 previous = term.coefficient;
171 std::vector<LiteralWithCoeff>* cst, Coefficient* rhs) {
178 if (x.coefficient > *rhs) x.coefficient = *rhs + 1;
183 Coefficient bound_shift,
184 Coefficient max_value) {
185 Coefficient rhs = upper_bound;
187 if (bound_shift > 0) {
193 return Coefficient(-1);
196 if (rhs < 0)
return Coefficient(-1);
197 return std::min(max_value, rhs);
201 Coefficient bound_shift,
202 Coefficient max_value) {
205 Coefficient shifted_lb = lower_bound;
207 if (bound_shift > 0) {
209 return Coefficient(-1);
215 if (shifted_lb <= 0) {
220 return max_value - shifted_lb;
224 bool use_lower_bound, Coefficient lower_bound,
bool use_upper_bound,
225 Coefficient upper_bound, std::vector<LiteralWithCoeff>* cst) {
227 Coefficient bound_shift;
228 Coefficient max_value;
233 if (use_upper_bound) {
234 const Coefficient rhs =
236 if (!AddConstraint(*cst, max_value, rhs))
return false;
238 if (use_lower_bound) {
240 for (
int i = 0;
i < cst->size(); ++
i) {
241 (*cst)[
i].literal = (*cst)[
i].literal.Negated();
243 const Coefficient rhs =
245 if (!AddConstraint(*cst, max_value, rhs))
return false;
250bool CanonicalBooleanLinearProblem::AddConstraint(
251 absl::Span<const LiteralWithCoeff> cst, Coefficient max_value,
253 if (rhs < 0)
return false;
254 if (rhs >= max_value)
return true;
255 constraints_.emplace_back(cst.begin(), cst.end());
262 if (terms_.size() != num_variables) {
263 terms_.assign(num_variables, Coefficient(0));
264 non_zeros_.ClearAndResize(BooleanVariable(num_variables));
274 for (BooleanVariable var : non_zeros_.PositionsSetAtLeastOnce()) {
275 terms_[var] = Coefficient(0);
277 non_zeros_.ResetAllToFalse();
284 CHECK_LT(rhs_, max_sum_) <<
"Trivially sat.";
285 Coefficient removed_sum(0);
286 const Coefficient bound = max_sum_ - rhs_;
291 terms_[var] = (terms_[var] > 0) ? bound : -bound;
295 max_sum_ -= removed_sum;
296 DCHECK_EQ(max_sum_, ComputeMaxSum());
302 if (!result.empty()) result +=
" + ";
306 result += absl::StrFormat(
" <= %d", rhs_.value());
313 const Trail& trail,
int trail_index)
const {
314 Coefficient activity(0);
322 return rhs_ - activity;
328 Coefficient activity(0);
329 Coefficient removed_sum(0);
330 const Coefficient bound = max_sum_ - rhs_;
338 terms_[var] = (terms_[var] > 0) ? bound : -bound;
350 max_sum_ -= removed_sum;
351 DCHECK_EQ(max_sum_, ComputeMaxSum());
352 return rhs_ - activity;
356 const Trail& trail,
int trail_index, Coefficient initial_slack,
357 Coefficient target) {
359 const Coefficient slack = initial_slack;
361 CHECK_LE(target, slack);
367 CHECK_LT(slack, coeff);
370 if (slack == target)
return;
373 const Coefficient diff = slack - target;
382 terms_[var] = (terms_[var] > 0) ? terms_[var] - diff : terms_[var] + diff;
389 DCHECK_EQ(max_sum_, ComputeMaxSum());
393 std::vector<LiteralWithCoeff>* output) {
395 for (BooleanVariable var : non_zeros_.PositionsSetAtLeastOnce()) {
401 std::sort(output->begin(), output->end(), CoeffComparator);
404Coefficient MutableUpperBoundedLinearConstraint::ComputeMaxSum()
const {
405 Coefficient result(0);
413 const std::vector<Literal>& enforcement_literals,
414 const std::vector<LiteralWithCoeff>& cst)
415 : is_marked_for_deletion_(false),
417 first_reason_trail_index_(-1),
419 enforcement_id_(-1) {
420 DCHECK(!cst.empty());
422 std::is_sorted(enforcement_literals.begin(), enforcement_literals.end()));
423 DCHECK(std::is_sorted(cst.begin(), cst.end(), CoeffComparator));
424 literals_.reserve(cst.size());
431 if (term.coefficient != prev) {
432 prev = term.coefficient;
436 coeffs_.reserve(size);
437 starts_.reserve(size + 1);
442 if (term.coefficient != prev) {
443 prev = term.coefficient;
444 coeffs_.push_back(term.coefficient);
445 starts_.push_back(literals_.size());
447 literals_.push_back(term.literal);
451 starts_.push_back(literals_.size());
454 std::pair<std::vector<Literal>, std::vector<LiteralWithCoeff>>>()(
455 {enforcement_literals, cst});
460 CHECK_LT(enforcement_id_, 0) <<
"Enforcement literals are not supported";
461 int literal_index = 0;
463 for (
Literal literal : literals_) {
464 conflict->
AddTerm(literal, coeffs_[coeff_index]);
466 if (literal_index == starts_[coeff_index + 1]) ++coeff_index;
472 absl::Span<const Literal> enforcement_literals,
473 absl::Span<const LiteralWithCoeff> cst,
475 if (enforcement_literals !=
479 if (cst.size() != literals_.size())
return false;
480 int literal_index = 0;
483 if (literals_[literal_index] != term.literal)
return false;
484 if (coeffs_[coeff_index] != term.coefficient)
return false;
486 if (literal_index == starts_[coeff_index + 1]) {
495 absl::Span<const Literal> enforcement_literals, Coefficient rhs,
496 int trail_index, Coefficient* threshold,
Trail* trail,
502 Coefficient slack = rhs;
508 std::vector<Coefficient> sum_at_previous_level(last_level + 2,
511 int max_relevant_trail_index = 0;
512 if (trail_index > 0) {
513 int literal_index = 0;
515 for (
Literal literal : literals_) {
516 const BooleanVariable var = literal.Variable();
517 const Coefficient coeff = coeffs_[coeff_index];
520 max_relevant_trail_index =
523 sum_at_previous_level[trail->
Info(var).
level + 1] += coeff;
526 if (literal_index == starts_[coeff_index + 1]) ++coeff_index;
530 if (slack < 0 && enforcement_literals.empty()) {
535 for (
int i = 1;
i < sum_at_previous_level.size(); ++
i) {
536 sum_at_previous_level[
i] += sum_at_previous_level[
i - 1];
541 int literal_index = 0;
543 for (
Literal literal : literals_) {
544 const BooleanVariable var = literal.Variable();
549 CHECK_LE(coeffs_[coeff_index], rhs_ - sum_at_previous_level[level])
550 <<
"var should have been propagated at an earlier level !";
553 if (literal_index == starts_[coeff_index + 1]) ++coeff_index;
563 index_ = coeffs_.size() - 1;
564 already_propagated_end_ = literals_.size();
565 Update(slack, threshold);
571 return Propagate(max_relevant_trail_index, threshold, trail,
572 enforcement_status, enforcement_literals, helper);
576 int trail_index, Coefficient* threshold,
Trail* trail,
578 absl::Span<const Literal> enforcement_literals,
580 DCHECK_LT(*threshold, 0);
583 const Coefficient slack = GetSlackFromThreshold(*threshold);
588 DCHECK(!enforcement_literals.empty());
591 for (
const Literal literal : enforcement_literals) {
593 helper->
Enqueue(literal.Negated(), trail_index,
this, trail);
600 FillReason(*trail, trail_index, enforcement_literals,
607 while (index_ >= 0 && coeffs_[index_] > slack) --index_;
608 if (need_untrail_inspection !=
nullptr) {
609 *need_untrail_inspection =
true;
613 BooleanVariable first_propagated_variable(-1);
614 for (
int i = starts_[index_ + 1];
i < already_propagated_end_; ++
i) {
617 const int literal_trail_index =
619 if (literal_trail_index > trail_index) {
622 FillReason(*trail, trail_index, enforcement_literals,
625 helper->
conflict.push_back(literals_[
i].Negated());
626 Update(slack, threshold);
630 for (
const Literal literal : enforcement_literals) {
632 helper->
Enqueue(literal.Negated(), literal_trail_index,
this,
637 Update(slack, threshold);
643 if (first_propagated_variable < 0) {
644 if (first_reason_trail_index_ == -1) {
645 first_reason_trail_index_ = trail->
Index();
647 helper->
Enqueue(literals_[
i].Negated(), trail_index,
this, trail);
648 first_propagated_variable = literals_[
i].Variable();
654 first_propagated_variable);
658 Update(slack, threshold);
659 DCHECK_GE(*threshold, 0);
664 const Trail& trail,
int source_trail_index,
665 absl::Span<const Literal> enforcement_literals,
666 BooleanVariable propagated_variable,
667 std::vector<std::tuple<int, int, int>>* temporary_tuples,
668 std::vector<Literal>* reason) {
669 bool enforcement_propagation =
false;
671 for (
const Literal literal : enforcement_literals) {
673 reason->push_back(literal.Negated());
674 }
else if (literal.Variable() == propagated_variable) {
675 enforcement_propagation =
true;
683 const bool add_extra_literal_reason =
688 if (rhs_ == 1 && !add_extra_literal_reason) {
689 reason->push_back(trail[source_trail_index].Negated());
696 std::vector<std::tuple<int, int, int>>& true_literals = *temporary_tuples;
697 true_literals.clear();
698 Coefficient propagated_variable_coefficient(0);
700 int literal_index = 0;
702 for (
Literal literal : literals_) {
703 if (literal.Variable() == propagated_variable) {
704 propagated_variable_coefficient = coeffs_[coeff_index];
709 literal_index, coeff_index});
712 if (literal_index == starts_[coeff_index + 1]) ++coeff_index;
714 std::sort(true_literals.begin(), true_literals.end());
721 Coefficient slack = rhs_;
723 for (
int i = 0;
i < true_literals.size(); ++
i) {
724 auto [trail_index, literal_index, coeff_index] = true_literals[
i];
725 const Literal literal = literals_[literal_index];
726 const Coefficient coeff = coeffs_[coeff_index];
728 propagated_variable_coefficient = coeff;
729 if (add_extra_literal_reason) {
730 reason->push_back(literal.
Negated());
735 true_literals[new_size++] = {trail_index, literal_index, coeff_index};
737 slack -= coeff.value();
739 true_literals.resize(new_size);
740 DCHECK_GT(propagated_variable_coefficient, slack);
741 DCHECK_GE(propagated_variable_coefficient, 0);
744 if (true_literals.size() <= 1 || coeffs_.size() == 1) {
745 for (
const auto& [unused1, literal_index, unused2] : true_literals) {
746 reason->push_back(literals_[literal_index].Negated());
753 Coefficient limit = propagated_variable_coefficient - slack;
755 for (
int i = true_literals.size() - 1;
i >= 0; --
i) {
756 const auto [_, literal_index, coeff_index] = true_literals[
i];
757 const Coefficient coeff = coeffs_[coeff_index];
759 limit -= coeff.value();
761 reason->push_back(literals_[literal_index].Negated());
768 const Trail& trail,
int trail_index,
770 Coefficient result(0);
771 int literal_index = 0;
773 for (
Literal literal : literals_) {
779 if (literal_index == starts_[coeff_index + 1]) ++coeff_index;
785 const Trail& trail, BooleanVariable var,
787 Coefficient* conflict_slack) {
788 CHECK_LT(enforcement_id_, 0) <<
"Enforcement literals are not supported";
794 Coefficient var_coeff(0);
795 int literal_index = 0;
797 for (
Literal literal : literals_) {
798 if (literal.Variable() == var) {
801 var_coeff = coeffs_[coeff_index];
807 if (literal_index == starts_[coeff_index + 1]) ++coeff_index;
828 DCHECK_EQ(*conflict_slack,
834 const Coefficient slack = rhs_ -
activity;
838 DCHECK_EQ(*conflict_slack,
844 const Coefficient cancelation =
852 const Coefficient conflict_var_coeff = conflict->
GetCoefficient(var);
853 const Coefficient min_coeffs = std::min(var_coeff, conflict_var_coeff);
854 const Coefficient new_slack_ub = slack + *conflict_slack - min_coeffs;
855 CHECK_LT(*conflict_slack, conflict_var_coeff);
856 CHECK_LT(slack, var_coeff);
857 if (new_slack_ub < 0) {
859 DCHECK_EQ(*conflict_slack + slack - cancelation,
874 Coefficient conflict_diff(0);
877 if (new_slack_ub < std::max(var_coeff, conflict_var_coeff) - min_coeffs) {
878 const Coefficient reduc = new_slack_ub + 1;
879 if (var_coeff < conflict_var_coeff) {
880 conflict_diff += reduc;
889 conflict_diff = *conflict_slack;
893 CHECK_GE(conflict_diff, 0);
894 CHECK_LE(conflict_diff, *conflict_slack);
895 if (conflict_diff > 0) {
896 conflict->
ReduceSlackTo(trail, limit_trail_index, *conflict_slack,
897 *conflict_slack - conflict_diff);
898 *conflict_slack -= conflict_diff;
904 CHECK_LE(diff, slack);
913 for (
Literal literal : literals_) {
916 conflict->
AddTerm(literal, coeffs_[coeff_index]);
918 const Coefficient new_coeff = coeffs_[coeff_index] - diff;
922 conflict->
AddTerm(literal, new_coeff);
926 if (literal_index == starts_[coeff_index + 1]) ++coeff_index;
935 const Coefficient slack = GetSlackFromThreshold(*threshold);
936 while (index_ + 1 < coeffs_.size() && coeffs_[index_ + 1] <= slack) ++index_;
937 Update(slack, threshold);
938 if (first_reason_trail_index_ >= trail_index) {
939 first_reason_trail_index_ = -1;
946 const std::vector<Literal>& enforcement_literals,
947 const std::vector<LiteralWithCoeff>& cst, Coefficient rhs,
Trail* trail) {
949 DCHECK(!cst.empty());
951 std::is_sorted(enforcement_literals.begin(), enforcement_literals.end()));
952 DCHECK(std::is_sorted(cst.begin(), cst.end(), CoeffComparator));
955 if (constraints_.empty()) {
962 std::unique_ptr<UpperBoundedLinearConstraint> c(
964 std::vector<UpperBoundedLinearConstraint*>& duplicate_candidates =
965 possible_duplicates_[c->hash()];
969 if (candidate->HasIdenticalTermsAndEnforcement(enforcement_literals, cst,
970 enforcement_propagator_)) {
971 if (rhs < candidate->Rhs()) {
975 ConstraintIndex
i(0);
976 while (
i < constraints_.size() &&
977 constraints_[
i.value()].get() != candidate) {
980 CHECK_LT(
i, constraints_.size());
981 return candidate->InitializeRhs(
982 enforcement_propagator_->Status(candidate->enforcement_id()),
984 &thresholds_[
i], trail, &enqueue_helper_);
992 thresholds_.push_back(Coefficient(0));
994 enforcement_propagator_->Status(enforcement_literals);
995 if (!c->InitializeRhs(enforcement_status, enforcement_literals, rhs,
998 thresholds_.pop_back();
1002 const ConstraintIndex cst_index(constraints_.size());
1003 enforcement_status_changed_.Resize(cst_index + 1);
1004 if (!enforcement_literals.empty()) {
1005 c->set_enforcement_id(enforcement_propagator_->Register(
1006 enforcement_literals,
1008 if (status == EnforcementStatus::IS_ENFORCED ||
1009 status == EnforcementStatus::CAN_PROPAGATE_ENFORCEMENT) {
1010 enforcement_status_changed_.Set(cst_index);
1014 duplicate_candidates.push_back(c.get());
1015 constraints_.emplace_back(c.release());
1017 DCHECK_LT(term.literal.Index(), to_update_.size());
1018 to_update_[term.literal].push_back(ConstraintIndexWithCoeff(
1019 trail->Assignment().VariableIsAssigned(term.literal.Variable()),
1020 cst_index, term.coefficient));
1026 const std::vector<LiteralWithCoeff>& cst, Coefficient rhs,
Trail* trail) {
1027 DeleteSomeLearnedConstraintIfNeeded();
1028 const int old_num_constraints = constraints_.size();
1034 if (result && constraints_.size() > old_num_constraints) {
1035 constraints_.back()->set_is_learned(
true);
1040bool PbConstraints::PropagateConstraint(ConstraintIndex index,
Trail* trail,
1041 int source_trail_index,
1042 bool* need_untrail_inspection) {
1050 bool conflict =
false;
1051 ++num_constraint_lookups_;
1053 if (!cst->
Propagate(source_trail_index, &thresholds_[index], trail,
1055 enforcement_propagator_->GetEnforcementLiterals(
1057 &enqueue_helper_, need_untrail_inspection)) {
1059 conflicting_constraint_index_ = index;
1063 BumpActivity(constraints_[index.value()].get());
1065 num_inspected_constraint_literals_ +=
1070bool PbConstraints::PropagateNext(
Trail* trail) {
1072 const int source_trail_index = propagation_trail_index_;
1073 const Literal true_literal = (*trail)[propagation_trail_index_];
1074 ++propagation_trail_index_;
1078 bool conflict =
false;
1079 num_threshold_updates_ += to_update_[true_literal].size();
1080 for (ConstraintIndexWithCoeff& update : to_update_[true_literal]) {
1082 thresholds_[update.index] - update.coefficient;
1083 thresholds_[update.index] = threshold;
1084 if (threshold < 0 && !conflict) {
1085 conflict = !PropagateConstraint(update.index, trail, source_trail_index,
1086 &update.need_untrail_inspection);
1093 for (
const ConstraintIndex index :
1094 enforcement_status_changed_.PositionsSetAtLeastOnce()) {
1095 if (thresholds_[index] < 0 &&
1097 enforcement_status_changed_.ResetAllToFalse();
1101 enforcement_status_changed_.ResetAllToFalse();
1103 const int old_index = trail->
Index();
1105 if (!PropagateNext(trail))
return false;
1112 to_untrail_.ClearAndResize(ConstraintIndex(constraints_.size()));
1116 for (ConstraintIndexWithCoeff& update : to_update_[literal]) {
1117 thresholds_[update.index] += update.coefficient;
1121 if (update.need_untrail_inspection) {
1122 update.need_untrail_inspection =
false;
1123 to_untrail_.Set(update.index);
1127 for (ConstraintIndex cst_index : to_untrail_.PositionsSetAtLeastOnce()) {
1128 constraints_[cst_index.value()]->Untrail(&(thresholds_[cst_index]),
1138 enqueue_helper_.reasons[trail_index];
1142 enforcement_propagator_->GetEnforcementLiterals(
1144 trail[trail_index].Variable(), &enqueue_helper_.temporary_tuples, reason);
1149 int trail_index)
const {
1151 enqueue_helper_.reasons[trail_index];
1158void PbConstraints::ComputeNewLearnedConstraintLimit() {
1159 const int num_constraints = constraints_.size();
1160 target_number_of_learned_constraint_ =
1161 num_constraints + parameters_->pb_cleanup_increment();
1162 num_learned_constraint_before_cleanup_ =
1163 static_cast<int>(target_number_of_learned_constraint_ /
1164 parameters_->pb_cleanup_ratio()) -
1168void PbConstraints::DeleteSomeLearnedConstraintIfNeeded() {
1169 if (num_learned_constraint_before_cleanup_ == 0) {
1171 ComputeNewLearnedConstraintLimit();
1174 --num_learned_constraint_before_cleanup_;
1175 if (num_learned_constraint_before_cleanup_ > 0)
return;
1180 std::vector<double> activities;
1181 for (
int i = 0; i < constraints_.size(); ++i) {
1182 const UpperBoundedLinearConstraint& constraint = *(constraints_[i].get());
1183 CHECK_LT(constraint.enforcement_id(), 0)
1184 <<
"Enforcement literals are not supported";
1185 if (constraint.is_learned() && !constraint.is_used_as_a_reason()) {
1186 activities.push_back(constraint.activity());
1192 std::sort(activities.begin(), activities.end());
1193 const int num_constraints_to_delete =
1194 constraints_.size() - target_number_of_learned_constraint_;
1195 CHECK_GT(num_constraints_to_delete, 0);
1196 if (num_constraints_to_delete >= activities.size()) {
1199 for (
int i = 0;
i < constraints_.size(); ++
i) {
1200 UpperBoundedLinearConstraint& constraint = *(constraints_[
i].get());
1201 if (constraint.is_learned() && !constraint.is_used_as_a_reason()) {
1202 constraint.MarkForDeletion();
1206 const double limit_activity = activities[num_constraints_to_delete];
1207 int num_constraint_at_limit_activity = 0;
1208 for (
int i = num_constraints_to_delete;
i >= 0; --
i) {
1209 if (activities[i] == limit_activity) {
1210 ++num_constraint_at_limit_activity;
1220 for (
int i = constraints_.size() - 1; i >= 0; --i) {
1221 UpperBoundedLinearConstraint& constraint = *(constraints_[
i].get());
1222 if (constraint.is_learned() && !constraint.is_used_as_a_reason()) {
1223 if (constraint.activity() <= limit_activity) {
1224 if (constraint.activity() == limit_activity &&
1225 num_constraint_at_limit_activity > 0) {
1226 --num_constraint_at_limit_activity;
1228 constraint.MarkForDeletion();
1236 DeleteConstraintMarkedForDeletion();
1237 ComputeNewLearnedConstraintLimit();
1242 const double max_activity = parameters_->max_clause_activity_value();
1244 constraint_activity_increment_);
1245 if (constraint->
activity() > max_activity) {
1251 constraint_activity_increment_ *= scaling_factor;
1252 for (
int i = 0;
i < constraints_.size(); ++
i) {
1253 constraints_[
i]->set_activity(constraints_[
i]->activity() * scaling_factor);
1258 const double decay = parameters_->clause_activity_decay();
1259 constraint_activity_increment_ *= 1.0 / decay;
1262void PbConstraints::DeleteConstraintMarkedForDeletion() {
1264 constraints_.size(), ConstraintIndex(-1));
1265 ConstraintIndex new_index(0);
1266 for (ConstraintIndex
i(0);
i < constraints_.size(); ++
i) {
1267 if (!constraints_[
i.value()]->is_marked_for_deletion()) {
1268 index_mapping[
i] = new_index;
1269 if (new_index <
i) {
1270 constraints_[new_index.value()] = std::move(constraints_[
i.value()]);
1271 thresholds_[new_index] = thresholds_[
i];
1276 UpperBoundedLinearConstraint* c = constraints_[i.value()].get();
1279 CHECK_LT(c->enforcement_id(), 0);
1280 std::vector<UpperBoundedLinearConstraint*>& ref =
1281 possible_duplicates_[c->hash()];
1282 for (
int i = 0; i < ref.size(); ++i) {
1284 std::swap(ref[i], ref.back());
1291 constraints_.resize(new_index.value());
1292 thresholds_.resize(new_index.value());
1296 for (LiteralIndex lit(0); lit < to_update_.size(); ++lit) {
1297 std::vector<ConstraintIndexWithCoeff>& updates = to_update_[lit];
1299 for (
int i = 0;
i < updates.size(); ++
i) {
1300 const ConstraintIndex m = index_mapping[updates[
i].index];
1302 updates[new_index] = updates[
i];
1303 updates[new_index].index = m;
1307 updates.resize(new_index);
const std::vector< IntegerType > & PositionsSetAtLeastOnce() const
bool AddLinearConstraint(bool use_lower_bound, Coefficient lower_bound, bool use_upper_bound, Coefficient upper_bound, std::vector< LiteralWithCoeff > *cst)
absl::Span< const Literal > GetEnforcementLiterals(EnforcementId id) const
BooleanVariable Variable() const
std::string DebugString()
Coefficient ReduceCoefficientsAndComputeSlackForTrailPrefix(const Trail &trail, int trail_index)
Coefficient CancelationAmount(Literal literal, Coefficient coeff) const
void ReduceCoefficients()
Coefficient GetCoefficient(BooleanVariable var) const
Coefficient ComputeSlackForTrailPrefix(const Trail &trail, int trail_index) const
void AddToRhs(Coefficient value)
void CopyIntoVector(std::vector< LiteralWithCoeff > *output)
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_
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)
Coefficient ComputeCancelation(const Trail &trail, int trail_index, const MutableUpperBoundedLinearConstraint &conflict)
void set_activity(double activity)
void AddToConflict(MutableUpperBoundedLinearConstraint *conflict)
void Untrail(Coefficient *threshold, int trail_index)
int already_propagated_end() const
EnforcementId enforcement_id() const
bool Propagate(int trail_index, Coefficient *threshold, Trail *trail, EnforcementStatus enforcement_status, absl::Span< const Literal > enforcement_literals, PbConstraintsEnqueueHelper *helper, bool *need_untrail_inspection=nullptr)
UpperBoundedLinearConstraint(const std::vector< Literal > &enforcement_literals, const std::vector< LiteralWithCoeff > &cst)
void FillReason(const Trail &trail, int source_trail_index, absl::Span< const Literal > enforcement_literals, BooleanVariable propagated_variable, std::vector< std::tuple< int, int, int > > *temporary_tuples, std::vector< Literal > *reason)
bool HasIdenticalTermsAndEnforcement(absl::Span< const Literal > enforcement_literals, absl::Span< const LiteralWithCoeff > cst, EnforcementPropagator *enforcement_propagator)
bool InitializeRhs(EnforcementStatus enforcement_status, absl::Span< const Literal > enforcement_literals, Coefficient rhs, int trail_index, Coefficient *threshold, Trail *trail, PbConstraintsEnqueueHelper *helper)
bool VariableIsAssigned(BooleanVariable var) const
bool LiteralIsAssigned(Literal literal) const
bool LiteralIsFalse(Literal literal) const
bool LiteralIsTrue(Literal literal) const
std::tuple< int64_t, int64_t, const double > Coefficient
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)
bool BooleanLinearExpressionIsCanonical(absl::Span< const Literal > enforcement_literals, absl::Span< const LiteralWithCoeff > cst)
const LiteralIndex kTrueLiteralIndex(-2)
const LiteralIndex kFalseLiteralIndex(-3)
@ CAN_PROPAGATE_ENFORCEMENT
Coefficient ComputeCanonicalRhs(Coefficient upper_bound, Coefficient bound_shift, Coefficient max_value)
const BooleanVariable kNoBooleanVariable(-1)
bool ComputeBooleanLinearExpressionCanonicalForm(std::vector< LiteralWithCoeff > *cst, Coefficient *bound_shift, Coefficient *max_value)
bool SafeAddInto(IntegerType a, IntegerType *b)
#define SCOPED_TIME_STAT(stats)
UpperBoundedLinearConstraint * pb_constraint
void Enqueue(Literal l, int source_trail_index, UpperBoundedLinearConstraint *ct, Trail *trail)
std::vector< std::tuple< int, int, int > > temporary_tuples
std::vector< Literal > conflict