14#ifndef OR_TOOLS_SAT_PRECEDENCES_H_
15#define OR_TOOLS_SAT_PRECEDENCES_H_
24#include "absl/container/inlined_vector.h"
25#include "absl/log/check.h"
26#include "absl/strings/string_view.h"
27#include "absl/types/span.h"
58 : params_(*
model->GetOrCreate<SatParameters>()),
66 graph_.
AddNode(num_variables - 1);
71 bool Add(IntegerVariable
tail, IntegerVariable
head, IntegerValue offset);
82 IntegerVariable
a, IntegerVariable
b,
102 std::vector<FullIntegerPrecedence>* output);
113 std::vector<PrecedenceData>* output);
123 IntegerValue
GetOffset(IntegerVariable
a, IntegerVariable
b)
const;
137 IntegerVariable
b)
const;
146 void CreateLevelEntryIfNeeded();
148 std::pair<IntegerVariable, IntegerVariable> GetKey(IntegerVariable
a,
149 IntegerVariable
b)
const {
150 return a <=
b ? std::make_pair(
a,
b) :
std::make_pair(
b,
a);
155 bool AddInternal(IntegerVariable
tail, IntegerVariable
head,
156 IntegerValue offset) {
158 const auto [it, inserted] = root_relations_.insert({key, -offset});
159 UpdateBestRelationIfBetter(key, -offset);
162 if (new_size > after_.size()) after_.
resize(new_size);
167 it->second = std::min(it->second, -offset);
171 void UpdateBestRelationIfBetter(
172 std::pair<IntegerVariable, IntegerVariable> key, IntegerValue rhs) {
173 const auto [it, inserted] = best_relations_.insert({key, rhs});
175 it->second = std::min(it->second, rhs);
179 void UpdateBestRelation(std::pair<IntegerVariable, IntegerVariable> key,
181 const auto it = root_relations_.find(key);
182 if (it != root_relations_.end()) {
183 rhs = std::min(rhs, it->second);
186 best_relations_.erase(key);
188 best_relations_[key] = rhs;
192 const SatParameters& params_;
194 IntegerTrail* integer_trail_;
197 std::vector<IntegerValue> arc_offsets_;
199 bool is_built_ =
false;
200 bool is_dag_ =
false;
201 std::vector<IntegerVariable> topological_order_;
207 struct ConditionalEntry {
208 ConditionalEntry(
int p, IntegerValue r,
209 std::pair<IntegerVariable, IntegerVariable> k,
210 absl::Span<const Literal> e)
211 : prev_entry(p), rhs(r), key(k), enforcements(e.begin(), e.
end()) {}
215 std::pair<IntegerVariable, IntegerVariable> key;
216 absl::InlinedVector<Literal, 4> enforcements;
218 std::vector<ConditionalEntry> conditional_stack_;
219 std::vector<std::pair<int, int>> level_to_stack_size_;
223 absl::flat_hash_map<std::pair<IntegerVariable, IntegerVariable>, IntegerValue>
225 absl::flat_hash_map<std::pair<IntegerVariable, IntegerVariable>,
int>
226 conditional_relations_;
230 absl::flat_hash_map<std::pair<IntegerVariable, IntegerVariable>, IntegerValue>
242 std::vector<IntegerVariable> var_with_positive_degree_;
245 std::vector<PrecedenceData> tmp_precedences_;
273 watcher_id_(watcher_->Register(this)) {
286 void Untrail(const
Trail& trail,
int trail_index) final;
300 IntegerValue offset);
302 IntegerVariable offset_var);
309 IntegerValue offset,
Literal l);
314 IntegerVariable offset_var,
319 IntegerValue offset);
327 IntegerVariable tail_var;
328 IntegerVariable head_var;
331 IntegerVariable offset_var;
334 absl::InlinedVector<Literal, 6> presence_literals;
338 mutable bool is_marked;
346 void AdjustSizeFor(IntegerVariable
i);
347 void AddArc(IntegerVariable
tail, IntegerVariable
head, IntegerValue offset,
348 IntegerVariable offset_var,
349 absl::Span<const Literal> presence_literals);
353 bool EnqueueAndCheck(
const ArcInfo&
arc, IntegerValue new_head_lb,
355 IntegerValue ArcOffset(
const ArcInfo&
arc)
const;
359 void PropagateOptionalArcs(
Trail* trail);
377 void InitializeBFQueueWithModifiedNodes();
378 bool BellmanFordTarjan(
Trail* trail);
379 bool DisassembleSubtree(
int source,
int target,
380 std::vector<bool>* can_be_skipped);
382 std::vector<Literal>* must_be_all_true,
383 std::vector<Literal>* literal_reason,
384 std::vector<IntegerLiteral>* integer_reason);
385 void CleanUpMarkedArcsAndParents();
389 bool NoPropagationLeft(
const Trail& trail)
const;
392 void PushConditionalRelations(
const ArcInfo&
arc);
426 absl::InlinedVector<OptionalArcIndex, 6>>
427 impacted_potential_arcs_;
438 literal_to_new_impacted_arcs_;
442 std::vector<Literal> literal_reason_;
443 std::vector<IntegerLiteral> integer_reason_;
448 std::deque<int> bf_queue_;
449 std::vector<bool> bf_in_queue_;
450 std::vector<bool> bf_can_be_skipped_;
451 std::vector<ArcIndex> bf_parent_arc_of_;
454 std::vector<int> tmp_vector_;
457 int64_t num_cycles_ = 0;
458 int64_t num_pushes_ = 0;
459 int64_t num_enforcement_pushes_ = 0;
466 IntegerValue
coeff = IntegerValue(0);
488 bool auto_detect_clauses =
false);
494 int AddGreaterThanAtLeastOneOfConstraintsFromClause(
495 absl::Span<const Literal> clause,
Model*
model);
501 int AddGreaterThanAtLeastOneOfConstraintsWithClauseAutoDetection(
506 bool AddRelationFromIndices(IntegerVariable
var,
507 absl::Span<const Literal> clause,
517 std::vector<Relation> relations_;
519 std::unique_ptr<CompactVectorVector<LiteralIndex, int>> lit_to_relations_;
527 IntegerVariable i2) {
533 IntegerVariable i1, IntegerVariable i2, IntegerValue offset) {
545 IntegerVariable i1, IntegerVariable i2, IntegerValue offset,
Literal l) {
550 IntegerVariable i1, IntegerVariable i2, IntegerVariable offset_var) {
551 AddArc(i1, i2, IntegerValue(0), offset_var, {});
555 IntegerVariable i1, IntegerVariable i2, IntegerValue offset,
556 IntegerVariable offset_var, absl::Span<const Literal> presence_literals) {
557 AddArc(i1, i2, offset, offset_var, presence_literals);
576 return [=](Model*
model) {
579 a,
b, IntegerValue(offset));
585 AffineExpression
a, AffineExpression
b, int64_t offset) {
587 CHECK_EQ(
a.coeff, 1);
589 CHECK_EQ(
b.coeff, 1);
592 a.var,
b.var,
a.constant -
b.constant + offset);
594 a.var,
b.var,
a.constant -
b.constant + offset);
600 absl::Span<const Literal> enforcement_literals, IntegerVariable
a,
601 IntegerVariable
b, int64_t ub, Model*
model) {
603 if (enforcement_literals.empty()) {
608 PrecedencesPropagator* p =
model->GetOrCreate<PrecedencesPropagator>();
609 p->AddPrecedenceWithAllOptions(
a,
NegationOf(
b), IntegerValue(-ub),
617 absl::Span<const Literal> enforcement_literals, IntegerVariable
a,
618 IntegerVariable
b, IntegerVariable c, int64_t ub, Model*
model) {
619 PrecedencesPropagator* p =
model->GetOrCreate<PrecedencesPropagator>();
621 enforcement_literals);
627 return [=](Model*
model) {
628 return model->GetOrCreate<PrecedencesPropagator>()->AddPrecedence(
b,
a);
633inline std::function<void(Model*)>
Equality(IntegerVariable
a,
635 return [=](Model*
model) {
645 return [=](Model*
model) {
653 IntegerVariable
a, IntegerVariable
b, int64_t offset, Literal is_le) {
654 return [=](Model*
model) {
655 PrecedencesPropagator* p =
model->GetOrCreate<PrecedencesPropagator>();
656 p->AddConditionalPrecedenceWithOffset(
a,
b, IntegerValue(offset), is_le);
void SetPropagatorPriority(int id, int priority)
int AddGreaterThanAtLeastOneOfConstraints(Model *model, bool auto_detect_clauses=false)
void Add(Literal lit, LinearTerm a, LinearTerm b, IntegerValue lhs, IntegerValue rhs)
Adds a relation lit => a + b \in [lhs, rhs].
void RegisterWatcher(SparseBitset< IntegerVariable > *p)
void RegisterReversibleClass(ReversibleInterface *rev)
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.
Base class for CP like propagators.
Base class for all the SAT constraints.
void AddPropagator(SatPropagator *propagator)
Simple class to add statistics by name and print them at the end.
void ReserveNodes(NodeIndexType bound) override
void AddNode(NodeIndexType node)
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::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Returns the vector of the negated variables.
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
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.
std::optional< int64_t > end
#define DEFINE_STRONG_INDEX_TYPE(index_type_name)
std::vector< IntegerValue > offsets
std::vector< int > indices