14#ifndef ORTOOLS_SAT_PRECEDENCES_H_
15#define ORTOOLS_SAT_PRECEDENCES_H_
24#include "absl/container/btree_set.h"
25#include "absl/container/flat_hash_map.h"
26#include "absl/container/flat_hash_set.h"
27#include "absl/container/inlined_vector.h"
28#include "absl/log/check.h"
29#include "absl/strings/str_format.h"
30#include "absl/types/span.h"
87inline LinearExpression2Index
NegationOf(LinearExpression2Index
i) {
88 return LinearExpression2Index(
i.value() ^ 1);
92 return (
i.value() & 1) == 0;
96 return LinearExpression2Index(
i.value() & (~1));
130 IntegerVariable var)
const;
135 IntegerVariable var1, IntegerVariable var2)
const;
138 std::vector<LinearExpression2> exprs_;
139 absl::flat_hash_map<LinearExpression2, int> expr_to_index_;
142 absl::flat_hash_map<IntegerVariable,
143 absl::InlinedVector<LinearExpression2Index, 2>>
146 absl::flat_hash_map<std::pair<IntegerVariable, IntegerVariable>,
147 absl::InlinedVector<LinearExpression2Index, 1>>
173 int64_t timestamp_ = 0;
175 absl::btree_set<int> propagator_ids_;
189 shared_linear2_bounds_id_(
190 shared_linear2_bounds_ == nullptr
192 : shared_linear2_bounds_->RegisterNewId(model->Name())) {}
202 if (integer_trail_->LevelZeroUpperBound(expr) <= ub &&
203 integer_trail_->LevelZeroLowerBound(expr) >= lb) {
204 return {
false,
false};
207 if (expr.
coeffs[0] == 0 || expr.
coeffs[1] == 0)
return {
false,
false};
208 const LinearExpression2Index index = lin2_indices_->AddOrGet(expr);
212 std::swap(lb_changed, ub_changed);
214 return {lb_changed, ub_changed};
219 if (integer_trail_->LevelZeroUpperBound(expr) <= ub)
return false;
221 if (expr.
coeffs[0] == 0 || expr.
coeffs[1] == 0)
return false;
237 bool AddUpperBound(LinearExpression2Index index, IntegerValue ub);
242 return integer_trail_->LevelZeroUpperBound(expr);
245 const LinearExpression2Index index = lin2_indices_->GetIndex(expr);
247 return integer_trail_->LevelZeroUpperBound(expr);
256 return std::min(integer_trail_->LevelZeroUpperBound(expr),
262 std::vector<std::pair<LinearExpression2, IntegerValue>>
270 std::vector<std::tuple<LinearExpression2, IntegerValue, IntegerValue>>
278 std::vector<std::tuple<LinearExpression2, IntegerValue, IntegerValue>>
280 IntegerVariable var2)
const;
285 absl::Span<const std::pair<IntegerVariable, LinearExpression2Index>>
296 IntegerValue ub)
const;
315 const int shared_linear2_bounds_id_;
325 std::vector<std::pair<IntegerVariable, LinearExpression2Index>>>
326 coeff_one_var_lookup_;
328 int64_t num_updates_ = 0;
350 [
this]() {
return Build(); });
370 std::vector<FullIntegerPrecedence>* output);
389 int64_t build_timestamp_ = -1;
390 bool is_dag_ =
false;
391 std::vector<IntegerVariable> topological_order_;
400 trail_(model->GetOrCreate<
Trail>()),
406 integer_trail_->RegisterReversibleClass(
this);
423 LinearExpression2Index index, IntegerValue rhs);
439 if (trail_->CurrentDecisionLevel() != stored_level_) {
440 SetLevel(trail_->CurrentDecisionLevel());
462 std::vector<PrecedenceData>* output);
470 LinearExpression2Index index, IntegerValue ub,
471 std::vector<Literal>* literal_reason,
472 std::vector<IntegerLiteral>* integer_reason)
const;
475 void CreateLevelEntryIfNeeded();
485 int64_t num_conditional_relation_updates_ = 0;
486 int stored_level_ = 0;
492 struct ConditionalEntry {
493 ConditionalEntry(
int p, IntegerValue r, LinearExpression2Index k,
494 absl::Span<const Literal> e)
495 : prev_entry(p), rhs(r), key(k), enforcements(e.
begin(), e.
end()) {}
499 LinearExpression2Index key;
500 absl::InlinedVector<Literal, 4> enforcements;
502 std::vector<ConditionalEntry> conditional_stack_;
503 std::vector<std::pair<int, int>> level_to_stack_size_;
514 std::vector<std::pair<IntegerVariable, LinearExpression2Index>>>
515 conditional_var_lookup_;
518 std::vector<IntegerVariable> var_with_positive_degree_;
521 std::vector<PrecedenceData> tmp_precedences_;
538 template <
typename Sink>
540 absl::Format(&sink,
"%s => %v in [%v, %v]",
542 relation.
lhs, relation.
rhs);
546class ReifiedLinear2Bounds;
559 int size()
const {
return relations_.size(); }
569 if (lit >= lit_to_relations_.size())
return {};
570 return lit_to_relations_[lit];
589 bool is_built_ =
false;
590 int num_enforced_relations_ = 0;
591 int num_encoded_equivalences_ = 0;
592 std::vector<Relation> relations_;
606 IntegerValue lin_expr_gcd,
611 if (expr.
coeffs[0] == 0 || expr.
coeffs[1] == 0)
return false;
622 LinearExpression2Index lin2_index)
const;
630 LinearExpression2Index lin2_index, IntegerValue ub,
631 std::vector<Literal>* literal_reason,
632 std::vector<IntegerLiteral>* integer_reason)
const;
643 int64_t num_affine_updates_ = 0;
652 std::pair<AffineExpression, IntegerValue>>
671 void AddLinear3(absl::Span<const IntegerVariable> vars,
672 absl::Span<const int64_t> coeffs, int64_t activity);
682 std::variant<ReifiedBoundType, Literal, IntegerLiteral>
GetEncodedBound(
686 LinearExpression2Index lin2_index)
const;
699 std::pair<AffineExpression, IntegerValue>>
703 absl::flat_hash_map<std::pair<LinearExpression2Index, IntegerValue>,
Literal>
710 absl::flat_hash_set<BooleanVariable> variable_appearing_in_reified_relations_;
711 std::vector<std::tuple<Literal, LinearExpression2Index, IntegerValue>>
712 all_reified_relations_;
714 int64_t num_linear3_relations_ = 0;
715 int64_t num_relations_fixed_at_root_level_ = 0;
729 trail_(model->GetOrCreate<
Trail>()),
738 IntegerValue
UpperBound(LinearExpression2Index lin2_index)
const;
742 std::vector<Literal>* literal_reason,
743 std::vector<IntegerLiteral>* integer_reason)
const;
746 IntegerValue ub)
const;
755 absl::Span<const Literal> literal_reason,
756 absl::Span<const IntegerLiteral> integer_reason);
775 int64_t enqueue_trivial_ = 0;
776 int64_t enqueue_degenerate_ = 0;
777 int64_t enqueue_true_at_root_level_ = 0;
778 int64_t enqueue_conflict_false_at_root_level_ = 0;
779 int64_t enqueue_individual_var_bounds_ = 0;
780 int64_t enqueue_literal_encoding_ = 0;
781 int64_t enqueue_integer_linear3_encoding_ = 0;
794 const IntegerTrail& integer_trail,
795 const RootLevelLinear2Bounds& root_level_bounds,
796 const ConditionalLinear2Bounds& repository,
797 const ImpliedBounds& implied_bounds, Literal lit,
798 const absl::flat_hash_map<IntegerVariable, IntegerValue>&
input,
799 absl::flat_hash_map<IntegerVariable, IntegerValue>* output);
824 bool auto_detect_clauses =
false);
827 struct VariableConditionalAffineBound {
833 void AddRelationIfNonTrivial(
835 std::vector<VariableConditionalAffineBound>* clause_bounds)
const;
840 int AddGreaterThanAtLeastOneOfConstraintsFromClause(
841 absl::Span<const Literal> clause,
Model* model,
842 const CompactVectorVector<LiteralIndex, IntegerLiteral>&
843 implied_bounds_by_literal);
849 int AddGreaterThanAtLeastOneOfConstraintsWithClauseAutoDetection(
854 bool AddRelationFromBounds(
855 IntegerVariable var, absl::Span<const Literal> clause,
856 absl::Span<const VariableConditionalAffineBound> bounds,
Model* model);
858 ConditionalLinear2Bounds& repository_;
859 const ImpliedBounds& implied_bounds_;
860 IntegerTrail& integer_trail_;
861 SharedStatistics* shared_stats_;
862 int64_t num_detected_constraints_ = 0;
863 int64_t total_num_expressions_ = 0;
864 int64_t maximum_num_expressions_ = 0;
869 LinearExpression2Index lin2_index)
const {
872 ub = std::min(ub, root_level_bounds_->GetUpperBoundNoTrail(lin2_index));
873 ub = std::min(ub, enforced_bounds_->GetUpperBoundFromEnforced(lin2_index));
874 ub = std::min(ub, linear3_bounds_->GetUpperBoundFromLinear3(lin2_index));
885 auto it = expr_to_index_.find(expr);
888 const LinearExpression2Index positive_index(2 * it->second);
892 return positive_index;
897 LinearExpression2Index index)
const {
899 const int lookup_index = index.value() / 2;
900 DCHECK_LT(lookup_index, exprs_.size());
902 return exprs_[lookup_index];
910inline absl::Span<const LinearExpression2Index>
913 auto it = var_to_bounds_.find(positive_var);
914 if (it == var_to_bounds_.end())
return {};
918inline absl::Span<const LinearExpression2Index>
920 IntegerVariable var2)
const {
923 if (positive_var1 > positive_var2) {
924 std::swap(positive_var1, positive_var2);
926 auto it = var_pair_to_bounds_.find({positive_var1, positive_var2});
927 if (it == var_pair_to_bounds_.end())
return {};
ConditionalLinear2Bounds(Model *model)
void AddPartialRelation(Literal lit, IntegerVariable a, IntegerVariable b)
absl::Span< const int > IndicesOfRelationsEnforcedBy(LiteralIndex lit) const
void Add(Literal lit, LinearExpression2 expr, IntegerValue lhs, IntegerValue rhs)
~ConditionalLinear2Bounds()
const Relation & relation(int index) const
~EnforcedLinear2Bounds() override
EnforcedLinear2Bounds(Model *model)
void SetLevel(int level) final
void PushConditionalRelation(absl::Span< const Literal > enforcements, LinearExpression2Index index, IntegerValue rhs)
IntegerValue GetUpperBoundFromEnforced(LinearExpression2Index index) const
void AddReasonForUpperBoundLowerThan(LinearExpression2Index index, IntegerValue ub, std::vector< Literal > *literal_reason, std::vector< IntegerLiteral > *integer_reason) const
void PushConditionalRelation(absl::Span< const Literal > enforcements, LinearExpression2 expr, IntegerValue rhs)
void CollectPrecedences(absl::Span< const IntegerVariable > vars, std::vector< PrecedenceData > *output)
~GreaterThanAtLeastOneOfDetector()
int AddGreaterThanAtLeastOneOfConstraints(Model *model, bool auto_detect_clauses=false)
GreaterThanAtLeastOneOfDetector(Model *model)
LazyReasonInterface()=default
IntegerValue GetUpperBoundFromLinear3(LinearExpression2Index lin2_index) const
bool AddAffineUpperBound(LinearExpression2 expr, AffineExpression affine_ub)
Linear2BoundsFromLinear3(Model *model)
~Linear2BoundsFromLinear3()
bool AddAffineUpperBound(LinearExpression2Index lin2_index, IntegerValue lin_expr_gcd, AffineExpression affine_ub)
void AddReasonForUpperBoundLowerThan(LinearExpression2Index lin2_index, IntegerValue ub, std::vector< Literal > *literal_reason, std::vector< IntegerLiteral > *integer_reason) const
Linear2Bounds(Model *model)
void Explain(int id, IntegerLiteral to_explain, IntegerReason *reason) final
RelationStatus GetStatus(LinearExpression2 expr, IntegerValue lb, IntegerValue ub) const
std::string LazyReasonName() const final
bool EnqueueLowerOrEqual(LinearExpression2 expr, IntegerValue ub, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
void AddReasonForUpperBoundLowerThan(LinearExpression2 expr, IntegerValue ub, std::vector< Literal > *literal_reason, std::vector< IntegerLiteral > *integer_reason) const
IntegerValue NonTrivialUpperBound(LinearExpression2Index lin2_index) const
IntegerValue UpperBound(LinearExpression2 expr) const
absl::Span< const LinearExpression2Index > GetAllLinear2ContainingVariables(IntegerVariable var1, IntegerVariable var2) const
LinearExpression2Index GetIndex(LinearExpression2 expr) const
LinearExpression2Index AddOrGet(LinearExpression2 expr)
absl::Span< const LinearExpression2Index > GetAllLinear2ContainingVariable(IntegerVariable var) const
LinearExpression2 GetExpression(LinearExpression2Index index) const
absl::Span< const LinearExpression2 > GetStoredLinear2Indices() const
int64_t Timestamp() const
int64_t VarTimestamp(IntegerVariable var)
Linear2Watcher(Model *model)
void WatchAllLinearExpressions2(int id)
void NotifyBoundChanged(LinearExpression2 expr)
std::string DebugString() const
std::pair< AffineExpression, IntegerValue > GetLinear3Bound(LinearExpression2Index lin2_index) const
void AddBoundEncodingIfNonTrivial(Literal l, LinearExpression2 expr, IntegerValue ub)
std::variant< ReifiedBoundType, Literal, IntegerLiteral > GetEncodedBound(LinearExpression2 expr, IntegerValue ub)
void AddLinear3(absl::Span< const IntegerVariable > vars, absl::Span< const int64_t > coeffs, int64_t activity)
ReifiedLinear2Bounds(Model *model)
RelationStatus GetLevelZeroStatus(LinearExpression2 expr, IntegerValue lb, IntegerValue ub) const
bool AddLowerBound(LinearExpression2Index index, IntegerValue lb)
int AugmentSimpleRelations(IntegerVariable var, int work_limit)
absl::Span< const std::pair< IntegerVariable, LinearExpression2Index > > GetVariablesInSimpleRelation(IntegerVariable var) const
std::pair< bool, bool > Add(LinearExpression2 expr, IntegerValue lb, IntegerValue ub)
bool AddLowerBound(LinearExpression2 expr, IntegerValue lb)
std::vector< std::tuple< LinearExpression2, IntegerValue, IntegerValue > > GetAllBoundsContainingVariable(IntegerVariable var) const
~RootLevelLinear2Bounds()
IntegerValue LevelZeroUpperBound(LinearExpression2Index index) const
bool AddUpperBound(LinearExpression2 expr, IntegerValue ub)
IntegerValue GetUpperBoundNoTrail(LinearExpression2Index index) const
std::vector< std::pair< LinearExpression2, IntegerValue > > GetSortedNonTrivialUpperBounds() const
RootLevelLinear2Bounds(Model *model)
int64_t num_updates() const
std::vector< std::tuple< LinearExpression2, IntegerValue, IntegerValue > > GetAllBoundsContainingVariables(IntegerVariable var1, IntegerVariable var2) const
IntegerValue LevelZeroUpperBound(LinearExpression2 expr) const
void ComputeFullPrecedences(absl::Span< const IntegerVariable > vars, std::vector< FullIntegerPrecedence > *output)
TransitivePrecedencesEvaluator(Model *model)
IntegerValue FloorRatio(IntegerValue dividend, IntegerValue positive_divisor)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
bool PropagateLocalBounds(const IntegerTrail &integer_trail, const RootLevelLinear2Bounds &root_level_bounds, const ConditionalLinear2Bounds &repository, const ImpliedBounds &implied_bounds, Literal lit, const absl::flat_hash_map< IntegerVariable, IntegerValue > &input, absl::flat_hash_map< IntegerVariable, IntegerValue > *output)
LinearExpression2Index PositiveLinear2(LinearExpression2Index i)
const LinearExpression2Index kNoLinearExpression2Index(-1)
std::vector< IntegerVariable > NegationOf(absl::Span< const IntegerVariable > vars)
IntegerVariable PositiveVariable(IntegerVariable i)
bool Linear2IsPositive(LinearExpression2Index i)
IntegerValue CapProdI(IntegerValue a, IntegerValue b)
ClosedInterval::Iterator end(ClosedInterval interval)
ClosedInterval::Iterator begin(ClosedInterval interval)
static int input(yyscan_t yyscanner)
#define DEFINE_STRONG_INDEX_TYPE(index_type_name)
LinearExpression2Index lin2_index
std::vector< IntegerValue > offsets
std::vector< int > indices
std::vector< std::function< bool()> > callbacks
bool NegateForCanonicalization()
IntegerValue DivideByGcd()
bool IsCanonicalized() const
bool CanonicalizeAndUpdateBounds(IntegerValue &lb, IntegerValue &ub)
void SimpleCanonicalization()
friend void AbslStringify(Sink &sink, const Relation &relation)
bool operator==(const Relation &other) const