27 num_vars_with_negation_ = 2 * num_variables;
28 partition_ = absl::make_unique<DynamicPartition>(num_vars_with_negation_);
30 can_freely_decrease_.
assign(num_vars_with_negation_,
true);
32 shared_buffer_.clear();
33 initial_candidates_.
assign(num_vars_with_negation_, IntegerVariableSpan());
36 dominating_vars_.
assign(num_vars_with_negation_, IntegerVariableSpan());
38 ct_index_for_signature_ = 0;
39 block_down_signatures_.
assign(num_vars_with_negation_, 0);
42 void VarDomination::RefinePartition(std::vector<int>* vars) {
43 if (vars->empty())
return;
44 partition_->Refine(*vars);
45 for (
int&
var : *vars) {
46 const IntegerVariable wrapped(
var);
47 can_freely_decrease_[wrapped] =
false;
48 can_freely_decrease_[
NegationOf(wrapped)] =
false;
51 partition_->Refine(*vars);
55 if (phase_ != 0)
return;
57 for (
const int ref : refs) {
60 RefinePartition(&tmp_vars_);
65 absl::Span<const int64_t> coeffs) {
66 if (phase_ != 0)
return;
67 FillTempRanks(
false, {}, refs,
70 for (
int i = 0; i < tmp_ranks_.size(); ++i) {
71 if (i > 0 && tmp_ranks_[i].rank != tmp_ranks_[i - 1].rank) {
72 RefinePartition(&tmp_vars_);
75 tmp_vars_.push_back(tmp_ranks_[i].
var.value());
77 RefinePartition(&tmp_vars_);
82 void VarDomination::ProcessTempRanks() {
86 ++ct_index_for_signature_;
87 for (IntegerVariableWithRank& entry : tmp_ranks_) {
88 can_freely_decrease_[entry.var] =
false;
89 block_down_signatures_[entry.var] |= uint64_t{1}
90 << (ct_index_for_signature_ % 64);
91 entry.part = partition_->PartOf(entry.var.value());
94 tmp_ranks_.begin(), tmp_ranks_.end(),
95 [](
const IntegerVariableWithRank&
a,
const IntegerVariableWithRank&
b) {
96 return a.part <
b.part;
99 for (
int i = 1; i < tmp_ranks_.size(); ++i) {
100 if (tmp_ranks_[i].part != tmp_ranks_[start].part) {
101 Initialize({&tmp_ranks_[start], static_cast<size_t>(i - start)});
105 if (start < tmp_ranks_.size()) {
106 Initialize({&tmp_ranks_[start], tmp_ranks_.size() - start});
108 }
else if (phase_ == 1) {
109 FilterUsingTempRanks();
112 CheckUsingTempRanks();
117 absl::Span<const int> enforcements, absl::Span<const int> refs,
118 absl::Span<const int64_t> coeffs) {
119 FillTempRanks(
false, enforcements, refs, coeffs);
124 absl::Span<const int> enforcements, absl::Span<const int> refs,
125 absl::Span<const int64_t> coeffs) {
126 FillTempRanks(
true, enforcements, refs, coeffs);
130 void VarDomination::MakeRankEqualToStartOfPart(
131 absl::Span<IntegerVariableWithRank> span) {
132 const int size = span.size();
134 int previous_value = 0;
135 for (
int i = 0; i < size; ++i) {
136 const int64_t
value = span[i].rank;
137 if (
value != previous_value) {
138 previous_value =
value;
141 span[i].rank = start;
145 void VarDomination::Initialize(absl::Span<IntegerVariableWithRank> span) {
148 MakeRankEqualToStartOfPart(span);
150 const int future_start = shared_buffer_.size();
151 int first_start = -1;
155 const int kSizeThreshold = 1000;
156 const int size = span.size();
157 for (
int i =
std::max(0, size - kSizeThreshold); i < size; ++i) {
158 const IntegerVariableWithRank entry = span[i];
159 const int num_candidates = size - entry.rank;
160 if (num_candidates >= kSizeThreshold)
continue;
163 int size_threshold = kSizeThreshold;
166 const int var_part = partition_->PartOf(entry.var.value());
167 const int part_size = partition_->SizeOfPart(var_part);
168 size_threshold =
std::min(size_threshold, part_size);
171 const int current_num_candidates = initial_candidates_[entry.var].
size;
172 if (current_num_candidates != 0) {
173 size_threshold =
std::min(size_threshold, current_num_candidates);
176 if (num_candidates < size_threshold) {
177 if (first_start == -1) first_start = entry.rank;
178 initial_candidates_[entry.var] = {
179 future_start - first_start + static_cast<int>(entry.rank),
185 if (first_start == -1)
return;
186 for (
int i = first_start; i < size; ++i) {
187 shared_buffer_.push_back(span[i].
var);
203 const int kMaxInitialSize = 50;
204 std::vector<IntegerVariable> cropped_lists;
209 for (IntegerVariable
var(0);
var < num_vars_with_negation_; ++
var) {
210 if (can_freely_decrease_[
var])
continue;
211 const int part = partition_->PartOf(
var.value());
212 const int part_size = partition_->SizeOfPart(part);
214 const int start = buffer_.size();
217 const uint64_t var_sig = block_down_signatures_[
var];
218 const uint64_t not_var_sig = block_down_signatures_[
NegationOf(
var)];
219 const int stored_size = initial_candidates_[
var].
size;
220 if (stored_size == 0 || part_size < stored_size) {
224 for (
const int value : partition_->ElementsInPart(part)) {
225 const IntegerVariable c = IntegerVariable(
value);
230 if (++num_tested > 1000) {
231 is_cropped[
var] =
true;
232 cropped_lists.push_back(
var);
233 int extra = new_size;
234 while (extra < kMaxInitialSize) {
241 if (can_freely_decrease_[
NegationOf(c)])
continue;
242 if (var_sig & ~block_down_signatures_[c])
continue;
243 if (block_down_signatures_[
NegationOf(c)] & ~not_var_sig)
continue;
245 buffer_.push_back(c);
249 if (new_size > kMaxInitialSize) {
250 is_cropped[
var] =
true;
251 cropped_lists.push_back(
var);
260 for (
const IntegerVariable c : InitialDominatingCandidates(
var)) {
262 if (can_freely_decrease_[
NegationOf(c)])
continue;
263 if (partition_->PartOf(c.value()) != part)
continue;
264 if (var_sig & ~block_down_signatures_[c])
continue;
265 if (block_down_signatures_[
NegationOf(c)] & ~not_var_sig)
continue;
267 buffer_.push_back(c);
271 if (new_size > kMaxInitialSize) {
272 is_cropped[
var] =
true;
273 cropped_lists.push_back(
var);
279 dominating_vars_[
var] = {start, new_size};
286 for (
const IntegerVariable
var : cropped_lists) {
287 if (kMaxInitialSize / 2 < dominating_vars_[
var].size) {
288 dominating_vars_[
var].
size = kMaxInitialSize / 2;
291 for (IntegerVariable
var(0);
var < num_vars_with_negation_; ++
var) {
294 IntegerVariableSpan& s = dominating_vars_[
NegationOf(dom)];
295 if (s.size >= kMaxInitialSize)
continue;
304 for (
const IntegerVariable
var : cropped_lists) {
305 if (!is_cropped[
var])
continue;
306 IntegerVariableSpan& s = dominating_vars_[
var];
307 std::sort(&buffer_[s.start], &buffer_[s.start + s.size]);
308 const auto p = std::unique(&buffer_[s.start], &buffer_[s.start + s.size]);
309 s.size = p - &buffer_[s.start];
313 VLOG(1) <<
"Num initial list that where cropped: " << cropped_lists.size();
314 VLOG(1) <<
"Shared buffer size: " << shared_buffer_.size();
315 VLOG(1) <<
"Buffer size: " << buffer_.size();
325 shared_buffer_.clear();
326 initial_candidates_.
assign(num_vars_with_negation_, IntegerVariableSpan());
329 for (IntegerVariable
var(0);
var < num_vars_with_negation_; ++
var) {
337 for (IntegerVariable
var(0);
var < num_vars_with_negation_; ++
var) {
338 initial_candidates_[
var].start = start;
339 start += initial_candidates_[
var].
size;
340 initial_candidates_[
var].
size = 0;
342 shared_buffer_.resize(start);
345 for (IntegerVariable
var(0);
var < num_vars_with_negation_; ++
var) {
347 IntegerVariableSpan& span = initial_candidates_[
NegationOf(dom)];
354 tmp_var_to_rank_.
resize(num_vars_with_negation_, -1);
355 for (IntegerVariable
var(0);
var < num_vars_with_negation_; ++
var) {
356 for (
const IntegerVariable dom : InitialDominatingCandidates(
var)) {
357 tmp_var_to_rank_[dom] = 1;
361 IntegerVariableSpan& span = dominating_vars_[
var];
363 if (tmp_var_to_rank_[dom] != 1) {
367 buffer_[span.start + new_size++] = dom;
369 span.size = new_size;
371 for (
const IntegerVariable dom : InitialDominatingCandidates(
var)) {
372 tmp_var_to_rank_[dom] = -1;
376 VLOG(1) <<
"Transpose removed " << num_removed;
381 void VarDomination::FillTempRanks(
bool reverse_references,
382 absl::Span<const int> enforcements,
383 absl::Span<const int> refs,
384 absl::Span<const int64_t> coeffs) {
386 if (coeffs.empty()) {
388 for (
const int ref : refs) {
389 const IntegerVariable
var =
391 tmp_ranks_.push_back({
var, 0, 0});
395 for (
int i = 0; i < refs.size(); ++i) {
396 if (coeffs[i] == 0)
continue;
398 reverse_references ?
NegatedRef(refs[i]) : refs[i]);
400 tmp_ranks_.push_back({
var, 0, coeffs[i]});
405 std::sort(tmp_ranks_.begin(), tmp_ranks_.end());
406 MakeRankEqualToStartOfPart({&tmp_ranks_[0], tmp_ranks_.size()});
412 const int enforcement_rank = tmp_ranks_.size();
413 for (
const int ref : enforcements) {
414 tmp_ranks_.push_back(
421 void VarDomination::FilterUsingTempRanks() {
423 tmp_var_to_rank_.
resize(num_vars_with_negation_, -1);
424 for (
const IntegerVariableWithRank entry : tmp_ranks_) {
425 tmp_var_to_rank_[entry.var] = entry.rank;
429 for (
const IntegerVariableWithRank entry : tmp_ranks_) {
437 IntegerVariableSpan& span = dominating_vars_[entry.var];
438 if (span.size == 0)
continue;
441 if (tmp_var_to_rank_[candidate] < entry.rank)
continue;
442 buffer_[span.start + new_size++] = candidate;
444 span.size = new_size;
449 for (
const IntegerVariableWithRank entry : tmp_ranks_) {
450 tmp_var_to_rank_[entry.var] = -1;
455 void VarDomination::CheckUsingTempRanks() {
456 tmp_var_to_rank_.
resize(num_vars_with_negation_, -1);
457 for (
const IntegerVariableWithRank entry : tmp_ranks_) {
458 tmp_var_to_rank_[entry.var] = entry.rank;
462 for (IntegerVariable
var(0);
var < num_vars_with_negation_; ++
var) {
463 const int var_rank = tmp_var_to_rank_[
var];
464 const int negated_var_rank = tmp_var_to_rank_[
NegationOf(
var)];
470 CHECK_LE(var_rank, tmp_var_to_rank_[dom]);
475 for (
const IntegerVariableWithRank entry : tmp_ranks_) {
476 tmp_var_to_rank_[entry.var] = -1;
485 return can_freely_decrease_[
var];
488 absl::Span<const IntegerVariable> VarDomination::InitialDominatingCandidates(
489 IntegerVariable
var)
const {
490 const IntegerVariableSpan span = initial_candidates_[
var];
491 if (span.size == 0)
return absl::Span<const IntegerVariable>();
492 return absl::Span<const IntegerVariable>(&shared_buffer_[span.start],
502 IntegerVariable
var)
const {
503 const IntegerVariableSpan span = dominating_vars_[
var];
504 if (span.size == 0)
return absl::Span<const IntegerVariable>();
505 return absl::Span<const IntegerVariable>(&buffer_[span.start], span.size);
523 for (
const int ref : refs) {
524 const IntegerVariable
var = RefToIntegerVariable(ref);
527 locking_ct_index_[
var] = ct_index;
533 for (
const int ref : refs) {
534 const IntegerVariable
var = RefToIntegerVariable(ref);
542 for (
const int ref : refs) {
543 const IntegerVariable
var = RefToIntegerVariable(ref);
551 template <
typename LinearProto>
554 const LinearProto& linear, int64_t min_activity, int64_t max_activity) {
555 const int64_t lb_limit = linear.domain(linear.domain_size() - 2);
556 const int64_t ub_limit = linear.domain(1);
557 const int num_terms = linear.vars_size();
558 for (
int i = 0; i < num_terms; ++i) {
559 int ref = linear.vars(i);
560 int64_t coeff = linear.coeffs(i);
566 const int64_t min_term = coeff *
context.MinOf(ref);
567 const int64_t max_term = coeff *
context.MaxOf(ref);
568 const int64_t term_diff = max_term - min_term;
569 const IntegerVariable
var = RefToIntegerVariable(ref);
572 if (min_activity < lb_limit) {
574 if (min_activity + term_diff < lb_limit) {
577 const IntegerValue slack(lb_limit - min_activity);
578 const IntegerValue var_diff =
579 CeilRatio(IntegerValue(slack), IntegerValue(coeff));
580 can_freely_decrease_until_[
var] =
582 IntegerValue(
context.MinOf(ref)) + var_diff);
594 if (max_activity > ub_limit) {
596 if (max_activity - term_diff > ub_limit) {
599 const IntegerValue slack(max_activity - ub_limit);
600 const IntegerValue var_diff =
601 CeilRatio(IntegerValue(slack), IntegerValue(coeff));
604 -IntegerValue(
context.MaxOf(ref)) + var_diff);
613 for (
int var = 0;
var < num_vars; ++
var) {
619 if (ub_limit == lb) {
620 context->UpdateRuleStats(
"dual: fix variable");
627 const int64_t lb_limit =
629 if (lb_limit == ub) {
630 context->UpdateRuleStats(
"dual: fix variable");
637 if (lb_limit > ub_limit) {
647 context->UpdateRuleStats(
"dual: fix variable with multiple choices");
655 if (lb_limit > lb || ub_limit < ub) {
656 const int64_t new_ub =
663 const int64_t new_lb =
670 context->UpdateRuleStats(
"dual: reduced domain");
680 std::vector<bool> processed(num_vars,
false);
681 for (
int positive_ref = 0; positive_ref < num_vars; ++positive_ref) {
682 if (processed[positive_ref])
continue;
683 if (
context->IsFixed(positive_ref))
continue;
684 const IntegerVariable
var = RefToIntegerVariable(positive_ref);
686 if (num_locks_[
var] == 1 && locking_ct_index_[
var] != -1) {
687 ct_index = locking_ct_index_[
var];
696 context->UpdateRuleStats(
"TODO dual: tighten at most one");
701 if (
ct.enforcement_literal().size() != 1)
continue;
706 int a =
ct.enforcement_literal(0);
709 num_locks_[RefToIntegerVariable(
NegatedRef(
a))] == 1) {
712 if (
ct.bool_and().literals().size() != 1)
continue;
713 b =
ct.bool_and().literals(0);
717 for (
const int lhs :
ct.bool_and().literals()) {
719 num_locks_[RefToIntegerVariable(lhs)] == 1) {
731 context->StoreBooleanEqualityRelation(
a,
b);
732 context->UpdateRuleStats(
"dual: enforced equivalence");
741 template <
typename LinearExprProto>
743 const LinearExprProto&
proto, int64_t* min_activity,
744 int64_t* max_activity) {
747 const int num_vars =
proto.vars().size();
748 for (
int i = 0; i < num_vars; ++i) {
762 const int num_vars = cp_model.
variables().size();
763 var_domination->
Reset(num_vars);
764 dual_bound_strengthening->
Reset(num_vars);
769 for (
int var = 0;
var < num_vars; ++
var) {
781 }
else if (r.
coeff == -1) {
801 std::vector<int> tmp;
804 for (
int c = 0; c < num_constraints; ++c) {
809 switch (
ct.constraint_case()) {
815 ct.bool_or().literals(),
833 for (
const int ref :
ct.enforcement_literal()) {
836 for (
const int ref :
ct.bool_and().literals()) {
846 ct.at_most_one().literals(), c);
849 ct.at_most_one().literals(),
854 dual_bound_strengthening->
CannotMove(
ct.exactly_one().literals());
860 FillMinMaxActivity(
context,
ct.linear(), &min_activity,
864 false,
context,
ct.linear(), min_activity, max_activity);
866 const bool domain_is_simple =
ct.linear().domain().size() == 2;
867 const bool free_to_increase =
868 domain_is_simple &&
ct.linear().domain(1) >= max_activity;
869 const bool free_to_decrease =
870 domain_is_simple &&
ct.linear().domain(0) <= min_activity;
871 if (free_to_decrease && free_to_increase)
break;
872 if (free_to_increase) {
875 ct.linear().coeffs());
876 }
else if (free_to_decrease) {
879 ct.linear().coeffs());
882 if (!
ct.enforcement_literal().empty()) {
884 {},
ct.enforcement_literal(), {});
887 ct.linear().coeffs());
897 for (
const int var :
context.ConstraintToVars(c)) {
910 context.WriteObjectiveToProto();
919 if (domain.empty() || (domain.size() == 2 && domain[0] <= min_activity)) {
934 int64_t num_unconstrained_refs = 0;
935 int64_t num_dominated_refs = 0;
936 int64_t num_dominance_relations = 0;
937 for (
int var = 0;
var < num_vars; ++
var) {
942 num_unconstrained_refs++;
944 num_dominated_refs++;
945 num_dominance_relations +=
950 if (num_unconstrained_refs == 0 && num_dominated_refs == 0)
return;
951 VLOG(1) <<
"Dominance:" 952 <<
" num_unconstrained_refs=" << num_unconstrained_refs
953 <<
" num_dominated_refs=" << num_dominated_refs
954 <<
" num_dominance_relations=" << num_dominance_relations;
963 bool work_to_do =
false;
964 for (
int var = 0;
var < num_vars; ++
var) {
972 if (!work_to_do)
return true;
979 for (
int c = 0; c < num_constraints; ++c) {
983 if (
ct.enforcement_literal().size() != 1)
continue;
984 const int a =
ct.enforcement_literal(0);
986 for (
const int b :
ct.bool_and().literals()) {
990 for (
const IntegerVariable ivar :
994 context->UpdateRuleStats(
"domination: in implication");
995 if (!
context->SetLiteralToFalse(
a))
return false;
1002 for (
const IntegerVariable ivar :
1006 context->UpdateRuleStats(
"domination: in implication");
1007 if (!
context->SetLiteralToTrue(
b))
return false;
1015 if (!
ct.enforcement_literal().empty())
continue;
1023 for (
const int ref :
ct.at_most_one().literals()) {
1026 for (
const int ref :
ct.at_most_one().literals()) {
1027 if (
context->IsFixed(ref))
continue;
1030 if (dominating_ivars.empty())
continue;
1031 for (
const IntegerVariable ivar : dominating_ivars) {
1032 if (!in_constraints[ivar])
continue;
1038 context->UpdateRuleStats(
"domination: in at most one");
1039 if (!
context->SetLiteralToFalse(ref))
return false;
1043 for (
const int ref :
ct.at_most_one().literals()) {
1050 int num_dominated = 0;
1051 for (
const int var :
context->ConstraintToVars(c)) {
1057 if (num_dominated == 0)
continue;
1060 int64_t min_activity = 0;
1061 int64_t max_activity = 0;
1062 const int num_terms =
ct.linear().vars_size();
1063 for (
int i = 0; i < num_terms; ++i) {
1064 int ref =
ct.linear().vars(i);
1065 int64_t coeff =
ct.linear().coeffs(i);
1070 const int64_t min_term = coeff *
context->MinOf(ref);
1071 const int64_t max_term = coeff *
context->MaxOf(ref);
1072 min_activity += min_term;
1073 max_activity += max_term;
1075 var_lb_to_ub_diff[ivar] = max_term - min_term;
1076 var_lb_to_ub_diff[
NegationOf(ivar)] = min_term - max_term;
1078 const int64_t rhs_lb =
ct.linear().domain(0);
1079 const int64_t rhs_ub =
ct.linear().domain(
ct.linear().domain_size() - 1);
1080 if (max_activity < rhs_lb || min_activity > rhs_ub) {
1081 return context->NotifyThatModelIsUnsat(
"linear equation unsat.");
1085 for (
int i = 0; i < num_terms; ++i) {
1086 const int ref =
ct.linear().vars(i);
1087 const int64_t coeff =
ct.linear().coeffs(i);
1089 if (
context->IsFixed(ref))
continue;
1091 for (
const int current_ref : {ref,
NegatedRef(ref)}) {
1092 const absl::Span<const IntegerVariable> dominated_by =
1094 if (dominated_by.empty())
continue;
1096 const bool ub_side = (coeff > 0) == (current_ref == ref);
1098 if (max_activity <= rhs_ub)
continue;
1100 if (min_activity >= rhs_lb)
continue;
1102 const int64_t slack =
1103 ub_side ? rhs_ub - min_activity : max_activity - rhs_lb;
1108 for (
const IntegerVariable ivar : dominated_by) {
1116 const int64_t lb =
context->MinOf(current_ref);
1118 context->UpdateRuleStats(
"domination: fixed to lb.");
1119 if (!
context->IntersectDomainWith(current_ref,
Domain(lb))) {
1124 const IntegerVariable current_var =
1127 CHECK_GE(var_lb_to_ub_diff[current_var], 0);
1128 max_activity -= var_lb_to_ub_diff[current_var];
1130 CHECK_LE(var_lb_to_ub_diff[current_var], 0);
1131 min_activity -= var_lb_to_ub_diff[current_var];
1133 var_lb_to_ub_diff[current_var] = 0;
1134 var_lb_to_ub_diff[
NegationOf(current_var)] = 0;
1141 int64_t new_ub = lb + diff.value();
1142 if (new_ub < context->MaxOf(current_ref)) {
1146 new_ub =
context->DomainOf(current_ref)
1151 if (new_ub < context->MaxOf(current_ref)) {
1152 context->UpdateRuleStats(
"domination: reduced ub.");
1153 if (!
context->IntersectDomainWith(current_ref,
Domain(lb, new_ub))) {
1158 const IntegerVariable current_var =
1161 CHECK_GE(var_lb_to_ub_diff[current_var], 0);
1162 max_activity -= var_lb_to_ub_diff[current_var];
1164 CHECK_LE(var_lb_to_ub_diff[current_var], 0);
1165 min_activity -= var_lb_to_ub_diff[current_var];
1169 var_lb_to_ub_diff[current_var] = new_diff;
1170 var_lb_to_ub_diff[
NegationOf(current_var)] = -new_diff;
1171 max_activity += new_diff;
1173 var_lb_to_ub_diff[current_var] = -new_diff;
1174 var_lb_to_ub_diff[
NegationOf(current_var)] = +new_diff;
1175 min_activity -= new_diff;
1182 for (
const int ref :
ct.linear().vars()) {
1184 var_lb_to_ub_diff[ivar] = 0;
1202 for (
int positive_ref = 0; positive_ref < num_vars; ++positive_ref) {
1203 if (
context->IsFixed(positive_ref))
continue;
1204 if (!
context->CanBeUsedAsLiteral(positive_ref))
continue;
1205 for (
const int ref : {positive_ref,
NegatedRef(positive_ref)}) {
1208 for (
const IntegerVariable dom :
1210 if (increase_is_forbidden[dom])
continue;
1212 if (
context->IsFixed(dom_ref))
continue;
1213 if (!
context->CanBeUsedAsLiteral(dom_ref))
continue;
1215 context->AddImplication(ref, dom_ref);
1218 increase_is_forbidden[
var] =
true;
1219 increase_is_forbidden[
NegationOf(dom)] =
true;
1223 if (num_added > 0) {
1224 VLOG(1) <<
"Added " << num_added <<
" domination implications.";
1225 context->UpdateNewConstraintsVariableUsage();
1226 context->UpdateRuleStats(
"domination: added implications", num_added);
DecisionBuilder *const phase
::PROTOBUF_NAMESPACE_ID::int64 domain(int index) const
#define CHECK_GE(val1, val2)
bool CanFreelyDecrease(int ref) const
void ActivityShouldNotDecrease(absl::Span< const int > enforcements, absl::Span< const int > refs, absl::Span< const int64_t > coeffs)
Fractional coeff_magnitude
#define VLOG(verboselevel)
std::vector< int64_t > FlattenedIntervals() const
This method returns the flattened list of interval bounds of the domain.
std::string DominationDebugString(IntegerVariable var) const
absl::Span< const IntegerVariable > DominatingVariables(int ref) const
int variables_size() const
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
static int IntegerVariableToRef(IntegerVariable var)
IntegerVariable PositiveVariable(IntegerVariable i)
::PROTOBUF_NAMESPACE_ID::int32 vars(int index) const
void resize(size_type new_size)
const ::operations_research::sat::IntegerVariableProto & variables(int index) const
int64_t Min() const
Returns the min value of the domain.
void ActivityShouldNotIncrease(absl::Span< const int > enforcements, absl::Span< const int > refs, absl::Span< const int64_t > coeffs)
bool Strengthen(PresolveContext *context)
#define CHECK_LE(val1, val2)
const ::operations_research::sat::ConstraintProto & constraints(int index) const
const ::operations_research::sat::CpObjectiveProto & objective() const
void Reset(int num_variables)
::PROTOBUF_NAMESPACE_ID::int64 coeffs(int index) const
void CanOnlyDominateEachOther(absl::Span< const int > refs)
int constraints_size() const
int64_t CanFreelyDecreaseUntil(int ref) const
void STLClearObject(T *obj)
#define CHECK_EQ(val1, val2)
bool has_objective() const
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
void CannotMove(absl::Span< const int > refs)
void CannotDecrease(absl::Span< const int > refs, int ct_index=-1)
static IntegerVariable RefToIntegerVariable(int ref)
void ProcessLinearConstraint(bool is_objective, const PresolveContext &context, const LinearProto &linear, int64_t min_activity, int64_t max_activity)
We call domain any subset of Int64 = [kint64min, kint64max].
IntegerValue FloorRatio(IntegerValue dividend, IntegerValue positive_divisor)
bool Contains(int64_t value) const
Returns true iff value is in Domain.
IntegerValue CeilRatio(IntegerValue dividend, IntegerValue positive_divisor)
void CannotIncrease(absl::Span< const int > refs, int ct_index=-1)
Collection of objects used to extend the Constraint Solver library.
const IntegerVariable kNoIntegerVariable(-1)
void DetectDominanceRelations(const PresolveContext &context, VarDomination *var_domination, DualBoundStrengthening *dual_bound_strengthening)
void assign(size_type n, const value_type &val)
bool ExploitDominanceRelations(const VarDomination &var_domination, PresolveContext *context)
bool RefIsPositive(int ref)
void Reset(int num_variables)
void ActivityShouldNotChange(absl::Span< const int > refs, absl::Span< const int64_t > coeffs)
GurobiMPCallbackContext * context
bool IsEmpty() const
Returns true if this is the empty set.