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]);
414 std::vector<int> constraints_to_check;
415 while (!vars_queue.empty()) {
416 const int v = vars_queue.front();
417 vars_queue.pop_front();
418 if (var_is_secondary.
IsSet(v) || var_is_primary.
IsSet(v)) {
423 for (
const int c : constraints_per_var[v]) {
424 ConstraintData& data = constraint_data[c];
425 if (data.is_linear_inequality) {
428 if (data.deducible_vars.size() + data.input_vars.size() != 1) {
436 if (data.deducible_vars.empty()) {
440 data.input_vars.clear();
443 var_is_secondary.
Set(v);
452 if (!var_is_secondary.
IsSet(v)) {
453 if (var_appears_only_in_objective_and_linear.
IsSet(v) &&
454 count_of_unresolved_linear_inequalities_per_var[v] == 0) {
455 var_is_secondary.
Set(v);
459 model, v, constraints_per_var[v],
460 var_in_objective_is_negative.
IsSet(v),
466 var_is_primary.
Set(v);
472 auto update_constraints_after_var_is_decided = [&](
int v) {
473 for (
const int c : constraints_per_var[v]) {
474 ConstraintData& data = constraint_data[c];
475 data.deducible_vars.erase(v);
476 data.input_vars.erase(v);
477 if (data.input_vars.size() + data.deducible_vars.size() != 1) {
483 if (data.is_linear_inequality && data.deducible_vars.size() == 1) {
484 const int deducible_var = *data.deducible_vars.begin();
485 count_of_unresolved_linear_inequalities_per_var[deducible_var]--;
486 if (count_of_unresolved_linear_inequalities_per_var[deducible_var] ==
489 vars_queue.push_front(deducible_var);
492 if (data.deducible_vars.empty()) {
494 data.input_vars.clear();
497 constraints_to_check.push_back(c);
505 DCHECK(constraints_to_check.empty());
506 update_constraints_after_var_is_decided(v);
510 while (!constraints_to_check.empty()) {
511 const int c = constraints_to_check.back();
512 constraints_to_check.pop_back();
513 ConstraintData& data = constraint_data[c];
514 DCHECK_LE(data.deducible_vars.size(), 1);
515 if (data.deducible_vars.size() != 1) {
518 const int single_deducible_var = *data.deducible_vars.begin();
519 var_is_secondary.
Set(single_deducible_var);
520 update_constraints_after_var_is_decided(single_deducible_var);
532 &data.preferred_to_deduce);
533 for (
const int v : data.input_vars) {
534 if (var_is_secondary.
IsSet(v)) {
538 for (
const int v : data.deducible_vars) {
539 if (var_is_secondary.
IsSet(v) && v != var) {
552 dependent_variables_set.
Set(var);
563 int64_t coeff_of_var = 1;
564 for (
int j = 0; j < linear.
vars_size(); ++j) {
565 if (linear.
vars(j) == var) {
566 coeff_of_var = linear.
coeffs(j);
569 DCHECK(!dependent_variables_set.
IsSet(linear.
vars(j)));
570 sum_of_free_variables -=
571 linear.
coeffs(j) * (*solution)[linear.
vars(j)];
573 (*solution)[var] = sum_of_free_variables / coeff_of_var;
576 int64_t max = std::numeric_limits<int64_t>::min();
578 int64_t expr_value = expr.offset();
579 for (
int j = 0; j < expr.vars_size(); ++j) {
580 DCHECK(!dependent_variables_set.
IsSet(expr.vars(j)));
581 expr_value += expr.coeffs(j) * (*solution)[expr.vars(j)];
583 max = std::max(max, expr_value);
586 int64_t coeff_of_var = 1;
587 for (
int j = 0; j < target.
vars_size(); ++j) {
588 if (target.
vars(j) == var) {
589 coeff_of_var = target.
coeffs(j);
592 DCHECK(!dependent_variables_set.
IsSet(target.
vars(j)));
593 max -= target.
coeffs(j) * (*solution)[target.
vars(j)];
596 (*solution)[var] = max / coeff_of_var;
602 int64_t expr_value = expr.offset();
603 for (
int j = 0; j < expr.vars_size(); ++j) {
604 DCHECK(!dependent_variables_set.
IsSet(expr.vars(j)));
605 expr_value += (*solution)[expr.vars(j)] * expr.coeffs(j);
607 product *= expr_value;
609 int64_t coeff_of_var = 1;
611 for (
int j = 0; j < target.
vars_size(); ++j) {
612 if (target.
vars(j) == var) {
613 coeff_of_var = target.
coeffs(j);
616 DCHECK(!dependent_variables_set.
IsSet(target.
vars(j)));
617 product -= target.
coeffs(j) * (*solution)[target.
vars(j)];
619 product -= target.
offset();
620 (*solution)[var] = product / coeff_of_var;
623 (*solution)[var] = 0;
627 DCHECK(positive_ref == var ||
628 !dependent_variables_set.
IsSet(positive_ref));
630 : 1 - (*solution)[positive_ref];
633 (*solution)[var] ^= 1;
639 dependent_variables_set.
Set(var,
false);