24#include "absl/container/flat_hash_map.h"
25#include "absl/strings/str_format.h"
26#include "absl/strings/str_join.h"
41struct AffineTransformation {
42 AffineTransformation() :
a(1),
b(0) {}
43 AffineTransformation(int64_t aa, int64_t bb) :
a(aa),
b(bb) {
49 bool Reverse(int64_t
value, int64_t*
const reverse)
const {
50 const int64_t temp =
value -
b;
60 int64_t Forward(int64_t
value)
const {
return value *
a +
b; }
62 int64_t UnsafeReverse(int64_t
value)
const {
return (
value -
b) /
a; }
69 std::string DebugString()
const {
70 return absl::StrFormat(
"(%d * x + %d)",
a,
b);
75class VarLinearizer :
public ModelParser {
77 VarLinearizer() :
target_var_(nullptr), transformation_(nullptr) {}
78 ~VarLinearizer()
override {}
80 void VisitIntegerVariable(
const IntVar*
const variable,
81 const std::string& operation, int64_t
value,
82 IntVar*
const delegate)
override {
85 delegate->Accept(
this);
89 delegate->Accept(
this);
92 PushMultiplier(
value);
93 delegate->Accept(
this);
97 transformation_->a = multipliers_.back();
101 void VisitIntegerVariable(
const IntVar*
const variable,
102 IntExpr*
const delegate)
override {
104 transformation_->a = multipliers_.back();
107 void Visit(
const IntVar*
const var, IntVar**
const target_var,
108 AffineTransformation*
const transformation) {
110 transformation_ = transformation;
111 transformation->Clear();
115 CHECK(multipliers_.empty());
118 std::string DebugString()
const override {
return "VarLinearizer"; }
121 void AddConstant(int64_t
constant) {
122 transformation_->b +=
constant * multipliers_.back();
125 void PushMultiplier(int64_t multiplier) {
126 if (multipliers_.empty()) {
127 multipliers_.push_back(multiplier);
129 multipliers_.push_back(multiplier * multipliers_.back());
133 void PopMultiplier() { multipliers_.pop_back(); }
135 std::vector<int64_t> multipliers_;
137 AffineTransformation* transformation_;
140static const int kBitsInUint64 = 64;
156class BasePositiveTableConstraint :
public Constraint {
158 BasePositiveTableConstraint(Solver*
const s,
const std::vector<IntVar*>& vars,
159 const IntTupleSet& tuples)
167 transformations_(
arity_) {
177 VarLinearizer linearizer;
178 for (
int i = 0; i <
arity_; ++i) {
179 linearizer.Visit(vars[i], &
vars_[i], &transformations_[i]);
182 for (
int i = 0; i <
arity_; ++i) {
188 ~BasePositiveTableConstraint()
override {}
190 std::string DebugString()
const override {
191 return absl::StrFormat(
"AllowedAssignments(arity = %d, tuple_count = %d)",
195 void Accept(ModelVisitor*
const visitor)
const override {
204 bool TupleValue(
int tuple_index,
int var_index, int64_t*
const value)
const {
205 return transformations_[var_index].Reverse(
206 tuples_.Value(tuple_index, var_index),
value);
209 int64_t UnsafeTupleValue(
int tuple_index,
int var_index)
const {
210 return transformations_[var_index].UnsafeReverse(
211 tuples_.Value(tuple_index, var_index));
214 bool IsTupleSupported(
int tuple_index) {
215 for (
int var_index = 0; var_index <
arity_; ++var_index) {
217 if (!TupleValue(tuple_index, var_index, &
value) ||
234 const IntTupleSet tuples_;
237 std::vector<AffineTransformation> transformations_;
240class PositiveTableConstraint :
public BasePositiveTableConstraint {
242 typedef absl::flat_hash_map<int, std::vector<uint64_t>> ValueBitset;
244 PositiveTableConstraint(Solver*
const s,
const std::vector<IntVar*>& vars,
245 const IntTupleSet& tuples)
246 : BasePositiveTableConstraint(s, vars, tuples),
250 ~PositiveTableConstraint()
override {}
252 void Post()
override {
254 solver(),
this, &PositiveTableConstraint::Propagate,
"Propagate");
255 for (
int i = 0; i <
arity_; ++i) {
256 vars_[i]->WhenDomain(d);
258 solver(),
this, &PositiveTableConstraint::Update,
"Update", i);
259 vars_[i]->WhenDomain(u);
269 for (
int tuple_index = 0; tuple_index <
tuple_count_; ++tuple_index) {
270 if (IsTupleSupported(tuple_index)) {
271 SetBit64(actives.data(), tuple_index);
277 void InitialPropagate()
override {
279 for (
int var_index = 0; var_index <
arity_; ++var_index) {
280 for (
const auto& it :
masks_[var_index]) {
281 if (!
vars_[var_index]->Contains(it.first)) {
290 for (
int var_index = 0; var_index <
arity_; ++var_index) {
291 const ValueBitset& mask =
masks_[var_index];
292 IntVar*
const var =
vars_[var_index];
295 if (!mask.contains(
value)) {
306 for (
int var_index = 0; var_index <
arity_; ++var_index) {
307 IntVar*
const var =
vars_[var_index];
310 if (!Supported(var_index,
value)) {
320 void Update(
int index) {
323 const int64_t old_max =
var->OldMax();
324 const int64_t vmin =
var->Min();
325 const int64_t vmax =
var->Max();
327 const auto& it = var_masks.find(
value);
328 if (it != var_masks.end()) {
329 BlankActives(it->second);
333 const auto& it = var_masks.find(
value);
334 if (it != var_masks.end()) {
335 BlankActives(it->second);
339 const auto& it = var_masks.find(
value);
340 if (it != var_masks.end()) {
341 BlankActives(it->second);
346 void BlankActives(
const std::vector<uint64_t>& mask) {
355 bool Supported(
int var_index, int64_t
value) {
359 const std::vector<uint64_t>& mask =
masks_[var_index][
value];
364 std::string DebugString()
const override {
365 return absl::StrFormat(
"PositiveTableConstraint([%s], %d tuples)",
370 void InitializeMask(
int tuple_index) {
371 std::vector<int64_t> cache(
arity_);
372 for (
int var_index = 0; var_index <
arity_; ++var_index) {
373 if (!TupleValue(tuple_index, var_index, &cache[var_index])) {
377 for (
int var_index = 0; var_index <
arity_; ++var_index) {
378 const int64_t
value = cache[var_index];
379 std::vector<uint64_t>& mask =
masks_[var_index][
value];
395class CompactPositiveTableConstraint :
public BasePositiveTableConstraint {
397 CompactPositiveTableConstraint(Solver*
const s,
398 const std::vector<IntVar*>& vars,
399 const IntTupleSet& tuples)
400 : BasePositiveTableConstraint(s, vars, tuples),
413 ~CompactPositiveTableConstraint()
override {}
415 void Post()
override {
417 solver(),
this, &CompactPositiveTableConstraint::Propagate,
419 for (
int i = 0; i <
arity_; ++i) {
421 solver(),
this, &CompactPositiveTableConstraint::Update,
"Update", i);
422 vars_[i]->WhenDomain(u);
424 for (
int i = 0; i <
arity_; ++i) {
425 var_sizes_.SetValue(solver(), i,
vars_[i]->Size());
429 void InitialPropagate()
override {
431 FillMasksAndActiveTuples();
432 ComputeMasksBoundaries();
434 RemoveUnsupportedValues();
441 if (touched_var_ == -2) {
448 for (
int var_index = 0; var_index <
arity_; ++var_index) {
453 if (var_index == touched_var_) {
457 IntVar*
const var =
vars_[var_index];
458 const int64_t original_min = original_min_[var_index];
459 const int64_t var_size =
var->Size();
464 if (!Supported(var_index,
var->Min() - original_min)) {
470 const int64_t var_min =
var->Min();
471 const int64_t var_max =
var->Max();
472 const bool min_support = Supported(var_index, var_min - original_min);
473 const bool max_support = Supported(var_index, var_max - original_min);
478 var->SetValue(var_max);
479 var_sizes_.SetValue(solver(), var_index, 1);
481 }
else if (!max_support) {
482 var->SetValue(var_min);
483 var_sizes_.SetValue(solver(), var_index, 1);
489 const int64_t var_min =
var->Min();
490 const int64_t var_max =
var->Max();
491 int64_t new_min = var_min;
492 int64_t new_max = var_max;
496 if (var_max - var_min + 1 == var_size) {
497 for (; new_min <= var_max; ++new_min) {
498 if (Supported(var_index, new_min - original_min)) {
502 for (; new_max >= new_min; --new_max) {
503 if (Supported(var_index, new_max - original_min)) {
507 var->SetRange(new_min, new_max);
509 if (!Supported(var_index,
value - original_min)) {
518 for (
const int64_t
value :
520 if (!Supported(var_index,
value - original_min)) {
531 var->SetRange(new_min, new_max);
540 var_sizes_.SetValue(solver(), var_index,
var->Size());
546 void Update(
int var_index) {
547 if (
vars_[var_index]->Size() == var_sizes_.Value(var_index)) {
554 IntVar*
const var =
vars_[var_index];
555 bool changed =
false;
556 const int64_t omin = original_min_[var_index];
557 const int64_t var_size =
var->Size();
558 const int64_t var_min =
var->Min();
559 const int64_t var_max =
var->Max();
563 changed = AndMaskWithActive(
masks_[var_index][var_min - omin]);
567 SetTempMask(var_index, var_min - omin);
568 OrTempMask(var_index, var_max - omin);
573 const int64_t estimated_hole_size =
574 var_sizes_.Value(var_index) - var_size;
575 const int64_t old_min =
var->OldMin();
576 const int64_t old_max =
var->OldMax();
579 const int64_t number_of_operations =
580 estimated_hole_size + var_min - old_min + old_max - var_max;
581 if (number_of_operations < var_size) {
584 changed |= SubtractMaskFromActive(
masks_[var_index][
value - omin]);
586 for (
const int64_t
value : InitAndGetValues(
holes_[var_index])) {
587 changed |= SubtractMaskFromActive(
masks_[var_index][
value - omin]);
590 changed |= SubtractMaskFromActive(
masks_[var_index][
value - omin]);
596 if (var_max - var_min + 1 == var_size) {
598 OrTempMask(var_index,
value - omin);
601 for (
const int64_t
value :
603 OrTempMask(var_index,
value - omin);
611 var_sizes_.SetValue(solver(), var_index, var_size);
616 if (touched_var_ == -1 || touched_var_ == var_index) {
617 touched_var_ = var_index;
621 EnqueueDelayedDemon(demon_);
625 std::string DebugString()
const override {
626 return absl::StrFormat(
"CompactPositiveTableConstraint([%s], %d tuples)",
635 for (
int i = 0; i <
arity_; ++i) {
636 original_min_[i] =
vars_[i]->Min();
637 const int64_t span =
vars_[i]->Max() - original_min_[i] + 1;
642 void FillMasksAndActiveTuples() {
644 for (
int tuple_index = 0; tuple_index <
tuple_count_; ++tuple_index) {
645 if (IsTupleSupported(tuple_index)) {
646 SetBit64(actives.data(), tuple_index);
648 for (
int var_index = 0; var_index <
arity_; ++var_index) {
649 const int64_t
value = UnsafeTupleValue(tuple_index, var_index);
650 const int64_t value_index =
value - original_min_[var_index];
653 if (
masks_[var_index][value_index].empty()) {
663 void RemoveUnsupportedValues() {
665 for (
int var_index = 0; var_index <
arity_; ++var_index) {
666 IntVar*
const var =
vars_[var_index];
669 if (
masks_[var_index][
value - original_min_[var_index]].empty()) {
679 void ComputeMasksBoundaries() {
680 for (
int var_index = 0; var_index <
arity_; ++var_index) {
681 mask_starts_[var_index].resize(
masks_[var_index].size());
682 mask_ends_[var_index].resize(
masks_[var_index].size());
683 for (
int value_index = 0; value_index <
masks_[var_index].size();
685 const std::vector<uint64_t>& mask =
masks_[var_index][value_index];
701 mask_starts_[var_index][value_index] =
start;
702 mask_ends_[var_index][value_index] =
end;
707 void BuildSupports() {
708 for (
int var_index = 0; var_index <
arity_; ++var_index) {
715 bool AndMaskWithActive(
const std::vector<uint64_t>& mask) {
723 bool SubtractMaskFromActive(
const std::vector<uint64_t>& mask) {
731 bool Supported(
int var_index, int64_t value_index) {
736 const std::vector<uint64_t>& mask =
masks_[var_index][value_index];
741 void OrTempMask(
int var_index, int64_t value_index) {
742 const std::vector<uint64_t>& mask =
masks_[var_index][value_index];
744 const int mask_span = mask_ends_[var_index][value_index] -
745 mask_starts_[var_index][value_index] + 1;
751 for (
int i = mask_starts_[var_index][value_index];
752 i <= mask_ends_[var_index][value_index]; ++i) {
759 void SetTempMask(
int var_index, int64_t value_index) {
774 void ClearTempMask() {
790 std::vector<std::vector<std::vector<uint64_t>>>
masks_;
792 std::vector<std::vector<int>> mask_starts_;
793 std::vector<std::vector<int>> mask_ends_;
795 std::vector<int64_t> original_min_;
803 RevArray<int64_t> var_sizes_;
810class SmallCompactPositiveTableConstraint :
public BasePositiveTableConstraint {
812 SmallCompactPositiveTableConstraint(Solver*
const s,
813 const std::vector<IntVar*>& vars,
814 const IntTupleSet& tuples)
815 : BasePositiveTableConstraint(s, vars, tuples),
824 CHECK_LE(tuples.NumTuples(), kBitsInUint64);
827 ~SmallCompactPositiveTableConstraint()
override {}
829 void Post()
override {
831 solver(),
this, &SmallCompactPositiveTableConstraint::Propagate,
833 for (
int i = 0; i <
arity_; ++i) {
834 if (!
vars_[i]->Bound()) {
836 solver(),
this, &SmallCompactPositiveTableConstraint::Update,
838 vars_[i]->WhenDomain(update_demon);
846 for (
int i = 0; i <
arity_; ++i) {
847 original_min_[i] =
vars_[i]->Min();
848 const int64_t span =
vars_[i]->Max() - original_min_[i] + 1;
849 masks_[i].assign(span, 0);
853 bool IsTupleSupported(
int tuple_index) {
854 for (
int var_index = 0; var_index <
arity_; ++var_index) {
856 if (!TupleValue(tuple_index, var_index, &
value) ||
864 void ComputeActiveTuples() {
867 for (
int tuple_index = 0; tuple_index <
tuple_count_; ++tuple_index) {
868 if (IsTupleSupported(tuple_index)) {
869 const uint64_t local_mask =
OneBit64(tuple_index);
871 for (
int var_index = 0; var_index <
arity_; ++var_index) {
872 const int64_t
value = UnsafeTupleValue(tuple_index, var_index);
873 masks_[var_index][
value - original_min_[var_index]] |= local_mask;
882 void RemoveUnsupportedValues() {
884 for (
int var_index = 0; var_index <
arity_; ++var_index) {
885 IntVar*
const var =
vars_[var_index];
886 const int64_t original_min = original_min_[var_index];
889 if (
masks_[var_index][
value - original_min] == 0) {
899 void InitialPropagate()
override {
901 ComputeActiveTuples();
902 RemoveUnsupportedValues();
912 if (touched_var_ == -2) {
920 for (
int var_index = 0; var_index <
arity_; ++var_index) {
925 if (var_index == touched_var_) {
929 const std::vector<uint64_t>& var_mask =
masks_[var_index];
930 const int64_t original_min = original_min_[var_index];
931 IntVar*
const var =
vars_[var_index];
932 const int64_t var_size =
var->Size();
935 if ((var_mask[
var->Min() - original_min] & actives) == 0) {
945 const int64_t var_min =
var->Min();
946 const int64_t var_max =
var->Max();
947 const bool min_support =
948 (var_mask[var_min - original_min] & actives) != 0;
949 const bool max_support =
950 (var_mask[var_max - original_min] & actives) != 0;
951 if (!min_support && !max_support) {
953 }
else if (!min_support) {
954 var->SetValue(var_max);
955 }
else if (!max_support) {
956 var->SetValue(var_min);
962 const int64_t var_min =
var->Min();
963 const int64_t var_max =
var->Max();
964 int64_t new_min = var_min;
965 int64_t new_max = var_max;
966 if (var_max - var_min + 1 == var_size) {
968 for (; new_min <= var_max; ++new_min) {
969 if ((var_mask[new_min - original_min] & actives) != 0) {
973 for (; new_max >= new_min; --new_max) {
974 if ((var_mask[new_max - original_min] & actives) != 0) {
978 var->SetRange(new_min, new_max);
980 if ((var_mask[
value - original_min] & actives) == 0) {
985 bool min_set =
false;
987 for (
const int64_t
value :
991 if ((var_mask[
value - original_min] & actives) == 0) {
1005 var->SetRange(new_min, new_max);
1017 void Update(
int var_index) {
1021 IntVar*
const var =
vars_[var_index];
1022 const int64_t original_min = original_min_[var_index];
1023 const int64_t var_size =
var->Size();
1026 ApplyMask(var_index,
masks_[var_index][
var->Min() - original_min]);
1030 ApplyMask(var_index,
masks_[var_index][
var->Min() - original_min] |
1031 masks_[var_index][
var->Max() - original_min]);
1037 const std::vector<uint64_t>& var_mask =
masks_[var_index];
1038 const int64_t old_min =
var->OldMin();
1039 const int64_t old_max =
var->OldMax();
1040 const int64_t var_min =
var->Min();
1041 const int64_t var_max =
var->Max();
1042 const bool contiguous = var_size == var_max - var_min + 1;
1043 const bool nearly_contiguous =
1044 var_size > (var_max - var_min + 1) * 7 / 10;
1051 uint64_t hole_mask = 0;
1053 for (
const int64_t
value : InitAndGetValues(
holes_[var_index])) {
1054 hole_mask |= var_mask[
value - original_min];
1057 const int64_t hole_operations = var_min - old_min + old_max - var_max;
1059 const int64_t domain_operations = contiguous ? var_size : 4 * var_size;
1060 if (hole_operations < domain_operations) {
1062 hole_mask |= var_mask[
value - original_min];
1065 hole_mask |= var_mask[
value - original_min];
1068 ApplyMask(var_index, ~hole_mask);
1070 uint64_t domain_mask = 0;
1073 domain_mask |= var_mask[
value - original_min];
1075 }
else if (nearly_contiguous) {
1078 domain_mask |= var_mask[
value - original_min];
1082 for (
const int64_t
value :
1084 domain_mask |= var_mask[
value - original_min];
1087 ApplyMask(var_index, domain_mask);
1093 std::string DebugString()
const override {
1094 return absl::StrFormat(
1095 "SmallCompactPositiveTableConstraint([%s], %d tuples)",
1100 void ApplyMask(
int var_index, uint64_t mask) {
1103 const uint64_t current_stamp = solver()->stamp();
1104 if (
stamp_ < current_stamp) {
1111 if (touched_var_ == -1 || touched_var_ == var_index) {
1112 touched_var_ = var_index;
1116 EnqueueDelayedDemon(demon_);
1130 std::vector<std::vector<uint64_t>>
masks_;
1132 std::vector<int64_t> original_min_;
1137bool HasCompactDomains(
const std::vector<IntVar*>& vars) {
1148class TransitionConstraint :
public Constraint {
1153 TransitionConstraint(Solver*
const s,
const std::vector<IntVar*>& vars,
1154 const IntTupleSet& transition_table,
1155 int64_t initial_state,
1156 const std::vector<int64_t>& final_states)
1159 transition_table_(transition_table),
1160 initial_state_(initial_state),
1161 final_states_(final_states) {}
1163 TransitionConstraint(Solver*
const s,
const std::vector<IntVar*>& vars,
1164 const IntTupleSet& transition_table,
1165 int64_t initial_state,
1166 const std::vector<int>& final_states)
1169 transition_table_(transition_table),
1170 initial_state_(initial_state),
1171 final_states_(final_states.size()) {
1172 for (
int i = 0; i < final_states.size(); ++i) {
1173 final_states_[i] = final_states[i];
1177 ~TransitionConstraint()
override {}
1179 void Post()
override {
1180 Solver*
const s = solver();
1183 const int nb_vars =
vars_.size();
1184 for (
int i = 0; i < transition_table_.NumTuples(); ++i) {
1195 std::vector<IntVar*> states;
1196 states.push_back(s->MakeIntConst(initial_state_));
1197 for (
int var_index = 1; var_index < nb_vars; ++var_index) {
1198 states.push_back(s->MakeIntVar(state_min, state_max));
1200 states.push_back(s->MakeIntVar(final_states_));
1201 CHECK_EQ(nb_vars + 1, states.size());
1203 const int num_tuples = transition_table_.NumTuples();
1205 for (
int var_index = 0; var_index < nb_vars; ++var_index) {
1206 std::vector<IntVar*> tmp_vars(3);
1207 tmp_vars[0] = states[var_index];
1208 tmp_vars[1] =
vars_[var_index];
1209 tmp_vars[2] = states[var_index + 1];
1211 if (num_tuples <= kBitsInUint64) {
1212 s->AddConstraint(s->RevAlloc(
new SmallCompactPositiveTableConstraint(
1213 s, tmp_vars, transition_table_)));
1215 s->AddConstraint(s->RevAlloc(
new CompactPositiveTableConstraint(
1216 s, tmp_vars, transition_table_)));
1221 void InitialPropagate()
override {}
1223 void Accept(ModelVisitor*
const visitor)
const override {
1235 std::string DebugString()
const override {
1236 return absl::StrFormat(
1237 "TransitionConstraint([%s], %d transitions, initial = %d, final = "
1240 initial_state_, absl::StrJoin(final_states_,
", "));
1245 const std::vector<IntVar*>
vars_;
1247 const IntTupleSet transition_table_;
1249 const int64_t initial_state_;
1251 std::vector<int64_t> final_states_;
1263 if (HasCompactDomains(vars)) {
1264 if (tuples.
NumTuples() < kBitsInUint64 && parameters_.use_small_table()) {
1266 new SmallCompactPositiveTableConstraint(
this, vars, tuples));
1268 return RevAlloc(
new CompactPositiveTableConstraint(
this, vars, tuples));
1271 return RevAlloc(
new PositiveTableConstraint(
this, vars, tuples));
1275 const std::vector<IntVar*>& vars,
const IntTupleSet& transition_table,
1276 int64_t initial_state,
const std::vector<int64_t>& final_states) {
1277 return RevAlloc(
new TransitionConstraint(
this, vars, transition_table,
1278 initial_state, final_states));
1282 const std::vector<IntVar*>& vars,
const IntTupleSet& transition_table,
1283 int64_t initial_state,
const std::vector<int>& final_states) {
1284 return RevAlloc(
new TransitionConstraint(
this, vars, transition_table,
1285 initial_state, final_states));
#define DCHECK_LE(val1, val2)
#define DCHECK_NE(val1, val2)
#define CHECK_EQ(val1, val2)
#define CHECK_GE(val1, val2)
#define DCHECK_GE(val1, val2)
#define CHECK_NE(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK(condition)
#define CHECK_LE(val1, val2)
#define DCHECK_EQ(val1, val2)
A constraint is the main modeling object.
static const char kFinalStatesArgument[]
static const char kProductOperation[]
static const char kTraceOperation[]
static const char kTransition[]
static const char kTuplesArgument[]
static const char kAllowedAssignments[]
static const char kDifferenceOperation[]
static const char kVarsArgument[]
static const char kSumOperation[]
static const char kInitialState[]
Constraint * MakeTransitionConstraint(const std::vector< IntVar * > &vars, const IntTupleSet &transition_table, int64_t initial_state, const std::vector< int64_t > &final_states)
This constraint create a finite automaton that will check the sequence of variables vars.
Constraint * MakeAllowedAssignments(const std::vector< IntVar * > &vars, const IntTupleSet &tuples)
This method creates a constraint where the graph of the relation between the variables is given in ex...
T * RevAlloc(T *object)
Registers the given object as being reversible.
static const int kTransitionTupleSize
static const int kStatePosition
static const int kNextStatePosition
std::vector< ValueBitset > masks_
std::vector< IntVar * > vars_
std::vector< IntVarIterator * > holes_
std::vector< int64_t > to_remove_
std::vector< uint64_t > temp_mask_
UnsortedNullableRevBitset active_tuples_
std::vector< IntVarIterator * > iterators_
std::vector< int > supports_
Collection of objects used to extend the Constraint Solver library.
Demon * MakeDelayedConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
std::string JoinDebugStringPtr(const std::vector< T > &v, const std::string &separator)
uint64_t OneBit64(int pos)
uint64_t BitLength64(uint64_t size)
Demon * MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
void SetBit64(uint64_t *const bitset, uint64_t pos)
BeginEndReverseIteratorWrapper< Container > Reverse(const Container &c)
IntervalVar *const target_var_
std::optional< int64_t > end