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);
42void 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_);
82void 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);
130void 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;
145void 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;
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;
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;
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;
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;
381void 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(
421void 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;
455void 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];
488absl::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);
551template <
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);
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 =
580 can_freely_decrease_until_[
var] =
582 IntegerValue(
context.MinOf(ref)) + var_diff);
595 if (max_activity > ub_limit) {
597 if (max_activity - term_diff > ub_limit) {
600 const IntegerValue slack(max_activity - ub_limit);
601 const IntegerValue var_diff =
605 -IntegerValue(
context.MaxOf(ref)) + var_diff);
614 for (
int var = 0;
var < num_vars; ++
var) {
620 if (ub_limit == lb) {
621 context->UpdateRuleStats(
"dual: fix variable");
628 const int64_t lb_limit =
630 if (lb_limit == ub) {
631 context->UpdateRuleStats(
"dual: fix variable");
638 if (lb_limit > ub_limit) {
648 context->UpdateRuleStats(
"dual: fix variable with multiple choices");
656 if (lb_limit > lb || ub_limit < ub) {
657 const int64_t new_ub =
664 const int64_t new_lb =
671 context->UpdateRuleStats(
"dual: reduced domain");
681 std::vector<bool> processed(num_vars,
false);
682 for (
int positive_ref = 0; positive_ref < num_vars; ++positive_ref) {
683 if (processed[positive_ref])
continue;
684 if (
context->IsFixed(positive_ref))
continue;
685 const IntegerVariable
var = RefToIntegerVariable(positive_ref);
687 if (num_locks_[
var] == 1 && locking_ct_index_[
var] != -1) {
688 ct_index = locking_ct_index_[
var];
697 context->UpdateRuleStats(
"TODO dual: tighten at most one");
702 if (
ct.enforcement_literal().size() != 1)
continue;
707 int a =
ct.enforcement_literal(0);
710 num_locks_[RefToIntegerVariable(
NegatedRef(
a))] == 1) {
713 if (
ct.bool_and().literals().size() != 1)
continue;
714 b =
ct.bool_and().literals(0);
718 for (
const int lhs :
ct.bool_and().literals()) {
720 num_locks_[RefToIntegerVariable(lhs)] == 1) {
732 context->StoreBooleanEqualityRelation(
a,
b);
733 context->UpdateRuleStats(
"dual: enforced equivalence");
742template <
typename LinearExprProto>
744 const LinearExprProto&
proto, int64_t* min_activity,
745 int64_t* max_activity) {
748 const int num_vars =
proto.vars().size();
749 for (
int i = 0; i < num_vars; ++i) {
763 const int num_vars = cp_model.
variables().size();
764 var_domination->
Reset(num_vars);
765 dual_bound_strengthening->
Reset(num_vars);
770 for (
int var = 0;
var < num_vars; ++
var) {
782 }
else if (r.
coeff == -1) {
802 std::vector<int> tmp;
805 for (
int c = 0; c < num_constraints; ++c) {
810 switch (
ct.constraint_case()) {
816 ct.bool_or().literals(),
834 for (
const int ref :
ct.enforcement_literal()) {
837 for (
const int ref :
ct.bool_and().literals()) {
847 ct.at_most_one().literals(), c);
850 ct.at_most_one().literals(),
855 dual_bound_strengthening->
CannotMove(
ct.exactly_one().literals());
861 FillMinMaxActivity(
context,
ct.linear(), &min_activity,
865 false,
context,
ct.linear(), min_activity, max_activity);
867 const bool domain_is_simple =
ct.linear().domain().size() == 2;
868 const bool free_to_increase =
869 domain_is_simple &&
ct.linear().domain(1) >= max_activity;
870 const bool free_to_decrease =
871 domain_is_simple &&
ct.linear().domain(0) <= min_activity;
872 if (free_to_decrease && free_to_increase)
break;
873 if (free_to_increase) {
876 ct.linear().coeffs());
877 }
else if (free_to_decrease) {
880 ct.linear().coeffs());
883 if (!
ct.enforcement_literal().empty()) {
885 {},
ct.enforcement_literal(), {});
888 ct.linear().coeffs());
898 for (
const int var :
context.ConstraintToVars(c)) {
911 context.WriteObjectiveToProto();
920 if (domain.empty() || (domain.size() == 2 && domain[0] <= min_activity)) {
935 int64_t num_unconstrained_refs = 0;
936 int64_t num_dominated_refs = 0;
937 int64_t num_dominance_relations = 0;
938 for (
int var = 0;
var < num_vars; ++
var) {
943 num_unconstrained_refs++;
945 num_dominated_refs++;
946 num_dominance_relations +=
951 if (num_unconstrained_refs == 0 && num_dominated_refs == 0)
return;
952 VLOG(1) <<
"Dominance:"
953 <<
" num_unconstrained_refs=" << num_unconstrained_refs
954 <<
" num_dominated_refs=" << num_dominated_refs
955 <<
" num_dominance_relations=" << num_dominance_relations;
964 bool work_to_do =
false;
965 for (
int var = 0;
var < num_vars; ++
var) {
973 if (!work_to_do)
return true;
980 for (
int c = 0; c < num_constraints; ++c) {
984 if (
ct.enforcement_literal().size() != 1)
continue;
985 const int a =
ct.enforcement_literal(0);
987 for (
const int b :
ct.bool_and().literals()) {
991 for (
const IntegerVariable ivar :
995 context->UpdateRuleStats(
"domination: in implication");
996 if (!
context->SetLiteralToFalse(
a))
return false;
1003 for (
const IntegerVariable ivar :
1007 context->UpdateRuleStats(
"domination: in implication");
1008 if (!
context->SetLiteralToTrue(
b))
return false;
1016 if (!
ct.enforcement_literal().empty())
continue;
1024 for (
const int ref :
ct.at_most_one().literals()) {
1027 for (
const int ref :
ct.at_most_one().literals()) {
1028 if (
context->IsFixed(ref))
continue;
1031 if (dominating_ivars.empty())
continue;
1032 for (
const IntegerVariable ivar : dominating_ivars) {
1033 if (!in_constraints[ivar])
continue;
1039 context->UpdateRuleStats(
"domination: in at most one");
1040 if (!
context->SetLiteralToFalse(ref))
return false;
1044 for (
const int ref :
ct.at_most_one().literals()) {
1051 int num_dominated = 0;
1052 for (
const int var :
context->ConstraintToVars(c)) {
1058 if (num_dominated == 0)
continue;
1061 int64_t min_activity = 0;
1062 int64_t max_activity = 0;
1063 const int num_terms =
ct.linear().vars_size();
1064 for (
int i = 0; i < num_terms; ++i) {
1065 int ref =
ct.linear().vars(i);
1066 int64_t
coeff =
ct.linear().coeffs(i);
1073 min_activity += min_term;
1074 max_activity += max_term;
1076 var_lb_to_ub_diff[ivar] = max_term - min_term;
1077 var_lb_to_ub_diff[
NegationOf(ivar)] = min_term - max_term;
1079 const int64_t rhs_lb =
ct.linear().domain(0);
1080 const int64_t rhs_ub =
ct.linear().domain(
ct.linear().domain_size() - 1);
1081 if (max_activity < rhs_lb || min_activity > rhs_ub) {
1082 return context->NotifyThatModelIsUnsat(
"linear equation unsat.");
1086 for (
int i = 0; i < num_terms; ++i) {
1087 const int ref =
ct.linear().vars(i);
1088 const int64_t
coeff =
ct.linear().coeffs(i);
1090 if (
context->IsFixed(ref))
continue;
1092 for (
const int current_ref : {ref,
NegatedRef(ref)}) {
1093 const absl::Span<const IntegerVariable> dominated_by =
1095 if (dominated_by.empty())
continue;
1097 const bool ub_side = (
coeff > 0) == (current_ref == ref);
1099 if (max_activity <= rhs_ub)
continue;
1101 if (min_activity >= rhs_lb)
continue;
1103 const int64_t slack =
1104 ub_side ? rhs_ub - min_activity : max_activity - rhs_lb;
1109 for (
const IntegerVariable ivar : dominated_by) {
1117 const int64_t lb =
context->MinOf(current_ref);
1119 context->UpdateRuleStats(
"domination: fixed to lb.");
1120 if (!
context->IntersectDomainWith(current_ref,
Domain(lb))) {
1125 const IntegerVariable current_var =
1128 CHECK_GE(var_lb_to_ub_diff[current_var], 0);
1129 max_activity -= var_lb_to_ub_diff[current_var];
1131 CHECK_LE(var_lb_to_ub_diff[current_var], 0);
1132 min_activity -= var_lb_to_ub_diff[current_var];
1134 var_lb_to_ub_diff[current_var] = 0;
1135 var_lb_to_ub_diff[
NegationOf(current_var)] = 0;
1142 int64_t new_ub = lb + diff.value();
1143 if (new_ub < context->MaxOf(current_ref)) {
1147 new_ub =
context->DomainOf(current_ref)
1152 if (new_ub < context->MaxOf(current_ref)) {
1153 context->UpdateRuleStats(
"domination: reduced ub.");
1154 if (!
context->IntersectDomainWith(current_ref,
Domain(lb, new_ub))) {
1159 const IntegerVariable current_var =
1162 CHECK_GE(var_lb_to_ub_diff[current_var], 0);
1163 max_activity -= var_lb_to_ub_diff[current_var];
1165 CHECK_LE(var_lb_to_ub_diff[current_var], 0);
1166 min_activity -= var_lb_to_ub_diff[current_var];
1170 var_lb_to_ub_diff[current_var] = new_diff;
1171 var_lb_to_ub_diff[
NegationOf(current_var)] = -new_diff;
1172 max_activity += new_diff;
1174 var_lb_to_ub_diff[current_var] = -new_diff;
1175 var_lb_to_ub_diff[
NegationOf(current_var)] = +new_diff;
1176 min_activity -= new_diff;
1183 for (
const int ref :
ct.linear().vars()) {
1185 var_lb_to_ub_diff[ivar] = 0;
1203 for (
int positive_ref = 0; positive_ref < num_vars; ++positive_ref) {
1204 if (
context->IsFixed(positive_ref))
continue;
1205 if (!
context->CanBeUsedAsLiteral(positive_ref))
continue;
1206 for (
const int ref : {positive_ref,
NegatedRef(positive_ref)}) {
1209 for (
const IntegerVariable dom :
1211 if (increase_is_forbidden[dom])
continue;
1213 if (
context->IsFixed(dom_ref))
continue;
1214 if (!
context->CanBeUsedAsLiteral(dom_ref))
continue;
1216 context->AddImplication(ref, dom_ref);
1219 increase_is_forbidden[
var] =
true;
1220 increase_is_forbidden[
NegationOf(dom)] =
true;
1224 if (num_added > 0) {
1225 VLOG(1) <<
"Added " << num_added <<
" domination implications.";
1226 context->UpdateNewConstraintsVariableUsage();
1227 context->UpdateRuleStats(
"domination: added implications", num_added);
#define CHECK_EQ(val1, val2)
#define CHECK_GE(val1, val2)
#define CHECK_LE(val1, val2)
#define VLOG(verboselevel)
void assign(size_type n, const value_type &val)
void resize(size_type new_size)
void push_back(const value_type &x)
We call domain any subset of Int64 = [kint64min, kint64max].
bool Contains(int64_t value) const
Returns true iff value is in Domain.
std::vector< int64_t > FlattenedIntervals() const
This method returns the flattened list of interval bounds of the domain.
int64_t Min() const
Returns the min value of the domain.
bool IsEmpty() const
Returns true if this is the empty set.
const ::operations_research::sat::CpObjectiveProto & objective() const
const ::operations_research::sat::IntegerVariableProto & variables(int index) const
bool has_objective() const
int variables_size() const
int constraints_size() const
const ::operations_research::sat::ConstraintProto & constraints(int index) const
int64_t domain(int index) const
int32_t vars(int index) const
int64_t coeffs(int index) const
bool Strengthen(PresolveContext *context)
void ProcessLinearConstraint(bool is_objective, const PresolveContext &context, const LinearProto &linear, int64_t min_activity, int64_t max_activity)
void Reset(int num_variables)
int64_t CanFreelyDecreaseUntil(int ref) const
void CannotMove(absl::Span< const int > refs)
void CannotIncrease(absl::Span< const int > refs, int ct_index=-1)
void CannotDecrease(absl::Span< const int > refs, int ct_index=-1)
void ActivityShouldNotIncrease(absl::Span< const int > enforcements, absl::Span< const int > refs, absl::Span< const int64_t > coeffs)
void ActivityShouldNotChange(absl::Span< const int > refs, absl::Span< const int64_t > coeffs)
bool CanFreelyDecrease(int ref) const
static int IntegerVariableToRef(IntegerVariable var)
void Reset(int num_variables)
void ActivityShouldNotDecrease(absl::Span< const int > enforcements, absl::Span< const int > refs, absl::Span< const int64_t > coeffs)
absl::Span< const IntegerVariable > DominatingVariables(int ref) const
std::string DominationDebugString(IntegerVariable var) const
static IntegerVariable RefToIntegerVariable(int ref)
void CanOnlyDominateEachOther(absl::Span< const int > refs)
DecisionBuilder *const phase
GurobiMPCallbackContext * context
void STLClearObject(T *obj)
IntegerValue FloorRatio(IntegerValue dividend, IntegerValue positive_divisor)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
bool RefIsPositive(int ref)
IntegerValue CeilRatio(IntegerValue dividend, IntegerValue positive_divisor)
const IntegerVariable kNoIntegerVariable(-1)
void DetectDominanceRelations(const PresolveContext &context, VarDomination *var_domination, DualBoundStrengthening *dual_bound_strengthening)
IntegerVariable PositiveVariable(IntegerVariable i)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
bool ExploitDominanceRelations(const VarDomination &var_domination, PresolveContext *context)
Collection of objects used to extend the Constraint Solver library.
Fractional coeff_magnitude