@@ -2942,6 +2942,34 @@ bool CpModelPresolver::PresolveSmallLinear(ConstraintProto* ct) {
29422942 return false;
29432943}
29442944
2945+ namespace {
2946+ // Set the hint in `context` for the variable in `equality` that has no hint, if
2947+ // there is exactly one. Otherwise do nothing.
2948+ void MaybeComputeMissingHint(PresolveContext* context,
2949+ const LinearConstraintProto& equality) {
2950+ DCHECK(equality.domain_size() == 2 &&
2951+ equality.domain(0) == equality.domain(1));
2952+ if (!context->HintIsLoaded()) return;
2953+ int term_with_missing_hint = -1;
2954+ int64_t missing_term_value = equality.domain(0);
2955+ for (int i = 0; i < equality.vars_size(); ++i) {
2956+ if (context->VarHasSolutionHint(equality.vars(i))) {
2957+ missing_term_value -=
2958+ context->SolutionHint(equality.vars(i)) * equality.coeffs(i);
2959+ } else if (term_with_missing_hint == -1) {
2960+ term_with_missing_hint = i;
2961+ } else {
2962+ // More than one variable has a missing hint.
2963+ return;
2964+ }
2965+ }
2966+ if (term_with_missing_hint == -1) return;
2967+ context->SetNewVariableHint(
2968+ equality.vars(term_with_missing_hint),
2969+ missing_term_value / equality.coeffs(term_with_missing_hint));
2970+ }
2971+ } // namespace
2972+
29452973bool CpModelPresolver::PresolveDiophantine(ConstraintProto* ct) {
29462974 if (ct->constraint_case() != ConstraintProto::kLinear) return false;
29472975 if (ct->linear().vars().size() <= 1) return false;
@@ -3064,6 +3092,15 @@ bool CpModelPresolver::PresolveDiophantine(ConstraintProto* ct) {
30643092 }
30653093 }
30663094 context_->InitializeNewDomains();
3095+ // Scan the new constraints added above in reverse order so that the hint of
3096+ // `new_variables[k]` can be computed from the hint of the existing variables
3097+ // and from the hints of `new_variables[k']`, with k' > k.
3098+ const int num_constraints = context_->working_model->constraints_size();
3099+ for (int i = 0; i < num_replaced_variables; ++i) {
3100+ MaybeComputeMissingHint(
3101+ context_,
3102+ context_->working_model->constraints(num_constraints - 1 - i).linear());
3103+ }
30673104
30683105 if (VLOG_IS_ON(2)) {
30693106 std::string log_eq = absl::StrCat(linear_constraint.domain(0), " = ");
@@ -7457,7 +7494,7 @@ void CpModelPresolver::Probe() {
74577494namespace {
74587495
74597496bool FixFromAssignment(const VariablesAssignment& assignment,
7460- const std::vector< int>& var_mapping,
7497+ absl::Span<const int> var_mapping,
74617498 PresolveContext* context) {
74627499 const int num_vars = assignment.NumberOfVariables();
74637500 for (int i = 0; i < num_vars; ++i) {
0 commit comments