This commit is contained in:
Laurent Perron
2021-03-04 18:25:44 +01:00
parent fa84bc05e7
commit 94e37f774f

View File

@@ -13,6 +13,8 @@
#include "ortools/sat/cp_model_expand.h"
#include <cstdint>
#include <limits>
#include <map>
#include "absl/container/flat_hash_map.h"
@@ -49,7 +51,7 @@ void ExpandReservoir(ConstraintProto* ct, PresolveContext* context) {
int num_positives = 0;
int num_negatives = 0;
for (const int64 demand : reservoir.demands()) {
for (const int64_t demand : reservoir.demands()) {
if (demand > 0) {
num_positives++;
} else if (demand < 0) {
@@ -107,7 +109,7 @@ void ExpandReservoir(ConstraintProto* ct, PresolveContext* context) {
}
// Accounts for own demand in the domain of the sum.
const int64 demand_i = reservoir.demands(i);
const int64_t demand_i = reservoir.demands(i);
level->mutable_linear()->add_domain(
CapSub(reservoir.min_level(), demand_i));
level->mutable_linear()->add_domain(
@@ -145,14 +147,15 @@ void ExpandIntMod(ConstraintProto* ct, PresolveContext* context) {
const int mod_var = int_mod.vars(1);
const int target_var = int_mod.target();
const int64 mod_lb = context->MinOf(mod_var);
const int64_t mod_lb = context->MinOf(mod_var);
CHECK_GE(mod_lb, 1);
const int64 mod_ub = context->MaxOf(mod_var);
const int64_t mod_ub = context->MaxOf(mod_var);
const int64 var_lb = context->MinOf(var);
const int64 var_ub = context->MaxOf(var);
const int64_t var_lb = context->MinOf(var);
const int64_t var_ub = context->MaxOf(var);
// Compute domains of var / mod_var.
// TODO(user): implement Domain.ContinuousDivisionBy(domain).
const int div_var =
context->NewIntVar(Domain(var_lb / mod_ub, var_ub / mod_lb));
@@ -189,7 +192,8 @@ void ExpandIntMod(ConstraintProto* ct, PresolveContext* context) {
} else {
// Create prod_var = div_var * mod.
const int prod_var = context->NewIntVar(
Domain(var_lb * mod_lb / mod_ub, var_ub * mod_ub / mod_lb));
context->DomainOf(div_var).ContinuousMultiplicationBy(
context->DomainOf(mod_var)));
IntegerArgumentProto* const int_prod =
context->working_model->add_constraints()->mutable_int_prod();
int_prod->set_target(prod_var);
@@ -256,8 +260,10 @@ void ExpandIntProdWithOneAcrossZero(int a_ref, int b_ref, int product_ref,
// Split the domain of a in two, controlled by a new literal.
const int a_is_positive = context->NewBoolVar();
context->AddImplyInDomain(a_is_positive, a_ref, {0, kint64max});
context->AddImplyInDomain(NegatedRef(a_is_positive), a_ref, {kint64min, -1});
context->AddImplyInDomain(a_is_positive, a_ref,
{0, std::numeric_limits<int64_t>::max()});
context->AddImplyInDomain(NegatedRef(a_is_positive), a_ref,
{std::numeric_limits<int64_t>::min(), -1});
const int pos_a_ref = context->NewIntVar({0, context->MaxOf(a_ref)});
AddXEqualYOrXEqualZero(a_is_positive, pos_a_ref, a_ref, context);
@@ -304,10 +310,12 @@ void ExpandIntProdWithTwoAcrossZero(int a_ref, int b_ref, int product_ref,
PresolveContext* context) {
// Split a_ref domain in two, controlled by a new literal.
const int a_is_positive = context->NewBoolVar();
context->AddImplyInDomain(a_is_positive, a_ref, {0, kint64max});
context->AddImplyInDomain(NegatedRef(a_is_positive), a_ref, {kint64min, -1});
const int64 min_of_a = context->MinOf(a_ref);
const int64 max_of_a = context->MaxOf(a_ref);
context->AddImplyInDomain(a_is_positive, a_ref,
{0, std::numeric_limits<int64_t>::max()});
context->AddImplyInDomain(NegatedRef(a_is_positive), a_ref,
{std::numeric_limits<int64_t>::min(), -1});
const int64_t min_of_a = context->MinOf(a_ref);
const int64_t max_of_a = context->MaxOf(a_ref);
const int pos_a_ref = context->NewIntVar({0, max_of_a});
AddXEqualYOrXEqualZero(a_is_positive, pos_a_ref, a_ref, context);
@@ -412,7 +420,7 @@ void ExpandInverse(ConstraintProto* ct, PresolveContext* context) {
// Reduce the domains of each variable by checking that the inverse value
// exists.
std::vector<int64> possible_values;
std::vector<int64_t> possible_values;
// Propagate from one vector to its counterpart.
// Note this reaches the fixpoint as there is a one to one mapping between
// (variable-value) pairs in each vector.
@@ -460,7 +468,7 @@ void ExpandInverse(ConstraintProto* ct, PresolveContext* context) {
const int f_i = ct->inverse().f_direct(i);
const Domain domain = context->DomainOf(f_i);
for (const ClosedInterval& interval : domain) {
for (int64 j = interval.start; j <= interval.end; ++j) {
for (int64_t j = interval.start; j <= interval.end; ++j) {
// We have f[i] == j <=> r[j] == i;
const int r_j = ct->inverse().f_inverse(j);
int r_j_i;
@@ -490,13 +498,13 @@ void ExpandElement(ConstraintProto* ct, PresolveContext* context) {
}
bool all_constants = true;
absl::flat_hash_map<int64, int> constant_var_values_usage;
std::vector<int64> constant_var_values;
std::vector<int64> invalid_indices;
absl::flat_hash_map<int64_t, int> constant_var_values_usage;
std::vector<int64_t> constant_var_values;
std::vector<int64_t> invalid_indices;
Domain index_domain = context->DomainOf(index_ref);
Domain target_domain = context->DomainOf(target_ref);
for (const ClosedInterval& interval : index_domain) {
for (int64 v = interval.start; v <= interval.end; ++v) {
for (int64_t v = interval.start; v <= interval.end; ++v) {
const int var = element.vars(v);
const Domain var_domain = context->DomainOf(var);
if (var_domain.IntersectionWith(target_domain).IsEmpty()) {
@@ -508,7 +516,7 @@ void ExpandElement(ConstraintProto* ct, PresolveContext* context) {
break;
}
const int64 value = var_domain.Min();
const int64_t value = var_domain.Min();
if (constant_var_values_usage[value]++ == 0) {
constant_var_values.push_back(value);
}
@@ -531,7 +539,7 @@ void ExpandElement(ConstraintProto* ct, PresolveContext* context) {
// no longer valid for the target variable. They are created only for values
// that have multiples literals supporting them.
// Order is not important.
absl::flat_hash_map<int64, BoolArgumentProto*> supports;
absl::flat_hash_map<int64_t, BoolArgumentProto*> supports;
if (all_constants && target_ref != index_ref) {
if (!context->IntersectDomainWith(
target_ref, Domain::FromValues(constant_var_values))) {
@@ -547,7 +555,7 @@ void ExpandElement(ConstraintProto* ct, PresolveContext* context) {
}
for (const ClosedInterval& interval : target_domain) {
for (int64 v = interval.start; v <= interval.end; ++v) {
for (int64_t v = interval.start; v <= interval.end; ++v) {
const int usage = gtl::FindOrDie(constant_var_values_usage, v);
if (usage > 1) {
const int lit = context->GetOrCreateVarValueEncoding(target_ref, v);
@@ -565,7 +573,7 @@ void ExpandElement(ConstraintProto* ct, PresolveContext* context) {
auto* bool_or = context->working_model->add_constraints()->mutable_bool_or();
for (const ClosedInterval& interval : index_domain) {
for (int64 v = interval.start; v <= interval.end; ++v) {
for (int64_t v = interval.start; v <= interval.end; ++v) {
const int var = element.vars(v);
const int index_lit = context->GetOrCreateVarValueEncoding(index_ref, v);
const Domain var_domain = context->DomainOf(var);
@@ -582,7 +590,7 @@ void ExpandElement(ConstraintProto* ct, PresolveContext* context) {
context->AddImplyInDomain(index_lit, var, target_domain);
} else if (var_domain.Size() == 1) {
if (all_constants) {
const int64 value = var_domain.Min();
const int64_t value = var_domain.Min();
if (constant_var_values_usage[value] > 1) {
// The encoding literal for 'value' of the target_ref has been
// created before.
@@ -611,10 +619,10 @@ void ExpandElement(ConstraintProto* ct, PresolveContext* context) {
}
if (all_constants) {
const int64 var_min = target_domain.Min();
const int64_t var_min = target_domain.Min();
// Scan all values to find the one with the most literals attached.
int64 most_frequent_value = kint64max;
int64_t most_frequent_value = std::numeric_limits<int64_t>::max();
int usage = -1;
for (const auto it : constant_var_values_usage) {
if (it.second > usage ||
@@ -631,7 +639,7 @@ void ExpandElement(ConstraintProto* ct, PresolveContext* context) {
// coefficients are positive).
// TODO(user): Benchmark if using base is always beneficial.
// TODO(user): Try not to create this if max_usage == 1.
const int64 base =
const int64_t base =
usage > 2 && usage > size / 10 ? most_frequent_value : var_min;
if (base != var_min) {
VLOG(3) << "expand element: choose " << base << " with usage " << usage
@@ -640,15 +648,15 @@ void ExpandElement(ConstraintProto* ct, PresolveContext* context) {
LinearConstraintProto* const linear =
context->working_model->add_constraints()->mutable_linear();
int64 rhs = -base;
int64_t rhs = -base;
linear->add_vars(target_ref);
linear->add_coeffs(-1);
for (const ClosedInterval& interval : index_domain) {
for (int64 v = interval.start; v <= interval.end; ++v) {
for (int64_t v = interval.start; v <= interval.end; ++v) {
const int ref = element.vars(v);
const int index_lit =
context->GetOrCreateVarValueEncoding(index_ref, v);
const int64 delta = context->DomainOf(ref).Min() - base;
const int64_t delta = context->DomainOf(ref).Min() - base;
if (RefIsPositive(index_lit)) {
linear->add_vars(index_lit);
linear->add_coeffs(delta);
@@ -672,8 +680,8 @@ void ExpandElement(ConstraintProto* ct, PresolveContext* context) {
// Adds clauses so that literals[i] true <=> encoding[value[i]] true.
// This also implicitly use the fact that exactly one alternative is true.
void LinkLiteralsAndValues(
const std::vector<int>& value_literals, const std::vector<int64>& values,
const absl::flat_hash_map<int64, int>& target_encoding,
const std::vector<int>& value_literals, const std::vector<int64_t>& values,
const absl::flat_hash_map<int64_t, int>& target_encoding,
PresolveContext* context) {
CHECK_EQ(value_literals.size(), values.size());
@@ -685,7 +693,7 @@ void LinkLiteralsAndValues(
// value is false too (i.e not possible). Conversely, if the tuple is
// selected, the value must be selected.
for (int i = 0; i < values.size(); ++i) {
const int64 v = values[i];
const int64_t v = values[i];
CHECK(target_encoding.contains(v));
const int lit = gtl::FindOrDie(target_encoding, v);
value_literals_per_target_literal[lit].push_back(value_literals[i]);
@@ -724,8 +732,8 @@ void ExpandAutomaton(ConstraintProto* ct, PresolveContext* context) {
AutomatonConstraintProto& proto = *ct->mutable_automaton();
if (proto.vars_size() == 0) {
const int64 initial_state = proto.starting_state();
for (const int64 final_state : proto.final_states()) {
const int64_t initial_state = proto.starting_state();
for (const int64_t final_state : proto.final_states()) {
if (initial_state == final_state) {
context->UpdateRuleStats("automaton: empty constraint");
ct->Clear();
@@ -743,17 +751,17 @@ void ExpandAutomaton(ConstraintProto* ct, PresolveContext* context) {
const std::vector<int> vars = {proto.vars().begin(), proto.vars().end()};
// Compute the set of reachable state at each time point.
const absl::flat_hash_set<int64> final_states(
const absl::flat_hash_set<int64_t> final_states(
{proto.final_states().begin(), proto.final_states().end()});
std::vector<absl::flat_hash_set<int64>> reachable_states(n + 1);
std::vector<absl::flat_hash_set<int64_t>> reachable_states(n + 1);
reachable_states[0].insert(proto.starting_state());
// Forward pass.
for (int time = 0; time < n; ++time) {
for (int t = 0; t < proto.transition_tail_size(); ++t) {
const int64 tail = proto.transition_tail(t);
const int64 label = proto.transition_label(t);
const int64 head = proto.transition_head(t);
const int64_t tail = proto.transition_tail(t);
const int64_t label = proto.transition_label(t);
const int64_t head = proto.transition_head(t);
if (!reachable_states[time].contains(tail)) continue;
if (!context->DomainContains(vars[time], label)) continue;
if (time == n - 1 && !final_states.contains(head)) continue;
@@ -763,11 +771,11 @@ void ExpandAutomaton(ConstraintProto* ct, PresolveContext* context) {
// Backward pass.
for (int time = n - 1; time >= 0; --time) {
absl::flat_hash_set<int64> new_set;
absl::flat_hash_set<int64_t> new_set;
for (int t = 0; t < proto.transition_tail_size(); ++t) {
const int64 tail = proto.transition_tail(t);
const int64 label = proto.transition_label(t);
const int64 head = proto.transition_head(t);
const int64_t tail = proto.transition_tail(t);
const int64_t label = proto.transition_label(t);
const int64_t head = proto.transition_head(t);
if (!reachable_states[time].contains(tail)) continue;
if (!context->DomainContains(vars[time], label)) continue;
@@ -782,22 +790,22 @@ void ExpandAutomaton(ConstraintProto* ct, PresolveContext* context) {
// initial state, and at time n we should be in one of the final states. We
// don't need to create Booleans at at time when there is just one possible
// state (like at time zero).
absl::flat_hash_map<int64, int> encoding;
absl::flat_hash_map<int64, int> in_encoding;
absl::flat_hash_map<int64, int> out_encoding;
absl::flat_hash_map<int64_t, int> encoding;
absl::flat_hash_map<int64_t, int> in_encoding;
absl::flat_hash_map<int64_t, int> out_encoding;
bool removed_values = false;
for (int time = 0; time < n; ++time) {
// All these vector have the same size. We will use them to enforce a
// local table constraint representing one step of the automaton at the
// given time.
std::vector<int64> in_states;
std::vector<int64> transition_values;
std::vector<int64> out_states;
std::vector<int64_t> in_states;
std::vector<int64_t> transition_values;
std::vector<int64_t> out_states;
for (int i = 0; i < proto.transition_label_size(); ++i) {
const int64 tail = proto.transition_tail(i);
const int64 label = proto.transition_label(i);
const int64 head = proto.transition_head(i);
const int64_t tail = proto.transition_tail(i);
const int64_t label = proto.transition_label(i);
const int64_t head = proto.transition_head(i);
if (!reachable_states[time].contains(tail)) continue;
if (!reachable_states[time + 1].contains(head)) continue;
@@ -848,7 +856,7 @@ void ExpandAutomaton(ConstraintProto* ct, PresolveContext* context) {
// Fully encode vars[time].
{
std::vector<int64> s = transition_values;
std::vector<int64_t> s = transition_values;
gtl::STLSortAndRemoveDuplicates(&s);
encoding.clear();
@@ -859,7 +867,7 @@ void ExpandAutomaton(ConstraintProto* ct, PresolveContext* context) {
// Fully encode the variable.
for (const ClosedInterval& interval : context->DomainOf(vars[time])) {
for (int64 v = interval.start; v <= interval.end; ++v) {
for (int64_t v = interval.start; v <= interval.end; ++v) {
encoding[v] = context->GetOrCreateVarValueEncoding(vars[time], v);
}
}
@@ -867,7 +875,7 @@ void ExpandAutomaton(ConstraintProto* ct, PresolveContext* context) {
// For each possible out states, create one Boolean variable.
{
std::vector<int64> s = out_states;
std::vector<int64_t> s = out_states;
gtl::STLSortAndRemoveDuplicates(&s);
out_encoding.clear();
@@ -876,7 +884,7 @@ void ExpandAutomaton(ConstraintProto* ct, PresolveContext* context) {
out_encoding[s.front()] = var;
out_encoding[s.back()] = NegatedRef(var);
} else if (s.size() > 2) {
for (const int64 state : s) {
for (const int64_t state : s) {
out_encoding[state] = context->NewBoolVar();
}
}
@@ -907,7 +915,7 @@ void ExpandNegativeTable(ConstraintProto* ct, PresolveContext* context) {
TableConstraintProto& table = *ct->mutable_table();
const int num_vars = table.vars_size();
const int num_original_tuples = table.values_size() / num_vars;
std::vector<std::vector<int64>> tuples(num_original_tuples);
std::vector<std::vector<int64_t>> tuples(num_original_tuples);
int count = 0;
for (int i = 0; i < num_original_tuples; ++i) {
for (int j = 0; j < num_vars; ++j) {
@@ -922,8 +930,8 @@ void ExpandNegativeTable(ConstraintProto* ct, PresolveContext* context) {
}
// Compress tuples.
const int64 any_value = kint64min;
std::vector<int64> domain_sizes;
const int64_t any_value = std::numeric_limits<int64_t>::min();
std::vector<int64_t> domain_sizes;
for (int i = 0; i < num_vars; ++i) {
domain_sizes.push_back(context->DomainOf(table.vars(i)).Size());
}
@@ -931,10 +939,10 @@ void ExpandNegativeTable(ConstraintProto* ct, PresolveContext* context) {
// For each tuple, forbid the variables values to be this tuple.
std::vector<int> clause;
for (const std::vector<int64>& tuple : tuples) {
for (const std::vector<int64_t>& tuple : tuples) {
clause.clear();
for (int i = 0; i < num_vars; ++i) {
const int64 value = tuple[i];
const int64_t value = tuple[i];
if (value == any_value) continue;
const int literal =
@@ -976,18 +984,18 @@ void ExpandLinMin(ConstraintProto* ct, PresolveContext* context) {
// tuples_with_any vector provides a list of tuple_literals that will support
// any value.
void ProcessOneVariable(const std::vector<int>& tuple_literals,
const std::vector<int64>& values, int variable,
const std::vector<int64_t>& values, int variable,
const std::vector<int>& tuples_with_any,
PresolveContext* context) {
VLOG(2) << "Process var(" << variable << ") with domain "
<< context->DomainOf(variable) << " and " << values.size()
<< " active tuples, and " << tuples_with_any.size() << " any tuples";
CHECK_EQ(tuple_literals.size(), values.size());
std::vector<std::pair<int64, int>> pairs;
std::vector<std::pair<int64_t, int>> pairs;
// Collect pairs of value-literal.
for (int i = 0; i < values.size(); ++i) {
const int64 value = values[i];
const int64_t value = values[i];
CHECK(context->DomainContains(variable, value));
pairs.emplace_back(value, tuple_literals[i]);
}
@@ -998,7 +1006,7 @@ void ProcessOneVariable(const std::vector<int>& tuple_literals,
std::sort(pairs.begin(), pairs.end());
for (int i = 0; i < pairs.size();) {
selected.clear();
const int64 value = pairs[i].first;
const int64_t value = pairs[i].first;
for (; i < pairs.size() && pairs[i].first == value; ++i) {
selected.push_back(pairs[i].second);
}
@@ -1027,8 +1035,9 @@ void ProcessOneVariable(const std::vector<int>& tuple_literals,
// Simpler encoding for table constraints with 2 variables.
void AddSizeTwoTable(
const std::vector<int>& vars, const std::vector<std::vector<int64>>& tuples,
const std::vector<absl::flat_hash_set<int64>>& values_per_var,
const std::vector<int>& vars,
const std::vector<std::vector<int64_t>>& tuples,
const std::vector<absl::flat_hash_set<int64_t>>& values_per_var,
PresolveContext* context) {
CHECK_EQ(vars.size(), 2);
const int left_var = vars[0];
@@ -1044,8 +1053,8 @@ void AddSizeTwoTable(
std::map<int, std::vector<int>> right_to_left;
for (const auto& tuple : tuples) {
const int64 left_value(tuple[0]);
const int64 right_value(tuple[1]);
const int64_t left_value(tuple[0]);
const int64_t right_value(tuple[1]);
CHECK(context->DomainContains(left_var, left_value));
CHECK(context->DomainContains(right_var, right_value));
@@ -1101,7 +1110,7 @@ void ExpandPositiveTable(ConstraintProto* ct, PresolveContext* context) {
const int num_original_tuples = table.values_size() / num_vars;
// Read tuples flat array and recreate the vector of tuples.
std::vector<std::vector<int64>> tuples(num_original_tuples);
std::vector<std::vector<int64_t>> tuples(num_original_tuples);
int count = 0;
for (int tuple_index = 0; tuple_index < num_original_tuples; ++tuple_index) {
for (int var_index = 0; var_index < num_vars; ++var_index) {
@@ -1111,12 +1120,12 @@ void ExpandPositiveTable(ConstraintProto* ct, PresolveContext* context) {
// Compute the set of possible values for each variable (from the table).
// Remove invalid tuples along the way.
std::vector<absl::flat_hash_set<int64>> values_per_var(num_vars);
std::vector<absl::flat_hash_set<int64_t>> values_per_var(num_vars);
int new_size = 0;
for (int tuple_index = 0; tuple_index < num_original_tuples; ++tuple_index) {
bool keep = true;
for (int var_index = 0; var_index < num_vars; ++var_index) {
const int64 value = tuples[tuple_index][var_index];
const int64_t value = tuples[tuple_index][var_index];
if (!context->DomainContains(vars[var_index], value)) {
keep = false;
break;
@@ -1175,8 +1184,8 @@ void ExpandPositiveTable(ConstraintProto* ct, PresolveContext* context) {
// tuples.
int num_prefix_tuples = 0;
{
absl::flat_hash_set<absl::Span<const int64>> prefixes;
for (const std::vector<int64>& tuple : tuples) {
absl::flat_hash_set<absl::Span<const int64_t>> prefixes;
for (const std::vector<int64_t>& tuple : tuples) {
prefixes.insert(absl::MakeSpan(tuple.data(), num_vars - 1));
}
num_prefix_tuples = prefixes.size();
@@ -1185,8 +1194,8 @@ void ExpandPositiveTable(ConstraintProto* ct, PresolveContext* context) {
// TODO(user): reinvestigate ExploreSubsetOfVariablesAndAddNegatedTables.
// Compress tuples.
const int64 any_value = kint64min;
std::vector<int64> domain_sizes;
const int64_t any_value = std::numeric_limits<int64_t>::min();
std::vector<int64_t> domain_sizes;
for (int i = 0; i < num_vars; ++i) {
domain_sizes.push_back(values_per_var[i].size());
}
@@ -1214,7 +1223,7 @@ void ExpandPositiveTable(ConstraintProto* ct, PresolveContext* context) {
// Debug message to log the status of the expansion.
if (VLOG_IS_ON(2)) {
// Compute the maximum number of prefix tuples.
int64 max_num_prefix_tuples = 1;
int64_t max_num_prefix_tuples = 1;
for (int var_index = 0; var_index + 1 < num_vars; ++var_index) {
max_num_prefix_tuples =
CapProd(max_num_prefix_tuples, values_per_var[var_index].size());
@@ -1287,7 +1296,7 @@ void ExpandPositiveTable(ConstraintProto* ct, PresolveContext* context) {
}
std::vector<int> active_tuple_literals;
std::vector<int64> active_values;
std::vector<int64_t> active_values;
std::vector<int> any_tuple_literals;
for (int var_index = 0; var_index < num_vars; ++var_index) {
if (values_per_var[var_index].size() == 1) continue;
@@ -1297,7 +1306,7 @@ void ExpandPositiveTable(ConstraintProto* ct, PresolveContext* context) {
any_tuple_literals.clear();
for (int tuple_index = 0; tuple_index < tuple_literals.size();
++tuple_index) {
const int64 value = tuples[tuple_index][var_index];
const int64_t value = tuples[tuple_index][var_index];
const int tuple_literal = tuple_literals[tuple_index];
if (value == any_value) {
@@ -1339,7 +1348,7 @@ void ExpandAllDiff(bool expand_non_permutations, ConstraintProto* ct,
// equation per value stating that this value can be assigned at most once, or
// exactly once in case of permutation.
for (const ClosedInterval& interval : union_of_domains) {
for (int64 v = interval.start; v <= interval.end; ++v) {
for (int64_t v = interval.start; v <= interval.end; ++v) {
// Collect references which domain contains v.
std::vector<int> possible_refs;
int fixed_variable_count = 0;
@@ -1460,7 +1469,7 @@ void ExpandCpModel(PresolveContext* context) {
}
if (skip) continue; // Nothing was done for this constraint.
// Update variable-contraint graph.
// Update variable-constraint graph.
context->UpdateNewConstraintsVariableUsage();
if (ct->constraint_case() == ConstraintProto::CONSTRAINT_NOT_SET) {
context->UpdateConstraintVariableUsage(i);