14#ifndef ORTOOLS_SAT_PB_CONSTRAINT_H_
15#define ORTOOLS_SAT_PB_CONSTRAINT_H_
26#include "absl/container/flat_hash_map.h"
27#include "absl/log/check.h"
28#include "absl/types/span.h"
49 std::numeric_limits<Coefficient::ValueType>::max());
92 std::vector<LiteralWithCoeff>* cst, Coefficient* bound_shift,
93 Coefficient* max_value);
107 std::vector<LiteralWithCoeff>* cst, Coefficient* bound_shift,
108 Coefficient* max_value);
118 Coefficient bound_shift, Coefficient max_value);
126 Coefficient bound_shift,
127 Coefficient max_value);
134 absl::Span<const Literal> enforcement_literals,
135 absl::Span<const LiteralWithCoeff> cst);
140 std::vector<LiteralWithCoeff>* cst, Coefficient* rhs);
170 bool use_upper_bound, Coefficient upper_bound,
171 std::vector<LiteralWithCoeff>* cst);
175 Coefficient
Rhs(
int i)
const {
return rhs_[
i]; }
177 return constraints_[
i];
181 bool AddConstraint(absl::Span<const LiteralWithCoeff> cst,
182 Coefficient max_value, Coefficient rhs);
184 std::vector<Coefficient> rhs_;
185 std::vector<std::vector<LiteralWithCoeff>> constraints_;
203 return AbsCoefficient(terms_[var]);
210 return Literal(var, terms_[var] > 0);
227 const Coefficient bound = max_sum_ - rhs_;
232 terms_[var] = (terms_[var] > 0) ? bound : -bound;
239 int trail_index)
const;
251 const Trail& trail,
int trail_index);
276 Coefficient initial_slack, Coefficient target);
286 Coefficient
Rhs()
const {
return rhs_; }
287 Coefficient
MaxSum()
const {
return max_sum_; }
293 const BooleanVariable var = literal.
Variable();
294 const Coefficient term_encoding = literal.
IsPositive() ? coeff : -coeff;
301 rhs_ -= std::min(coeff, AbsCoefficient(terms_[var]));
302 max_sum_ += AbsCoefficient(term_encoding + terms_[var]) -
303 AbsCoefficient(terms_[var]);
308 CHECK_GE(max_sum_, 0) <<
"Overflow";
309 terms_[var] += term_encoding;
316 const BooleanVariable var = literal.
Variable();
317 if (literal ==
GetLiteral(var))
return Coefficient(0);
318 return std::min(coeff, AbsCoefficient(terms_[var]));
324 return non_zeros_.PositionsSetAtLeastOnce();
331 Coefficient AbsCoefficient(Coefficient a)
const {
return a > 0 ? a : -a; }
334 Coefficient ComputeMaxSum()
const;
346 Coefficient max_sum_;
354class UpperBoundedLinearConstraint;
398 const std::vector<LiteralWithCoeff>& cst);
408 absl::Span<const Literal> enforcement_literals,
409 absl::Span<const LiteralWithCoeff> cst,
411 Coefficient
Rhs()
const {
return rhs_; }
420 absl::Span<const Literal> enforcement_literals,
421 Coefficient rhs,
int trail_index, Coefficient* threshold,
437 bool Propagate(
int trail_index, Coefficient* threshold,
Trail* trail,
439 absl::Span<const Literal> enforcement_literals,
441 bool* need_untrail_inspection =
nullptr);
447 void Untrail(Coefficient* threshold,
int trail_index);
466 absl::Span<const Literal> enforcement_literals,
467 BooleanVariable propagated_variable,
468 std::vector<std::tuple<int, int, int>>* temporary_tuples,
469 std::vector<Literal>* reason);
475 Coefficient* conflict_slack);
490 const Trail& trail,
int trail_index,
513 uint64_t
hash()
const {
return hash_; }
520 Coefficient GetSlackFromThreshold(Coefficient threshold)
const {
521 return (index_ < 0) ? threshold : coeffs_[index_] + threshold;
523 void Update(Coefficient slack, Coefficient* threshold) {
524 *threshold = (index_ < 0) ? slack : slack - coeffs_[index_];
525 already_propagated_end_ = starts_[index_ + 1];
530 bool is_marked_for_deletion_;
532 int first_reason_trail_index_;
537 int already_propagated_end_;
546 EnforcementId enforcement_id_;
547 std::vector<Coefficient> coeffs_;
548 std::vector<int> starts_;
549 std::vector<Literal> literals_;
562 conflicting_constraint_index_(-1),
563 num_learned_constraint_before_cleanup_(0),
564 constraint_activity_increment_(1.0),
566 stats_(
"PbConstraints"),
567 num_constraint_lookups_(0),
568 num_inspected_constraint_literals_(0),
569 num_threshold_updates_(0) {
578 LOG(INFO) << stats_.StatString();
579 LOG(INFO) <<
"num_constraint_lookups_: " << num_constraint_lookups_;
580 LOG(INFO) <<
"num_threshold_updates_: " << num_threshold_updates_;
585 void Untrail(
const Trail& trail,
int trail_index)
final;
586 absl::Span<const Literal>
Reason(
const Trail& trail,
int trail_index,
587 int64_t conflict_id)
const final;
594 if (!constraints_.empty()) {
595 to_update_.resize(num_variables << 1);
596 enqueue_helper_.reasons.resize(num_variables);
610 bool AddConstraint(
const std::vector<LiteralWithCoeff>& cst, Coefficient rhs,
614 bool AddConstraint(
const std::vector<Literal>& enforcement_literals,
615 const std::vector<LiteralWithCoeff>& cst, Coefficient rhs,
621 Coefficient rhs,
Trail* trail);
625 bool IsEmpty() const final {
return constraints_.empty(); }
634 if (conflicting_constraint_index_ == -1)
return nullptr;
635 return constraints_[conflicting_constraint_index_.value()].get();
650 constraints_[index]->MarkForDeletion();
651 DeleteConstraintMarkedForDeletion();
657 return num_inspected_constraint_literals_;
664 bool PropagateNext(
Trail* trail);
665 bool PropagateConstraint(ConstraintIndex index,
Trail* trail,
666 int source_trail_index,
667 bool* need_untrail_inspection =
nullptr);
671 void ComputeNewLearnedConstraintLimit();
672 void DeleteSomeLearnedConstraintIfNeeded();
677 void DeleteConstraintMarkedForDeletion();
686 struct ConstraintIndexWithCoeff {
687 ConstraintIndexWithCoeff() =
default;
688 ConstraintIndexWithCoeff(
bool n, ConstraintIndex
i, Coefficient c)
689 : need_untrail_inspection(n), index(
i), coefficient(c) {}
690 bool need_untrail_inspection;
691 ConstraintIndex index;
692 Coefficient coefficient;
696 std::vector<std::unique_ptr<UpperBoundedLinearConstraint>> constraints_;
708 SparseBitset<ConstraintIndex> enforcement_status_changed_;
711 SparseBitset<ConstraintIndex> to_untrail_;
715 absl::flat_hash_map<int64_t, std::vector<UpperBoundedLinearConstraint*>>
716 possible_duplicates_;
719 PbConstraintsEnqueueHelper enqueue_helper_;
721 EnforcementPropagator* enforcement_propagator_;
725 ConstraintIndex conflicting_constraint_index_;
728 int target_number_of_learned_constraint_;
729 int num_learned_constraint_before_cleanup_;
730 double constraint_activity_increment_;
733 SatParameters* parameters_;
736 mutable StatsGroup stats_;
737 int64_t num_constraint_lookups_;
738 int64_t num_inspected_constraint_literals_;
739 int64_t num_threshold_updates_;
761 first_variable_.resize(num_variables);
762 seen_.ClearAndResize(BooleanVariable(num_variables));
766 void Clear() { seen_.ResetAllToFalse(); }
772 if (seen_[var])
return first_variable_[var];
773 const BooleanVariable reference_var =
774 trail_.ReferenceVarWithSameReason(var);
775 if (reference_var == var)
return var;
776 if (seen_[reference_var])
return first_variable_[reference_var];
777 seen_.Set(reference_var);
778 first_variable_[reference_var] = var;
int NumConstraints() const
CanonicalBooleanLinearProblem & operator=(const CanonicalBooleanLinearProblem &)=delete
Coefficient Rhs(int i) const
const std::vector< LiteralWithCoeff > & Constraint(int i) const
CanonicalBooleanLinearProblem()=default
CanonicalBooleanLinearProblem(const CanonicalBooleanLinearProblem &)=delete
bool AddLinearConstraint(bool use_lower_bound, Coefficient lower_bound, bool use_upper_bound, Coefficient upper_bound, std::vector< LiteralWithCoeff > *cst)
std::string DebugString() const
LiteralIndex Index() const
BooleanVariable Variable() const
Coefficient MaxSum() 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 ReduceGivenCoefficient(BooleanVariable var)
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
PbConstraints & operator=(const PbConstraints &)=delete
int64_t num_constraint_lookups() const
void Resize(int num_variables)
bool IsEmpty() const final
PbConstraints(const PbConstraints &)=delete
void ClearConflictingConstraint()
PbConstraints(Model *model)
~PbConstraints() override
int NumberOfConstraints() const
UpperBoundedLinearConstraint * ReasonPbConstraint(int trail_index) const
absl::Span< const Literal > Reason(const Trail &trail, int trail_index, int64_t conflict_id) const final
int64_t num_inspected_constraint_literals() const
void BumpActivity(UpperBoundedLinearConstraint *constraint)
bool AddLearnedConstraint(const std::vector< LiteralWithCoeff > &cst, Coefficient rhs, Trail *trail)
int64_t num_threshold_updates() const
void RescaleActivities(double scaling_factor)
void DeleteConstraint(int index)
UpperBoundedLinearConstraint * ConflictingConstraint()
void Untrail(const Trail &trail, int trail_index) final
SatPropagator(const std::string &name)
void Enqueue(Literal true_literal, int propagator_id)
void RegisterPropagator(SatPropagator *propagator)
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)
bool is_marked_for_deletion() const
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)
bool is_used_as_a_reason() const
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)
void set_is_learned(bool is_learned)
void set_enforcement_id(EnforcementId enforcement_id)
BooleanVariable FirstVariableWithSameReason(BooleanVariable var)
VariableWithSameReasonIdentifier(const VariableWithSameReasonIdentifier &)=delete
VariableWithSameReasonIdentifier & operator=(const VariableWithSameReasonIdentifier &)=delete
void Resize(int num_variables)
VariableWithSameReasonIdentifier(const Trail &trail)
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)
std::ostream & operator<<(std::ostream &os, const BoolVar &var)
Coefficient ComputeCanonicalRhs(Coefficient upper_bound, Coefficient bound_shift, Coefficient max_value)
H AbslHashValue(H h, const IntVar &i)
const Coefficient kCoefficientMax(std::numeric_limits< Coefficient::ValueType >::max())
bool ComputeBooleanLinearExpressionCanonicalForm(std::vector< LiteralWithCoeff > *cst, Coefficient *bound_shift, Coefficient *max_value)
#define IF_STATS_ENABLED(instructions)
#define DEFINE_STRONG_INT64_TYPE(integer_type_name)
#define DEFINE_STRONG_INDEX_TYPE(index_type_name)
LiteralWithCoeff()=default
LiteralWithCoeff(Literal l, Coefficient c)
bool operator==(const LiteralWithCoeff &other) const
LiteralWithCoeff(Literal l, int64_t c)
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
std::vector< ReasonInfo > reasons