14#ifndef OR_TOOLS_SAT_PRECEDENCES_H_
15#define OR_TOOLS_SAT_PRECEDENCES_H_
25#include "absl/container/flat_hash_map.h"
26#include "absl/container/inlined_vector.h"
27#include "absl/log/check.h"
28#include "absl/types/span.h"
61 : params_(*model->GetOrCreate<SatParameters>()),
62 trail_(model->GetOrCreate<
Trail>()),
64 integer_trail_->RegisterReversibleClass(
this);
68 graph_.ReserveNodes(num_variables);
69 graph_.AddNode(num_variables - 1);
74 bool Add(IntegerVariable tail, IntegerVariable head, IntegerValue offset);
85 IntegerVariable a, IntegerVariable
b,
105 std::vector<FullIntegerPrecedence>* output);
116 std::vector<PrecedenceData>* output);
126 IntegerValue
GetOffset(IntegerVariable a, IntegerVariable
b)
const;
140 IntegerVariable
b)
const;
149 void CreateLevelEntryIfNeeded();
151 std::pair<IntegerVariable, IntegerVariable> GetKey(IntegerVariable a,
152 IntegerVariable
b)
const {
153 return a <=
b ? std::make_pair(a,
b) :
std::make_pair(
b, a);
158 bool AddInternal(IntegerVariable tail, IntegerVariable head,
159 IntegerValue offset) {
160 const auto key = GetKey(tail,
NegationOf(head));
161 const auto [it, inserted] = root_relations_.insert({key, -offset});
162 UpdateBestRelationIfBetter(key, -offset);
164 const int new_size = std::max(tail.value(),
NegationOf(head).value()) + 1;
165 if (new_size > after_.size()) after_.
resize(new_size);
170 it->second = std::min(it->second, -offset);
174 void UpdateBestRelationIfBetter(
175 std::pair<IntegerVariable, IntegerVariable> key, IntegerValue rhs) {
176 const auto [it, inserted] = best_relations_.insert({key, rhs});
178 it->second = std::min(it->second, rhs);
182 void UpdateBestRelation(std::pair<IntegerVariable, IntegerVariable> key,
184 const auto it = root_relations_.find(key);
185 if (it != root_relations_.end()) {
186 rhs = std::min(rhs, it->second);
189 best_relations_.erase(key);
191 best_relations_[key] = rhs;
195 const SatParameters& params_;
197 IntegerTrail* integer_trail_;
199 util::StaticGraph<> graph_;
200 std::vector<IntegerValue> arc_offsets_;
202 bool is_built_ =
false;
203 bool is_dag_ =
false;
204 std::vector<IntegerVariable> topological_order_;
210 struct ConditionalEntry {
211 ConditionalEntry(
int p, IntegerValue r,
212 std::pair<IntegerVariable, IntegerVariable> k,
213 absl::Span<const Literal> e)
214 : prev_entry(p), rhs(r), key(k), enforcements(e.begin(), e.end()) {}
218 std::pair<IntegerVariable, IntegerVariable> key;
219 absl::InlinedVector<Literal, 4> enforcements;
221 std::vector<ConditionalEntry> conditional_stack_;
222 std::vector<std::pair<int, int>> level_to_stack_size_;
226 absl::flat_hash_map<std::pair<IntegerVariable, IntegerVariable>, IntegerValue>
228 absl::flat_hash_map<std::pair<IntegerVariable, IntegerVariable>,
int>
229 conditional_relations_;
233 absl::flat_hash_map<std::pair<IntegerVariable, IntegerVariable>, IntegerValue>
239 util_intops::StrongVector<IntegerVariable, std::vector<IntegerVariable>>
241 util_intops::StrongVector<IntegerVariable, std::vector<IntegerVariable>>
245 std::vector<IntegerVariable> var_with_positive_degree_;
246 util_intops::StrongVector<IntegerVariable, int> var_to_degree_;
247 util_intops::StrongVector<IntegerVariable, int> var_to_last_index_;
248 std::vector<PrecedenceData> tmp_precedences_;
272 trail_(model->GetOrCreate<
Trail>()),
276 watcher_id_(watcher_->Register(this)) {
278 integer_trail_->RegisterWatcher(&modified_vars_);
279 watcher_->SetPropagatorPriority(watcher_id_, 0);
289 void Untrail(const
Trail& trail,
int trail_index) final;
303 IntegerValue offset);
305 IntegerVariable offset_var);
312 IntegerValue offset,
Literal l);
317 IntegerVariable offset_var,
322 IntegerValue offset);
326 DEFINE_STRONG_INDEX_TYPE(OptionalArcIndex);
330 IntegerVariable tail_var;
331 IntegerVariable head_var;
334 IntegerVariable offset_var;
337 absl::InlinedVector<Literal, 6> presence_literals;
341 mutable bool is_marked;
349 void AdjustSizeFor(IntegerVariable
i);
350 void AddArc(IntegerVariable tail, IntegerVariable head, IntegerValue offset,
351 IntegerVariable offset_var,
352 absl::Span<const Literal> presence_literals);
356 bool EnqueueAndCheck(
const ArcInfo& arc, IntegerValue new_head_lb,
358 IntegerValue ArcOffset(
const ArcInfo& arc)
const;
362 void PropagateOptionalArcs(
Trail* trail);
380 void InitializeBFQueueWithModifiedNodes();
381 bool BellmanFordTarjan(
Trail* trail);
382 bool DisassembleSubtree(
int source,
int target,
383 std::vector<bool>* can_be_skipped);
385 std::vector<Literal>* must_be_all_true,
386 std::vector<Literal>* literal_reason,
387 std::vector<IntegerLiteral>* integer_reason);
388 void CleanUpMarkedArcsAndParents();
392 bool NoPropagationLeft(
const Trail& trail)
const;
395 void PushConditionalRelations(
const ArcInfo& arc);
429 absl::InlinedVector<OptionalArcIndex, 6>>
430 impacted_potential_arcs_;
441 literal_to_new_impacted_arcs_;
445 std::vector<Literal> literal_reason_;
446 std::vector<IntegerLiteral> integer_reason_;
451 std::deque<int> bf_queue_;
452 std::vector<bool> bf_in_queue_;
453 std::vector<bool> bf_can_be_skipped_;
454 std::vector<ArcIndex> bf_parent_arc_of_;
457 std::vector<int> tmp_vector_;
460 int64_t num_cycles_ = 0;
461 int64_t num_pushes_ = 0;
462 int64_t num_enforcement_pushes_ = 0;
469 IntegerValue
coeff = IntegerValue(0);
496 int size()
const {
return relations_.size(); }
500 if (lit >= lit_to_relations_.size())
return {};
501 return lit_to_relations_[lit];
520 const absl::flat_hash_map<IntegerVariable, IntegerValue>&
input,
521 absl::flat_hash_map<IntegerVariable, IntegerValue>* output)
const;
524 bool is_built_ =
false;
525 std::vector<Relation> relations_;
547 bool auto_detect_clauses =
false);
553 int AddGreaterThanAtLeastOneOfConstraintsFromClause(
554 absl::Span<const Literal> clause,
Model* model);
560 int AddGreaterThanAtLeastOneOfConstraintsWithClauseAutoDetection(
565 bool AddRelationFromIndices(IntegerVariable var,
566 absl::Span<const Literal> clause,
567 absl::Span<const int> indices,
Model* model);
577 IntegerVariable i2) {
583 IntegerVariable i1, IntegerVariable i2, IntegerValue offset) {
595 IntegerVariable i1, IntegerVariable i2, IntegerValue offset,
Literal l) {
600 IntegerVariable i1, IntegerVariable i2, IntegerVariable offset_var) {
601 AddArc(i1, i2, IntegerValue(0), offset_var, {});
605 IntegerVariable i1, IntegerVariable i2, IntegerValue offset,
606 IntegerVariable offset_var, absl::Span<const Literal> presence_literals) {
607 AddArc(i1, i2, offset, offset_var, presence_literals);
617 return [=](
Model* model) {
626 return [=](
Model* model) {
629 a,
b, IntegerValue(offset));
635 AffineExpression a, AffineExpression
b, int64_t offset) {
637 CHECK_EQ(a.coeff, 1);
639 CHECK_EQ(
b.coeff, 1);
640 return [=](
Model* model) {
642 a.var,
b.var, a.constant -
b.constant + offset);
644 a.var,
b.var, a.constant -
b.constant + offset);
650 absl::Span<const Literal> enforcement_literals, IntegerVariable a,
651 IntegerVariable
b, int64_t ub,
Model* model) {
653 if (enforcement_literals.empty()) {
658 PrecedencesPropagator* p = model->GetOrCreate<PrecedencesPropagator>();
659 p->AddPrecedenceWithAllOptions(a,
NegationOf(
b), IntegerValue(-ub),
667 absl::Span<const Literal> enforcement_literals, IntegerVariable a,
668 IntegerVariable
b, IntegerVariable c, int64_t ub,
Model* model) {
669 PrecedencesPropagator* p = model->GetOrCreate<PrecedencesPropagator>();
670 p->AddPrecedenceWithAllOptions(a,
NegationOf(c), IntegerValue(-ub),
b,
671 enforcement_literals);
677 return [=](
Model* model) {
678 return model->GetOrCreate<PrecedencesPropagator>()->AddPrecedence(
b, a);
683inline std::function<void(
Model*)>
Equality(IntegerVariable a,
685 return [=](
Model* model) {
695 return [=](
Model* model) {
703 IntegerVariable a, IntegerVariable
b, int64_t offset, Literal is_le) {
704 return [=](
Model* model) {
705 PrecedencesPropagator* p = model->GetOrCreate<PrecedencesPropagator>();
706 p->AddConditionalPrecedenceWithOffset(a,
b, IntegerValue(offset), is_le);
absl::Span< const int > relation_indices(LiteralIndex lit) const
bool PropagateLocalBounds(const IntegerTrail &integer_trail, Literal lit, const absl::flat_hash_map< IntegerVariable, IntegerValue > &input, absl::flat_hash_map< IntegerVariable, IntegerValue > *output) const
const Relation & relation(int index) const
void Add(Literal lit, LinearTerm a, LinearTerm b, IntegerValue lhs, IntegerValue rhs)
Adds a relation lit => a + b \in [lhs, rhs].
int AddGreaterThanAtLeastOneOfConstraints(Model *model, bool auto_detect_clauses=false)
GreaterThanAtLeastOneOfDetector(Model *model)
PrecedenceRelations(Model *model)
void PushConditionalRelation(absl::Span< const Literal > enforcements, IntegerVariable a, IntegerVariable b, IntegerValue rhs)
void CollectPrecedences(absl::Span< const IntegerVariable > vars, std::vector< PrecedenceData > *output)
bool Add(IntegerVariable tail, IntegerVariable head, IntegerValue offset)
IntegerValue GetConditionalOffset(IntegerVariable a, IntegerVariable b) const
void ComputeFullPrecedences(absl::Span< const IntegerVariable > vars, std::vector< FullIntegerPrecedence > *output)
void SetLevel(int level) final
Called each time we change decision level.
void Resize(int num_variables)
IntegerValue GetOffset(IntegerVariable a, IntegerVariable b) const
absl::Span< const Literal > GetConditionalEnforcements(IntegerVariable a, IntegerVariable b) const
bool PropagateOutgoingArcs(IntegerVariable var)
bool AddPrecedenceWithOffsetIfNew(IntegerVariable i1, IntegerVariable i2, IntegerValue offset)
This version check current precedence. It is however "slow".
PrecedencesPropagator(const PrecedencesPropagator &)=delete
This type is neither copyable nor movable.
void AddPrecedence(IntegerVariable i1, IntegerVariable i2)
void AddPrecedenceWithOffset(IntegerVariable i1, IntegerVariable i2, IntegerValue offset)
void AddPrecedenceWithAllOptions(IntegerVariable i1, IntegerVariable i2, IntegerValue offset, IntegerVariable offset_var, absl::Span< const Literal > presence_literals)
Generic function that cover all of the above case and more.
PrecedencesPropagator(Model *model)
~PrecedencesPropagator() override
void AddPrecedenceWithVariableOffset(IntegerVariable i1, IntegerVariable i2, IntegerVariable offset_var)
PrecedencesPropagator & operator=(const PrecedencesPropagator &)=delete
void AddConditionalPrecedenceWithOffset(IntegerVariable i1, IntegerVariable i2, IntegerValue offset, Literal l)
void Untrail(const Trail &trail, int trail_index) final
void AddConditionalPrecedence(IntegerVariable i1, IntegerVariable i2, Literal l)
Same as above, but the relation is only true when the given literal is.
PropagatorInterface()=default
SatPropagator(const std::string &name)
void AddPropagator(SatPropagator *propagator)
Simple class to add statistics by name and print them at the end.
void push_back(const value_type &val)
void resize(size_type new_size)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
std::function< void(Model *)> Equality(IntegerVariable v, int64_t value)
Fix v to a given value.
std::function< void(Model *)> LowerOrEqualWithOffset(IntegerVariable a, IntegerVariable b, int64_t offset)
a + offset <= b.
std::function< void(Model *)> AffineCoeffOneLowerOrEqualWithOffset(AffineExpression a, AffineExpression b, int64_t offset)
a + offset <= b. (when a and b are of the form 1 * var + offset).
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
std::vector< IntegerVariable > NegationOf(absl::Span< const IntegerVariable > vars)
Returns the vector of the negated variables.
const IntegerVariable kNoIntegerVariable(-1)
std::function< void(Model *)> EqualityWithOffset(IntegerVariable a, IntegerVariable b, int64_t offset)
a + offset == b.
std::function< void(Model *)> GreaterOrEqual(IntegerVariable v, int64_t lb)
void AddConditionalSum3LowerOrEqual(absl::Span< const Literal > enforcement_literals, IntegerVariable a, IntegerVariable b, IntegerVariable c, int64_t ub, Model *model)
void AddConditionalSum2LowerOrEqual(absl::Span< const Literal > enforcement_literals, IntegerVariable a, IntegerVariable b, int64_t ub, Model *model)
l => (a + b <= ub).
std::function< void(Model *)> ConditionalLowerOrEqualWithOffset(IntegerVariable a, IntegerVariable b, int64_t offset, Literal is_le)
is_le => (a + offset <= b).
In SWIG mode, we don't want anything besides these top-level includes.
static int input(yyscan_t yyscanner)
std::vector< IntegerValue > offsets
std::vector< int > indices