215 std::vector<int> num_times_variable_appears_as_input(model.
variables_size());
216 std::vector<int> num_times_variable_appears_as_deducible(
218 std::vector<int> num_times_variable_appears_as_preferred_to_deduce(
221 struct ConstraintData {
224 absl::btree_set<int> deducible_vars;
225 absl::btree_set<int> input_vars;
227 int preferred_to_deduce;
233 bool is_linear_inequality;
237 std::vector<std::vector<int>> constraints_per_var(model.
variables_size());
247 for (
int i = 0;
i < model.
objective().vars_size(); ++
i) {
256 ConstraintData& data = constraint_data[c];
258 data.is_linear_inequality =
false;
260 &data.preferred_to_deduce);
268 data.deducible_vars.empty() &&
272 data.is_linear_inequality =
true;
273 for (
int i = 0;
i < ct.
linear().vars_size(); ++
i) {
275 if (!var_appears_only_in_objective_and_linear.
IsSet(var)) {
276 data.input_vars.insert(var);
281 data.deducible_vars.insert(var);
283 data.input_vars.insert(var);
289 var_appears_only_in_objective_and_linear.
Set(var,
false);
295 var_appears_only_in_objective_and_linear.
Set(var,
false);
304 std::vector<int> deducible_vars_to_remove;
306 deducible_vars_to_remove.clear();
307 ConstraintData& data = constraint_data[c];
308 if (!data.is_linear_inequality) {
311 for (
const int var : data.deducible_vars) {
312 if (!var_appears_only_in_objective_and_linear.
IsSet(var)) {
313 deducible_vars_to_remove.push_back(var);
314 data.input_vars.insert(var);
317 for (
const int var : deducible_vars_to_remove) {
318 data.deducible_vars.erase(var);
320 if (data.deducible_vars.empty()) {
321 data.is_linear_inequality =
false;
325 for (
int c = 0; c < constraint_data.size(); ++c) {
326 ConstraintData& data = constraint_data[c];
327 if (data.deducible_vars.empty()) {
328 data.input_vars.clear();
331 if (data.preferred_to_deduce != -1) {
332 num_times_variable_appears_as_preferred_to_deduce
333 [data.preferred_to_deduce]++;
335 for (
const int v : data.deducible_vars) {
336 constraints_per_var[v].push_back(c);
337 num_times_variable_appears_as_deducible[v]++;
339 for (
const int v : data.input_vars) {
340 constraints_per_var[v].push_back(c);
341 num_times_variable_appears_as_input[v]++;
348 if (num_times_variable_appears_as_deducible[v] != 0) {
351 num_times_variable_appears_as_input[v] = 0;
352 var_is_primary.
Set(v);
353 for (
const int c : constraints_per_var[v]) {
354 ConstraintData& data = constraint_data[c];
355 data.deducible_vars.erase(v);
356 data.input_vars.erase(v);
358 constraints_per_var[v].clear();
367 std::vector<int> count_of_unresolved_linear_inequalities_per_var(
370 ConstraintData& data = constraint_data[c];
371 if (!data.is_linear_inequality) {
374 if (data.input_vars.size() + data.deducible_vars.size() > 1) {
375 for (
const int v : data.input_vars) {
376 count_of_unresolved_linear_inequalities_per_var[v]++;
378 for (
const int v : data.deducible_vars) {
379 count_of_unresolved_linear_inequalities_per_var[v]++;
393 std::deque<int> vars_queue;
395 if (var_is_primary.
IsSet(v) || var_is_secondary.
IsSet(v)) {
398 vars_queue.push_back(v);
400 absl::c_stable_sort(vars_queue, [&](
int a,
int b) {
401 const int a_diff_usage = num_times_variable_appears_as_deducible[a] -
402 num_times_variable_appears_as_input[a];
403 const int b_diff_usage = num_times_variable_appears_as_deducible[
b] -
404 num_times_variable_appears_as_input[
b];
405 return std::make_tuple(
407 -num_times_variable_appears_as_preferred_to_deduce[a],
408 -num_times_variable_appears_as_deducible[a]) <
411 -num_times_variable_appears_as_preferred_to_deduce[
b],
412 -num_times_variable_appears_as_deducible[
b]);
418 ConstraintData& data = constraint_data[c];
419 if (data.input_vars.size() + data.deducible_vars.size() != 1) {
422 if (!data.deducible_vars.empty()) {
423 vars_queue.push_front(*data.deducible_vars.begin());
424 }
else if (data.is_linear_inequality) {
425 vars_queue.push_front(*data.input_vars.begin());
429 std::vector<int> constraints_to_check;
430 while (!vars_queue.empty()) {
431 const int v = vars_queue.front();
432 vars_queue.pop_front();
433 if (var_is_secondary.
IsSet(v) || var_is_primary.
IsSet(v)) {
438 for (
const int c : constraints_per_var[v]) {
439 ConstraintData& data = constraint_data[c];
440 if (data.is_linear_inequality) {
443 if (data.deducible_vars.size() + data.input_vars.size() != 1) {
451 if (data.deducible_vars.empty()) {
455 data.input_vars.clear();
458 var_is_secondary.
Set(v);
467 if (!var_is_secondary.
IsSet(v)) {
468 if (var_appears_only_in_objective_and_linear.
IsSet(v) &&
469 count_of_unresolved_linear_inequalities_per_var[v] == 0) {
470 var_is_secondary.
Set(v);
474 model, v, constraints_per_var[v],
475 var_in_objective_is_negative.
IsSet(v),
481 var_is_primary.
Set(v);
487 auto update_constraints_after_var_is_decided = [&](
int v) {
488 for (
const int c : constraints_per_var[v]) {
489 ConstraintData& data = constraint_data[c];
490 data.deducible_vars.erase(v);
491 data.input_vars.erase(v);
492 if (data.input_vars.size() + data.deducible_vars.size() != 1) {
498 if (data.is_linear_inequality && data.deducible_vars.size() == 1) {
499 const int deducible_var = *data.deducible_vars.begin();
500 count_of_unresolved_linear_inequalities_per_var[deducible_var]--;
501 if (count_of_unresolved_linear_inequalities_per_var[deducible_var] ==
504 vars_queue.push_front(deducible_var);
507 if (data.deducible_vars.empty()) {
509 data.input_vars.clear();
512 constraints_to_check.push_back(c);
520 DCHECK(constraints_to_check.empty());
521 update_constraints_after_var_is_decided(v);
525 while (!constraints_to_check.empty()) {
526 const int c = constraints_to_check.back();
527 constraints_to_check.pop_back();
528 ConstraintData& data = constraint_data[c];
529 DCHECK_LE(data.deducible_vars.size(), 1);
530 if (data.deducible_vars.size() != 1) {
533 const int single_deducible_var = *data.deducible_vars.begin();
534 var_is_secondary.
Set(single_deducible_var);
535 update_constraints_after_var_is_decided(single_deducible_var);
547 &data.preferred_to_deduce);
548 for (
const int v : data.input_vars) {
549 if (var_is_secondary.
IsSet(v)) {
553 for (
const int v : data.deducible_vars) {
554 if (var_is_secondary.
IsSet(v) && v != var) {
567 dependent_variables_set.
Set(var);
578 int64_t coeff_of_var = 1;
579 for (
int j = 0; j < linear.
vars_size(); ++j) {
580 if (linear.
vars(j) == var) {
581 coeff_of_var = linear.
coeffs(j);
584 DCHECK(!dependent_variables_set.
IsSet(linear.
vars(j)));
585 sum_of_free_variables -=
586 linear.
coeffs(j) * (*solution)[linear.
vars(j)];
588 (*solution)[var] = sum_of_free_variables / coeff_of_var;
591 int64_t max = std::numeric_limits<int64_t>::min();
593 int64_t expr_value = expr.offset();
594 for (
int j = 0; j < expr.vars_size(); ++j) {
595 DCHECK(!dependent_variables_set.
IsSet(expr.vars(j)));
596 expr_value += expr.coeffs(j) * (*solution)[expr.vars(j)];
598 max = std::max(max, expr_value);
601 int64_t coeff_of_var = 1;
602 for (
int j = 0; j < target.
vars_size(); ++j) {
603 if (target.
vars(j) == var) {
604 coeff_of_var = target.
coeffs(j);
607 DCHECK(!dependent_variables_set.
IsSet(target.
vars(j)));
608 max -= target.
coeffs(j) * (*solution)[target.
vars(j)];
611 (*solution)[var] = max / coeff_of_var;
617 int64_t expr_value = expr.offset();
618 for (
int j = 0; j < expr.vars_size(); ++j) {
619 DCHECK(!dependent_variables_set.
IsSet(expr.vars(j)));
620 expr_value += (*solution)[expr.vars(j)] * expr.coeffs(j);
622 product *= expr_value;
624 int64_t coeff_of_var = 1;
626 for (
int j = 0; j < target.
vars_size(); ++j) {
627 if (target.
vars(j) == var) {
628 coeff_of_var = target.
coeffs(j);
631 DCHECK(!dependent_variables_set.
IsSet(target.
vars(j)));
632 product -= target.
coeffs(j) * (*solution)[target.
vars(j)];
634 product -= target.
offset();
635 (*solution)[var] = product / coeff_of_var;
638 (*solution)[var] = 0;
642 DCHECK(positive_ref == var ||
643 !dependent_variables_set.
IsSet(positive_ref));
645 : 1 - (*solution)[positive_ref];
648 (*solution)[var] ^= 1;
654 dependent_variables_set.
Set(var,
false);