OR-Tools  9.3
precedences.h
Go to the documentation of this file.
1// Copyright 2010-2021 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14#ifndef OR_TOOLS_SAT_PRECEDENCES_H_
15#define OR_TOOLS_SAT_PRECEDENCES_H_
16
17#include <cstdint>
18#include <deque>
19#include <functional>
20#include <vector>
21
22#include "absl/container/inlined_vector.h"
23#include "absl/strings/string_view.h"
24#include "absl/types/span.h"
26#include "ortools/base/macros.h"
28#include "ortools/sat/integer.h"
29#include "ortools/sat/model.h"
32#include "ortools/util/bitset.h"
34
35namespace operations_research {
36namespace sat {
37
38// This class implement a propagator on simple inequalities between integer
39// variables of the form (i1 + offset <= i2). The offset can be constant or
40// given by the value of a third integer variable. Offsets can also be negative.
41//
42// The algorithm works by mapping the problem onto a graph where the edges carry
43// the offset and the nodes correspond to one of the two bounds of an integer
44// variable (lower_bound or -upper_bound). It then find the fixed point using an
45// incremental variant of the Bellman-Ford(-Tarjan) algorithm.
46//
47// This is also known as an "integer difference logic theory" in the SMT world.
48// Another word is "separation logic".
49//
50// TODO(user): We could easily generalize the code to support any relation of
51// the form a*X + b*Y + c*Z >= rhs (or <=). Do that since this class should be
52// a lot faster at propagating small linear inequality than the generic
53// propagator and the overhead of supporting coefficient should not be too bad.
55 public:
57 : SatPropagator("PrecedencesPropagator"),
58 trail_(model->GetOrCreate<Trail>()),
59 integer_trail_(model->GetOrCreate<IntegerTrail>()),
60 watcher_(model->GetOrCreate<GenericLiteralWatcher>()),
61 watcher_id_(watcher_->Register(this)) {
62 model->GetOrCreate<SatSolver>()->AddPropagator(this);
63 integer_trail_->RegisterWatcher(&modified_vars_);
64 watcher_->SetPropagatorPriority(watcher_id_, 0);
65 }
66
67 bool Propagate() final;
68 bool Propagate(Trail* trail) final;
69 void Untrail(const Trail& trail, int trail_index) final;
70
71 // Propagates all the outgoing arcs of the given variable (and only those). It
72 // is more efficient to do all these propagation in one go by calling
73 // Propagate(), but for scheduling problem, we wants to propagate right away
74 // the end of an interval when its start moved.
75 bool PropagateOutgoingArcs(IntegerVariable var);
76
77 // Add a precedence relation (i1 + offset <= i2) between integer variables.
78 //
79 // Important: The optionality of the variable should be marked BEFORE this
80 // is called.
81 void AddPrecedence(IntegerVariable i1, IntegerVariable i2);
82 void AddPrecedenceWithOffset(IntegerVariable i1, IntegerVariable i2,
83 IntegerValue offset);
84 void AddPrecedenceWithVariableOffset(IntegerVariable i1, IntegerVariable i2,
85 IntegerVariable offset_var);
86
87 // Same as above, but the relation is only true when the given literal is.
88 void AddConditionalPrecedence(IntegerVariable i1, IntegerVariable i2,
89 Literal l);
90 void AddConditionalPrecedenceWithOffset(IntegerVariable i1,
91 IntegerVariable i2,
92 IntegerValue offset, Literal l);
93
94 // Generic function that cover all of the above case and more.
95 void AddPrecedenceWithAllOptions(IntegerVariable i1, IntegerVariable i2,
96 IntegerValue offset,
97 IntegerVariable offset_var,
98 absl::Span<const Literal> presence_literals);
99
100 // Finds all the IntegerVariable that are "after" at least two of the
101 // IntegerVariable in vars. Returns a vector of these precedences relation
102 // sorted by IntegerPrecedences.var so that it is efficient to find all the
103 // IntegerVariable "before" another one.
104 //
105 // Note that we only consider direct precedences here. Given our usage, it may
106 // be better to compute the full reachability in the precedence graph, but in
107 // pratice that may be too slow.
108 //
109 // Note that the IntegerVariable in the vector are also returned in
110 // topological order for a more efficient propagation in
111 // DisjunctivePrecedences::Propagate() where this is used.
112 //
113 // Important: For identical vars, the entry are sorted by index.
115 int index; // position in vars.
116 IntegerVariable var; // An IntegerVariable that is >= to vars[index].
117 int arc_index; // Used by AddPrecedenceReason().
118 IntegerValue offset; // we have: vars[index] + offset <= var
119 };
120 void ComputePrecedences(const std::vector<IntegerVariable>& vars,
121 std::vector<IntegerPrecedences>* output);
122 void AddPrecedenceReason(int arc_index, IntegerValue min_offset,
123 std::vector<Literal>* literal_reason,
124 std::vector<IntegerLiteral>* integer_reason) const;
125
126 // Advanced usage. To be called once all the constraints have been added to
127 // the model. This will loop over all "node" in this class, and if one of its
128 // optional incoming arcs must be chosen, it will add a corresponding
129 // GreaterThanAtLeastOneOfConstraint(). Returns the number of added
130 // constraint.
131 //
132 // TODO(user): This can be quite slow, add some kind of deterministic limit
133 // so that we can use it all the time.
135
136 private:
137 DEFINE_STRONG_INDEX_TYPE(ArcIndex);
138 DEFINE_STRONG_INDEX_TYPE(OptionalArcIndex);
139
140 // Given an existing clause, sees if it can be used to add "greater than at
141 // least one of" type of constraints. Returns the number of such constraint
142 // added.
143 int AddGreaterThanAtLeastOneOfConstraintsFromClause(
144 const absl::Span<const Literal> clause, Model* model);
145
146 // Another approach for AddGreaterThanAtLeastOneOfConstraints(), this one
147 // might be a bit slow as it relies on the propagation engine to detect
148 // clauses between incoming arcs presence literals.
149 // Returns the number of added constraints.
150 int AddGreaterThanAtLeastOneOfConstraintsWithClauseAutoDetection(
151 Model* model);
152
153 // Information about an individual arc.
154 struct ArcInfo {
155 IntegerVariable tail_var;
156 IntegerVariable head_var;
157
158 IntegerValue offset;
159 IntegerVariable offset_var; // kNoIntegerVariable if none.
160
161 // This arc is "present" iff all these literals are true.
162 absl::InlinedVector<Literal, 6> presence_literals;
163
164 // Used temporarily by our implementation of the Bellman-Ford algorithm. It
165 // should be false at the beginning of BellmanFordTarjan().
166 mutable bool is_marked;
167 };
168
169 // Internal functions to add new precedence relations.
170 //
171 // Note that internally, we only propagate lower bounds, so each time we add
172 // an arc, we actually create two of them: one on the given variables, and one
173 // on their negation.
174 void AdjustSizeFor(IntegerVariable i);
175 void AddArc(IntegerVariable tail, IntegerVariable head, IntegerValue offset,
176 IntegerVariable offset_var,
177 absl::Span<const Literal> presence_literals);
178
179 // Enqueue a new lower bound for the variable arc.head_lb that was deduced
180 // from the current value of arc.tail_lb and the offset of this arc.
181 bool EnqueueAndCheck(const ArcInfo& arc, IntegerValue new_head_lb,
182 Trail* trail);
183 IntegerValue ArcOffset(const ArcInfo& arc) const;
184
185 // Inspect all the optional arcs that needs inspection (to stay sparse) and
186 // check if their presence literal can be propagated to false.
187 void PropagateOptionalArcs(Trail* trail);
188
189 // The core algorithm implementation is split in these functions. One must
190 // first call InitializeBFQueueWithModifiedNodes() that will push all the
191 // IntegerVariable whose lower bound has been modified since the last call.
192 // Then, BellmanFordTarjan() will take care of all the propagation and returns
193 // false in case of conflict. Internally, it uses DisassembleSubtree() which
194 // is the Tarjan variant to detect a possible positive cycle. Before exiting,
195 // it will call CleanUpMarkedArcsAndParents().
196 //
197 // The Tarjan version of the Bellam-Ford algorithm is really nice in our
198 // context because it was really easy to make it incremental. Moreover, it
199 // supports batch increment!
200 //
201 // This implementation is kind of unique because of our context and the fact
202 // that it is incremental, but a good reference is "Negative-cycle detection
203 // algorithms", Boris V. Cherkassky, Andrew V. Goldberg, 1996,
204 // http://people.cs.nctu.edu.tw/~tjshen/doc/ne.pdf
205 void InitializeBFQueueWithModifiedNodes();
206 bool BellmanFordTarjan(Trail* trail);
207 bool DisassembleSubtree(int source, int target,
208 std::vector<bool>* can_be_skipped);
209 void AnalyzePositiveCycle(ArcIndex first_arc, Trail* trail,
210 std::vector<Literal>* must_be_all_true,
211 std::vector<Literal>* literal_reason,
212 std::vector<IntegerLiteral>* integer_reason);
213 void CleanUpMarkedArcsAndParents();
214
215 // Loops over all the arcs and verify that there is no propagation left.
216 // This is only meant to be used in a DCHECK() and is not optimized.
217 bool NoPropagationLeft(const Trail& trail) const;
218
219 // External class needed to get the IntegerVariable lower bounds and Enqueue
220 // new ones.
221 Trail* trail_;
222 IntegerTrail* integer_trail_;
223 GenericLiteralWatcher* watcher_;
224 int watcher_id_;
225
226 // The key to our incrementality. This will be cleared once the propagation
227 // is done, and automatically updated by the integer_trail_ with all the
228 // IntegerVariable that changed since the last clear.
229 SparseBitset<IntegerVariable> modified_vars_;
230
231 // An arc needs to be inspected for propagation (i.e. is impacted) if its
232 // tail_var changed. If an arc has 3 variables (tail, offset, head), it will
233 // appear as 6 different entries in the arcs_ vector, one for each variable
234 // and its negation, each time with a different tail.
235 //
236 // TODO(user): rearranging the index so that the arc of the same node are
237 // consecutive like in StaticGraph should have a big performance impact.
238 //
239 // TODO(user): We do not need to store ArcInfo.tail_var here.
241 impacted_arcs_;
243
244 // This is similar to impacted_arcs_/arcs_ but it is only used to propagate
245 // one of the presence literals when the arc cannot be present. An arc needs
246 // to appear only once in potential_arcs_, but it will be referenced by
247 // all its variable in impacted_potential_arcs_.
249 impacted_potential_arcs_;
251
252 // Temporary vectors used by ComputePrecedences().
255 struct SortedVar {
256 IntegerVariable var;
257 IntegerValue lower_bound;
258 bool operator<(const SortedVar& other) const {
259 return lower_bound < other.lower_bound;
260 }
261 };
262 std::vector<SortedVar> tmp_sorted_vars_;
263 std::vector<IntegerPrecedences> tmp_precedences_;
264
265 // Each time a literal becomes true, this list the set of arcs for which we
266 // need to decrement their count. When an arc count reach zero, it must be
267 // added to the set of impacted_arcs_. Note that counts never becomes
268 // negative.
269 //
270 // TODO(user): Try a one-watcher approach instead. Note that in most cases
271 // arc should be controlled by 1 or 2 literals, so not sure it is worth it.
273 literal_to_new_impacted_arcs_;
275
276 // Temp vectors to hold the reason of an assignment.
277 std::vector<Literal> literal_reason_;
278 std::vector<IntegerLiteral> integer_reason_;
279
280 // Temp vectors for the Bellman-Ford algorithm. The graph in which this
281 // algorithm works is in one to one correspondence with the IntegerVariable in
282 // impacted_arcs_.
283 std::deque<int> bf_queue_;
284 std::vector<bool> bf_in_queue_;
285 std::vector<bool> bf_can_be_skipped_;
286 std::vector<ArcIndex> bf_parent_arc_of_;
287
288 // Temp vector used by the tree traversal in DisassembleSubtree().
289 std::vector<int> tmp_vector_;
290
291 DISALLOW_COPY_AND_ASSIGN(PrecedencesPropagator);
292};
293
294// =============================================================================
295// Implementation of the small API functions below.
296// =============================================================================
297
298inline void PrecedencesPropagator::AddPrecedence(IntegerVariable i1,
299 IntegerVariable i2) {
300 AddArc(i1, i2, /*offset=*/IntegerValue(0), /*offset_var=*/kNoIntegerVariable,
301 {});
302}
303
305 IntegerVariable i1, IntegerVariable i2, IntegerValue offset) {
306 AddArc(i1, i2, offset, /*offset_var=*/kNoIntegerVariable, {});
307}
308
310 IntegerVariable i2,
311 Literal l) {
312 AddArc(i1, i2, /*offset=*/IntegerValue(0), /*offset_var=*/kNoIntegerVariable,
313 {l});
314}
315
317 IntegerVariable i1, IntegerVariable i2, IntegerValue offset, Literal l) {
318 AddArc(i1, i2, offset, /*offset_var=*/kNoIntegerVariable, {l});
319}
320
322 IntegerVariable i1, IntegerVariable i2, IntegerVariable offset_var) {
323 AddArc(i1, i2, /*offset=*/IntegerValue(0), offset_var, {});
324}
325
327 IntegerVariable i1, IntegerVariable i2, IntegerValue offset,
328 IntegerVariable offset_var, absl::Span<const Literal> presence_literals) {
329 AddArc(i1, i2, offset, offset_var, presence_literals);
330}
331
332// =============================================================================
333// Model based functions.
334// =============================================================================
335
336// a <= b.
337inline std::function<void(Model*)> LowerOrEqual(IntegerVariable a,
338 IntegerVariable b) {
339 return [=](Model* model) {
340 return model->GetOrCreate<PrecedencesPropagator>()->AddPrecedence(a, b);
341 };
342}
343
344// a + offset <= b.
345inline std::function<void(Model*)> LowerOrEqualWithOffset(IntegerVariable a,
346 IntegerVariable b,
347 int64_t offset) {
348 return [=](Model* model) {
349 return model->GetOrCreate<PrecedencesPropagator>()->AddPrecedenceWithOffset(
350 a, b, IntegerValue(offset));
351 };
352}
353
354// a + b <= ub.
355inline std::function<void(Model*)> Sum2LowerOrEqual(IntegerVariable a,
356 IntegerVariable b,
357 int64_t ub) {
358 return LowerOrEqualWithOffset(a, NegationOf(b), -ub);
359}
360
361// l => (a + b <= ub).
362inline std::function<void(Model*)> ConditionalSum2LowerOrEqual(
363 IntegerVariable a, IntegerVariable b, int64_t ub,
364 const std::vector<Literal>& enforcement_literals) {
365 return [=](Model* model) {
367 p->AddPrecedenceWithAllOptions(a, NegationOf(b), IntegerValue(-ub),
368 kNoIntegerVariable, enforcement_literals);
369 };
370}
371
372// a + b + c <= ub.
373inline std::function<void(Model*)> Sum3LowerOrEqual(IntegerVariable a,
374 IntegerVariable b,
375 IntegerVariable c,
376 int64_t ub) {
377 return [=](Model* model) {
379 p->AddPrecedenceWithAllOptions(a, NegationOf(c), IntegerValue(-ub), b, {});
380 };
381}
382
383// l => (a + b + c <= ub).
384inline std::function<void(Model*)> ConditionalSum3LowerOrEqual(
385 IntegerVariable a, IntegerVariable b, IntegerVariable c, int64_t ub,
386 const std::vector<Literal>& enforcement_literals) {
387 return [=](Model* model) {
389 p->AddPrecedenceWithAllOptions(a, NegationOf(c), IntegerValue(-ub), b,
390 enforcement_literals);
391 };
392}
393
394// a >= b.
395inline std::function<void(Model*)> GreaterOrEqual(IntegerVariable a,
396 IntegerVariable b) {
397 return [=](Model* model) {
398 return model->GetOrCreate<PrecedencesPropagator>()->AddPrecedence(b, a);
399 };
400}
401
402// a == b.
403inline std::function<void(Model*)> Equality(IntegerVariable a,
404 IntegerVariable b) {
405 return [=](Model* model) {
406 model->Add(LowerOrEqual(a, b));
407 model->Add(LowerOrEqual(b, a));
408 };
409}
410
411// a + offset == b.
412inline std::function<void(Model*)> EqualityWithOffset(IntegerVariable a,
413 IntegerVariable b,
414 int64_t offset) {
415 return [=](Model* model) {
416 model->Add(LowerOrEqualWithOffset(a, b, offset));
417 model->Add(LowerOrEqualWithOffset(b, a, -offset));
418 };
419}
420
421// is_le => (a + offset <= b).
422inline std::function<void(Model*)> ConditionalLowerOrEqualWithOffset(
423 IntegerVariable a, IntegerVariable b, int64_t offset, Literal is_le) {
424 return [=](Model* model) {
426 p->AddConditionalPrecedenceWithOffset(a, b, IntegerValue(offset), is_le);
427 };
428}
429
430// is_le => (a <= b).
431inline std::function<void(Model*)> ConditionalLowerOrEqual(IntegerVariable a,
432 IntegerVariable b,
433 Literal is_le) {
434 return ConditionalLowerOrEqualWithOffset(a, b, 0, is_le);
435}
436
437// literals => (a <= b).
438inline std::function<void(Model*)> ConditionalLowerOrEqual(
439 IntegerVariable a, IntegerVariable b, absl::Span<const Literal> literals) {
440 return [=](Model* model) {
442 p->AddPrecedenceWithAllOptions(a, b, IntegerValue(0),
443 /*offset_var*/ kNoIntegerVariable, literals);
444 };
445}
446
447// is_le <=> (a + offset <= b).
448inline std::function<void(Model*)> ReifiedLowerOrEqualWithOffset(
449 IntegerVariable a, IntegerVariable b, int64_t offset, Literal is_le) {
450 return [=](Model* model) {
452 p->AddConditionalPrecedenceWithOffset(a, b, IntegerValue(offset), is_le);
453
454 // The negation of (a + offset <= b) is (a + offset > b) which can be
455 // rewritten as (b + 1 - offset <= a).
456 p->AddConditionalPrecedenceWithOffset(b, a, IntegerValue(1 - offset),
457 is_le.Negated());
458 };
459}
460
461// is_eq <=> (a == b).
462inline std::function<void(Model*)> ReifiedEquality(IntegerVariable a,
463 IntegerVariable b,
464 Literal is_eq) {
465 return [=](Model* model) {
466 // We creates two extra Boolean variables in this case.
467 //
468 // TODO(user): Avoid creating them if we already have some literal that
469 // have the same meaning. For instance if a client also wanted to know if
470 // a <= b, he would have called ReifiedLowerOrEqualWithOffset() directly.
471 const Literal is_le = Literal(model->Add(NewBooleanVariable()), true);
472 const Literal is_ge = Literal(model->Add(NewBooleanVariable()), true);
473 model->Add(ReifiedBoolAnd({is_le, is_ge}, is_eq));
474 model->Add(ReifiedLowerOrEqualWithOffset(a, b, 0, is_le));
475 model->Add(ReifiedLowerOrEqualWithOffset(b, a, 0, is_ge));
476 };
477}
478
479// is_eq <=> (a + offset == b).
480inline std::function<void(Model*)> ReifiedEqualityWithOffset(IntegerVariable a,
481 IntegerVariable b,
482 int64_t offset,
483 Literal is_eq) {
484 return [=](Model* model) {
485 // We creates two extra Boolean variables in this case.
486 //
487 // TODO(user): Avoid creating them if we already have some literal that
488 // have the same meaning. For instance if a client also wanted to know if
489 // a <= b, he would have called ReifiedLowerOrEqualWithOffset() directly.
490 const Literal is_le = Literal(model->Add(NewBooleanVariable()), true);
491 const Literal is_ge = Literal(model->Add(NewBooleanVariable()), true);
492 model->Add(ReifiedBoolAnd({is_le, is_ge}, is_eq));
493 model->Add(ReifiedLowerOrEqualWithOffset(a, b, offset, is_le));
494 model->Add(ReifiedLowerOrEqualWithOffset(b, a, -offset, is_ge));
495 };
496}
497
498// a != b.
499inline std::function<void(Model*)> NotEqual(IntegerVariable a,
500 IntegerVariable b) {
501 return [=](Model* model) {
502 // We have two options (is_gt or is_lt) and one must be true.
503 const Literal is_lt = Literal(model->Add(NewBooleanVariable()), true);
504 const Literal is_gt = is_lt.Negated();
505 model->Add(ConditionalLowerOrEqualWithOffset(a, b, 1, is_lt));
506 model->Add(ConditionalLowerOrEqualWithOffset(b, a, 1, is_gt));
507 };
508}
509
510} // namespace sat
511} // namespace operations_research
512
513#endif // OR_TOOLS_SAT_PRECEDENCES_H_
void SetPropagatorPriority(int id, int priority)
Definition: integer.cc:2051
void RegisterWatcher(SparseBitset< IntegerVariable > *p)
Definition: integer.h:917
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:42
void AddPrecedenceReason(int arc_index, IntegerValue min_offset, std::vector< Literal > *literal_reason, std::vector< IntegerLiteral > *integer_reason) const
Definition: precedences.cc:224
void AddConditionalPrecedence(IntegerVariable i1, IntegerVariable i2, Literal l)
Definition: precedences.h:309
void AddConditionalPrecedenceWithOffset(IntegerVariable i1, IntegerVariable i2, IntegerValue offset, Literal l)
Definition: precedences.h:316
void AddPrecedenceWithOffset(IntegerVariable i1, IntegerVariable i2, IntegerValue offset)
Definition: precedences.h:304
void AddPrecedenceWithAllOptions(IntegerVariable i1, IntegerVariable i2, IntegerValue offset, IntegerVariable offset_var, absl::Span< const Literal > presence_literals)
Definition: precedences.h:326
void ComputePrecedences(const std::vector< IntegerVariable > &vars, std::vector< IntegerPrecedences > *output)
Definition: precedences.cc:147
void AddPrecedence(IntegerVariable i1, IntegerVariable i2)
Definition: precedences.h:298
void AddPrecedenceWithVariableOffset(IntegerVariable i1, IntegerVariable i2, IntegerVariable offset_var)
Definition: precedences.h:321
void Untrail(const Trail &trail, int trail_index) final
Definition: precedences.cc:123
bool PropagateOutgoingArcs(IntegerVariable var)
Definition: precedences.cc:108
int64_t b
int64_t a
IntVar * var
Definition: expr_array.cc:1874
double lower_bound
GRBmodel * model
int arc
Definition: cleanup.h:22
std::function< void(Model *)> Equality(IntegerVariable v, int64_t value)
Definition: integer.h:1721
std::function< void(Model *)> LowerOrEqualWithOffset(IntegerVariable a, IntegerVariable b, int64_t offset)
Definition: precedences.h:345
std::function< void(Model *)> ConditionalLowerOrEqual(IntegerVariable a, IntegerVariable b, Literal is_le)
Definition: precedences.h:431
std::function< BooleanVariable(Model *)> NewBooleanVariable()
Definition: integer.h:1608
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
Definition: integer.h:1706
std::function< void(Model *)> Sum2LowerOrEqual(IntegerVariable a, IntegerVariable b, int64_t ub)
Definition: precedences.h:355
const IntegerVariable kNoIntegerVariable(-1)
std::function< void(Model *)> NotEqual(IntegerVariable a, IntegerVariable b)
Definition: precedences.h:499
std::function< void(Model *)> EqualityWithOffset(IntegerVariable a, IntegerVariable b, int64_t offset)
Definition: precedences.h:412
std::function< void(Model *)> ReifiedBoolAnd(const std::vector< Literal > &literals, Literal r)
Definition: sat_solver.h:999
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Definition: integer.cc:47
std::function< void(Model *)> GreaterOrEqual(IntegerVariable v, int64_t lb)
Definition: integer.h:1691
std::function< void(Model *)> ConditionalSum2LowerOrEqual(IntegerVariable a, IntegerVariable b, int64_t ub, const std::vector< Literal > &enforcement_literals)
Definition: precedences.h:362
std::function< void(Model *)> Sum3LowerOrEqual(IntegerVariable a, IntegerVariable b, IntegerVariable c, int64_t ub)
Definition: precedences.h:373
std::function< void(Model *)> ReifiedLowerOrEqualWithOffset(IntegerVariable a, IntegerVariable b, int64_t offset, Literal is_le)
Definition: precedences.h:448
std::function< void(Model *)> ReifiedEqualityWithOffset(IntegerVariable a, IntegerVariable b, int64_t offset, Literal is_eq)
Definition: precedences.h:480
std::function< void(Model *)> ConditionalSum3LowerOrEqual(IntegerVariable a, IntegerVariable b, IntegerVariable c, int64_t ub, const std::vector< Literal > &enforcement_literals)
Definition: precedences.h:384
std::function< void(Model *)> ConditionalLowerOrEqualWithOffset(IntegerVariable a, IntegerVariable b, int64_t offset, Literal is_le)
Definition: precedences.h:422
std::function< void(Model *)> ReifiedEquality(IntegerVariable a, IntegerVariable b, Literal is_eq)
Definition: precedences.h:462
Collection of objects used to extend the Constraint Solver library.
int64_t tail
int64_t head