OR-Tools  8.0
cp_model_loader.cc
Go to the documentation of this file.
1 // Copyright 2010-2018 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
15 
16 #include <algorithm>
17 #include <map>
18 #include <memory>
19 #include <set>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "absl/container/flat_hash_map.h"
25 #include "absl/container/flat_hash_set.h"
26 #include "ortools/base/int_type.h"
28 #include "ortools/base/logging.h"
29 #include "ortools/base/map_util.h"
30 #include "ortools/base/stl_util.h"
32 #include "ortools/sat/circuit.h"
36 #include "ortools/sat/cumulative.h"
37 #include "ortools/sat/diffn.h"
40 #include "ortools/sat/integer.h"
42 #include "ortools/sat/intervals.h"
45 #include "ortools/sat/sat_base.h"
47 #include "ortools/sat/sat_solver.h"
48 #include "ortools/sat/table.h"
51 
52 namespace operations_research {
53 namespace sat {
54 
55 namespace {
56 
57 template <typename Values>
58 std::vector<int64> ValuesFromProto(const Values& values) {
59  return std::vector<int64>(values.begin(), values.end());
60 }
61 
62 void ComputeLinearBounds(const LinearConstraintProto& proto,
63  CpModelMapping* mapping, IntegerTrail* integer_trail,
64  int64* sum_min, int64* sum_max) {
65  *sum_min = 0;
66  *sum_max = 0;
67 
68  for (int i = 0; i < proto.vars_size(); ++i) {
69  const int64 coeff = proto.coeffs(i);
70  const IntegerVariable var = mapping->Integer(proto.vars(i));
71  const int64 lb = integer_trail->LowerBound(var).value();
72  const int64 ub = integer_trail->UpperBound(var).value();
73  if (coeff >= 0) {
74  (*sum_min) += coeff * lb;
75  (*sum_max) += coeff * ub;
76  } else {
77  (*sum_min) += coeff * ub;
78  (*sum_max) += coeff * lb;
79  }
80  }
81 }
82 
83 // We check if the constraint is a sum(ax * xi) == value.
84 bool ConstraintIsEq(const LinearConstraintProto& proto) {
85  return proto.domain_size() == 2 && proto.domain(0) == proto.domain(1);
86 }
87 
88 // We check if the constraint is a sum(ax * xi) != value.
89 bool ConstraintIsNEq(const LinearConstraintProto& proto,
90  CpModelMapping* mapping, IntegerTrail* integer_trail,
91  int64* single_value) {
92  int64 sum_min = 0;
93  int64 sum_max = 0;
94  ComputeLinearBounds(proto, mapping, integer_trail, &sum_min, &sum_max);
95 
96  const Domain complement =
97  Domain(sum_min, sum_max)
98  .IntersectionWith(ReadDomainFromProto(proto).Complement());
99  if (complement.IsEmpty()) return false;
100  const int64 value = complement.Min();
101 
102  if (complement.Size() == 1) {
103  if (single_value != nullptr) {
104  *single_value = value;
105  }
106  return true;
107  }
108  return false;
109 }
110 
111 } // namespace
112 
114  bool view_all_booleans_as_integers,
115  Model* m) {
116  const int num_proto_variables = model_proto.variables_size();
117 
118  // All [0, 1] variables always have a corresponding Boolean, even if it is
119  // fixed to 0 (domain == [0,0]) or fixed to 1 (domain == [1,1]).
120  {
121  auto* sat_solver = m->GetOrCreate<SatSolver>();
122  CHECK_EQ(sat_solver->NumVariables(), 0);
123 
124  BooleanVariable new_var(0);
125  std::vector<BooleanVariable> false_variables;
126  std::vector<BooleanVariable> true_variables;
127 
128  booleans_.resize(num_proto_variables, kNoBooleanVariable);
129  reverse_boolean_map_.resize(num_proto_variables, -1);
130  for (int i = 0; i < num_proto_variables; ++i) {
131  const auto& domain = model_proto.variables(i).domain();
132  if (domain.size() != 2) continue;
133  if (domain[0] >= 0 && domain[1] <= 1) {
134  booleans_[i] = new_var;
135  reverse_boolean_map_[new_var] = i;
136  if (domain[1] == 0) {
137  false_variables.push_back(new_var);
138  } else if (domain[0] == 1) {
139  true_variables.push_back(new_var);
140  }
141  ++new_var;
142  }
143  }
144 
145  sat_solver->SetNumVariables(new_var.value());
146  for (const BooleanVariable var : true_variables) {
147  m->Add(ClauseConstraint({sat::Literal(var, true)}));
148  }
149  for (const BooleanVariable var : false_variables) {
150  m->Add(ClauseConstraint({sat::Literal(var, false)}));
151  }
152  }
153 
154  // Compute the list of positive variable reference for which we need to
155  // create an IntegerVariable.
156  std::vector<int> var_to_instantiate_as_integer;
157  if (view_all_booleans_as_integers) {
158  var_to_instantiate_as_integer.resize(num_proto_variables);
159  for (int i = 0; i < num_proto_variables; ++i) {
160  var_to_instantiate_as_integer[i] = i;
161  }
162  } else {
163  // Compute the integer variable references used by the model.
164  absl::flat_hash_set<int> used_variables;
165 
166  IndexReferences refs;
167  for (int c = 0; c < model_proto.constraints_size(); ++c) {
168  const ConstraintProto& ct = model_proto.constraints(c);
170  for (const int ref : refs.variables) {
171  used_variables.insert(PositiveRef(ref));
172  }
173  }
174 
175  // Add the objectives and search heuristics variables that needs to be
176  // referenceable as integer even if they are only used as Booleans.
177  if (model_proto.has_objective()) {
178  for (const int obj_var : model_proto.objective().vars()) {
179  used_variables.insert(PositiveRef(obj_var));
180  }
181  }
182  for (const DecisionStrategyProto& strategy :
183  model_proto.search_strategy()) {
184  for (const int var : strategy.variables()) {
185  used_variables.insert(PositiveRef(var));
186  }
187  }
188 
189  // Make sure any unused variable, that is not already a Boolean is
190  // considered "used".
191  for (int i = 0; i < num_proto_variables; ++i) {
192  if (booleans_[i] == kNoBooleanVariable) {
193  used_variables.insert(i);
194  }
195  }
196 
197  // We want the variable in the problem order.
198  var_to_instantiate_as_integer.assign(used_variables.begin(),
199  used_variables.end());
200  gtl::STLSortAndRemoveDuplicates(&var_to_instantiate_as_integer);
201  }
202  integers_.resize(num_proto_variables, kNoIntegerVariable);
203 
204  auto* integer_trail = m->GetOrCreate<IntegerTrail>();
205  integer_trail->ReserveSpaceForNumVariables(
206  var_to_instantiate_as_integer.size());
207  reverse_integer_map_.resize(2 * var_to_instantiate_as_integer.size(), -1);
208  for (const int i : var_to_instantiate_as_integer) {
209  const auto& var_proto = model_proto.variables(i);
210  integers_[i] =
211  integer_trail->AddIntegerVariable(ReadDomainFromProto(var_proto));
212  DCHECK_LT(integers_[i], reverse_integer_map_.size());
213  reverse_integer_map_[integers_[i]] = i;
214  }
215 
216  auto* encoder = m->GetOrCreate<IntegerEncoder>();
217 
218  // Link any variable that has both views.
219  for (int i = 0; i < num_proto_variables; ++i) {
220  if (integers_[i] == kNoIntegerVariable) continue;
221  if (booleans_[i] == kNoBooleanVariable) continue;
222 
223  // Associate with corresponding integer variable.
224  encoder->AssociateToIntegerEqualValue(sat::Literal(booleans_[i], true),
225  integers_[i], IntegerValue(1));
226  }
227 
228  // Create the interval variables.
229  intervals_.resize(model_proto.constraints_size(), kNoIntervalVariable);
230  for (int c = 0; c < model_proto.constraints_size(); ++c) {
231  const ConstraintProto& ct = model_proto.constraints(c);
232  if (ct.constraint_case() != ConstraintProto::ConstraintCase::kInterval) {
233  continue;
234  }
235  if (HasEnforcementLiteral(ct)) {
236  const sat::Literal enforcement_literal =
237  Literal(ct.enforcement_literal(0));
238  // TODO(user): Fix the constant variable situation. An optional interval
239  // with constant start/end or size cannot share the same constant
240  // variable if it is used in non-optional situation.
241  intervals_[c] = m->Add(NewOptionalInterval(
242  Integer(ct.interval().start()), Integer(ct.interval().end()),
243  Integer(ct.interval().size()), enforcement_literal));
244  } else {
245  intervals_[c] = m->Add(NewInterval(Integer(ct.interval().start()),
246  Integer(ct.interval().end()),
247  Integer(ct.interval().size())));
248  }
249  already_loaded_ct_.insert(&ct);
250  }
251 }
252 
253 // The logic assumes that the linear constraints have been presolved, so that
254 // equality with a domain bound have been converted to <= or >= and so that we
255 // never have any trivial inequalities.
256 //
257 // TODO(user): Regroup/presolve two encoding like b => x > 2 and the same
258 // Boolean b => x > 5. These shouldn't happen if we merge linear constraints.
260  Model* m) {
261  auto* encoder = m->GetOrCreate<IntegerEncoder>();
262  auto* integer_trail = m->GetOrCreate<IntegerTrail>();
263  auto* sat_solver = m->GetOrCreate<SatSolver>();
264 
265  // TODO(user): Debug what makes it unsat at this point.
266  if (sat_solver->IsModelUnsat()) return;
267 
268  // Detection of literal equivalent to (i_var == value). We collect all the
269  // half-reified constraint lit => equality or lit => inequality for a given
270  // variable, and we will later sort them to detect equivalence.
271  struct EqualityDetectionHelper {
272  const ConstraintProto* ct;
274  int64 value;
275  bool is_equality; // false if != instead.
276 
277  bool operator<(const EqualityDetectionHelper& o) const {
278  if (literal.Variable() == o.literal.Variable()) {
279  if (value == o.value) return is_equality && !o.is_equality;
280  return value < o.value;
281  }
282  return literal.Variable() < o.literal.Variable();
283  }
284  };
285  std::vector<std::vector<EqualityDetectionHelper>> var_to_equalities(
286  model_proto.variables_size());
287 
288  // TODO(user): We will re-add the same implied bounds during probing, so
289  // it might not be necessary to do that here. Also, it might be too early
290  // if some of the literal view used in the LP are created later, but that
291  // should be fixable via calls to implied_bounds->NotifyNewIntegerView().
292  auto* implied_bounds = m->GetOrCreate<ImpliedBounds>();
293 
294  // Detection of literal equivalent to (i_var >= bound). We also collect
295  // all the half-refied part and we will sort the vector for detection of the
296  // equivalence.
297  struct InequalityDetectionHelper {
298  const ConstraintProto* ct;
300  IntegerLiteral i_lit;
301 
302  bool operator<(const InequalityDetectionHelper& o) const {
303  if (literal.Variable() == o.literal.Variable()) {
304  return i_lit.var < o.i_lit.var;
305  }
306  return literal.Variable() < o.literal.Variable();
307  }
308  };
309  std::vector<InequalityDetectionHelper> inequalities;
310 
311  // Loop over all contraints and fill var_to_equalities and inequalities.
312  for (const ConstraintProto& ct : model_proto.constraints()) {
313  if (ct.constraint_case() != ConstraintProto::ConstraintCase::kLinear) {
314  continue;
315  }
316  if (ct.enforcement_literal().size() != 1) continue;
317  if (ct.linear().vars_size() != 1) continue;
318 
319  // ct is a linear constraint with one term and one enforcement literal.
320  const sat::Literal enforcement_literal = Literal(ct.enforcement_literal(0));
321  const int ref = ct.linear().vars(0);
322  const int var = PositiveRef(ref);
323 
324  const Domain domain = ReadDomainFromProto(model_proto.variables(var));
325  const Domain domain_if_enforced =
326  ReadDomainFromProto(ct.linear())
327  .InverseMultiplicationBy(ct.linear().coeffs(0) *
328  (RefIsPositive(ref) ? 1 : -1));
329 
330  // Detect enforcement_literal => (var >= value or var <= value).
331  if (domain_if_enforced.NumIntervals() == 1) {
332  if (domain_if_enforced.Max() >= domain.Max() &&
333  domain_if_enforced.Min() > domain.Min()) {
334  inequalities.push_back(
335  {&ct, enforcement_literal,
337  Integer(var), IntegerValue(domain_if_enforced.Min()))});
338  implied_bounds->Add(enforcement_literal, inequalities.back().i_lit);
339  } else if (domain_if_enforced.Min() <= domain.Min() &&
340  domain_if_enforced.Max() < domain.Max()) {
341  inequalities.push_back(
342  {&ct, enforcement_literal,
344  Integer(var), IntegerValue(domain_if_enforced.Max()))});
345  implied_bounds->Add(enforcement_literal, inequalities.back().i_lit);
346  }
347  }
348 
349  // Detect enforcement_literal => (var == value or var != value).
350  //
351  // Note that for domain with 2 values like [0, 1], we will detect both ==
352  // 0 and != 1. Similarly, for a domain in [min, max], we should both
353  // detect (== min) and (<= min), and both detect (== max) and (>= max).
354  {
355  const Domain inter = domain.IntersectionWith(domain_if_enforced);
356  if (!inter.IsEmpty() && inter.Min() == inter.Max()) {
357  var_to_equalities[var].push_back(
358  {&ct, enforcement_literal, inter.Min(), true});
359  if (domain.Contains(inter.Min())) {
360  variables_to_encoded_values_[var].insert(inter.Min());
361  }
362  }
363  }
364  {
365  const Domain inter =
366  domain.IntersectionWith(domain_if_enforced.Complement());
367  if (!inter.IsEmpty() && inter.Min() == inter.Max()) {
368  var_to_equalities[var].push_back(
369  {&ct, enforcement_literal, inter.Min(), false});
370  if (domain.Contains(inter.Min())) {
371  variables_to_encoded_values_[var].insert(inter.Min());
372  }
373  }
374  }
375  }
376 
377  // Detect Literal <=> X >= value
378  int num_inequalities = 0;
379  std::sort(inequalities.begin(), inequalities.end());
380  for (int i = 0; i + 1 < inequalities.size(); i++) {
381  if (inequalities[i].literal != inequalities[i + 1].literal.Negated()) {
382  continue;
383  }
384 
385  // TODO(user): In these cases, we could fix the enforcement literal right
386  // away or ignore the constraint. Note that it will be done later anyway
387  // though.
388  if (integer_trail->IntegerLiteralIsTrue(inequalities[i].i_lit) ||
389  integer_trail->IntegerLiteralIsFalse(inequalities[i].i_lit)) {
390  continue;
391  }
392  if (integer_trail->IntegerLiteralIsTrue(inequalities[i + 1].i_lit) ||
393  integer_trail->IntegerLiteralIsFalse(inequalities[i + 1].i_lit)) {
394  continue;
395  }
396 
397  const auto pair_a = encoder->Canonicalize(inequalities[i].i_lit);
398  const auto pair_b = encoder->Canonicalize(inequalities[i + 1].i_lit);
399  if (pair_a.first == pair_b.second) {
400  ++num_inequalities;
401  encoder->AssociateToIntegerLiteral(inequalities[i].literal,
402  inequalities[i].i_lit);
403  already_loaded_ct_.insert(inequalities[i].ct);
404  already_loaded_ct_.insert(inequalities[i + 1].ct);
405  }
406  }
407 
408  // Encode the half-inequalities.
409  int num_half_inequalities = 0;
410  for (const auto inequality : inequalities) {
411  if (ConstraintIsAlreadyLoaded(inequality.ct)) continue;
412  m->Add(
413  Implication(inequality.literal,
414  encoder->GetOrCreateAssociatedLiteral(inequality.i_lit)));
415  if (sat_solver->IsModelUnsat()) return;
416 
417  ++num_half_inequalities;
418  already_loaded_ct_.insert(inequality.ct);
419  is_half_encoding_ct_.insert(inequality.ct);
420  }
421 
422  if (!inequalities.empty()) {
423  VLOG(1) << num_inequalities << " literals associated to VAR >= value, and "
424  << num_half_inequalities << " half-associations.";
425  }
426 
427  // Detect Literal <=> X == value and associate them in the IntegerEncoder.
428  //
429  // TODO(user): Fully encode variable that are almost fully encoded?
430  int num_constraints = 0;
431  int num_equalities = 0;
432  int num_half_equalities = 0;
433  int num_fully_encoded = 0;
434  int num_partially_encoded = 0;
435  for (int i = 0; i < var_to_equalities.size(); ++i) {
436  std::vector<EqualityDetectionHelper>& encoding = var_to_equalities[i];
437  std::sort(encoding.begin(), encoding.end());
438  if (encoding.empty()) continue;
439  num_constraints += encoding.size();
440 
441  absl::flat_hash_set<int64> values;
442  for (int j = 0; j + 1 < encoding.size(); j++) {
443  if ((encoding[j].value != encoding[j + 1].value) ||
444  (encoding[j].literal != encoding[j + 1].literal.Negated()) ||
445  (encoding[j].is_equality != true) ||
446  (encoding[j + 1].is_equality != false)) {
447  continue;
448  }
449 
450  ++num_equalities;
451  encoder->AssociateToIntegerEqualValue(encoding[j].literal, integers_[i],
452  IntegerValue(encoding[j].value));
453  already_loaded_ct_.insert(encoding[j].ct);
454  already_loaded_ct_.insert(encoding[j + 1].ct);
455  values.insert(encoding[j].value);
456  }
457 
458  // TODO(user): Try to remove it. Normally we caught UNSAT above, but
459  // tests are very flaky (it only happens in parallel). Keeping it there for
460  // the time being.
461  if (sat_solver->IsModelUnsat()) return;
462 
463  // Encode the half-equalities.
464  //
465  // TODO(user): delay this after PropagateEncodingFromEquivalenceRelations()?
466  // Otherwise we might create new Boolean variables for no reason. Note
467  // however, that in the presolve, we should only use the "representative" in
468  // linear constraints, so we should be fine.
469  for (const auto equality : encoding) {
470  if (ConstraintIsAlreadyLoaded(equality.ct)) continue;
471  const class Literal eq = encoder->GetOrCreateLiteralAssociatedToEquality(
472  integers_[i], IntegerValue(equality.value));
473  if (equality.is_equality) {
474  m->Add(Implication(equality.literal, eq));
475  } else {
476  m->Add(Implication(equality.literal, eq.Negated()));
477  }
478 
479  ++num_half_equalities;
480  already_loaded_ct_.insert(equality.ct);
481  is_half_encoding_ct_.insert(equality.ct);
482  }
483 
484  // Update stats.
485  if (VLOG_IS_ON(1)) {
486  if (encoder->VariableIsFullyEncoded(integers_[i])) {
487  ++num_fully_encoded;
488  } else {
489  ++num_partially_encoded;
490  }
491  }
492  }
493 
494  if (num_constraints > 0) {
495  VLOG(1) << num_equalities << " literals associated to VAR == value, and "
496  << num_half_equalities << " half-associations.";
497  }
498  if (num_fully_encoded > 0) {
499  VLOG(1) << "num_fully_encoded_variables: " << num_fully_encoded;
500  }
501  if (num_partially_encoded > 0) {
502  VLOG(1) << "num_partially_encoded_variables: " << num_partially_encoded;
503  }
504 }
505 
507  const CpModelProto& model_proto, Model* m) {
508  auto* encoder = m->GetOrCreate<IntegerEncoder>();
509  auto* sat_solver = m->GetOrCreate<SatSolver>();
510 
511  // Loop over all contraints and find affine ones.
512  int64 num_associations = 0;
513  int64 num_set_to_false = 0;
514  for (const ConstraintProto& ct : model_proto.constraints()) {
515  if (!ct.enforcement_literal().empty()) continue;
516  if (ct.constraint_case() != ConstraintProto::kLinear) continue;
517  if (ct.linear().vars_size() != 2) continue;
518  if (!ConstraintIsEq(ct.linear())) continue;
519 
520  const IntegerValue rhs(ct.linear().domain(0));
521 
522  // Make sure the coefficient are positive.
523  IntegerVariable var1 = Integer(ct.linear().vars(0));
524  IntegerVariable var2 = Integer(ct.linear().vars(1));
525  IntegerValue coeff1(ct.linear().coeffs(0));
526  IntegerValue coeff2(ct.linear().coeffs(1));
527  if (coeff1 < 0) {
528  var1 = NegationOf(var1);
529  coeff1 = -coeff1;
530  }
531  if (coeff2 < 0) {
532  var2 = NegationOf(var2);
533  coeff2 = -coeff2;
534  }
535 
536  // TODO(user): This is not supposed to happen, but apparently it did on
537  // once on routing_GCM_0001_sat.fzn. Investigate and fix.
538  if (coeff1 == 0 || coeff2 == 0) continue;
539 
540  // We first map the >= literals.
541  // It is important to do that first, since otherwise mapping a == literal
542  // might creates the underlying >= and <= literals.
543  for (int i = 0; i < 2; ++i) {
544  for (const auto value_literal :
545  encoder->PartialGreaterThanEncoding(var1)) {
546  const IntegerValue value1 = value_literal.first;
547  const IntegerValue bound2 = FloorRatio(rhs - value1 * coeff1, coeff2);
548  ++num_associations;
549  encoder->AssociateToIntegerLiteral(
550  value_literal.second, IntegerLiteral::LowerOrEqual(var2, bound2));
551  }
552  std::swap(var1, var2);
553  std::swap(coeff1, coeff2);
554  }
555 
556  // Same for the == literals.
557  //
558  // TODO(user): This is similar to LoadEquivalenceAC() for unreified
559  // constraints, but when the later is called, more encoding might have taken
560  // place.
561  for (int i = 0; i < 2; ++i) {
562  for (const auto value_literal : encoder->PartialDomainEncoding(var1)) {
563  const IntegerValue value1 = value_literal.value;
564  const IntegerValue intermediate = rhs - value1 * coeff1;
565  if (intermediate % coeff2 != 0) {
566  // Using this function deals properly with UNSAT.
567  ++num_set_to_false;
568  sat_solver->AddUnitClause(value_literal.literal.Negated());
569  continue;
570  }
571  ++num_associations;
572  encoder->AssociateToIntegerEqualValue(value_literal.literal, var2,
573  intermediate / coeff2);
574  }
575  std::swap(var1, var2);
576  std::swap(coeff1, coeff2);
577  }
578  }
579 
580  if (num_associations > 0) {
581  VLOG(1) << "Num associations from equivalences = " << num_associations;
582  }
583  if (num_set_to_false > 0) {
584  VLOG(1) << "Num literals set to false from equivalences = "
585  << num_set_to_false;
586  }
587 }
588 
590  Model* m) {
591  const SatParameters& parameters = *(m->GetOrCreate<SatParameters>());
592  if (!parameters.use_optional_variables()) return;
593  if (parameters.enumerate_all_solutions()) return;
594 
595  // The variables from the objective cannot be marked as optional!
596  const int num_proto_variables = model_proto.variables_size();
597  std::vector<bool> already_seen(num_proto_variables, false);
598  if (model_proto.has_objective()) {
599  for (const int ref : model_proto.objective().vars()) {
600  already_seen[PositiveRef(ref)] = true;
601  }
602  }
603 
604  // Compute for each variables the intersection of the enforcement literals
605  // of the constraints in which they appear.
606  //
607  // TODO(user): This deals with the simplest cases, but we could try to
608  // detect literals that implies all the constaints in which a variable
609  // appear to false. This can be done with a LCA computation in the tree of
610  // Boolean implication (once the presolve remove cycles). Not sure if we can
611  // properly exploit that afterwards though. Do some research!
612  std::vector<std::vector<int>> enforcement_intersection(num_proto_variables);
613  std::set<int> literals_set;
614  for (int c = 0; c < model_proto.constraints_size(); ++c) {
615  const ConstraintProto& ct = model_proto.constraints(c);
616  if (ct.enforcement_literal().empty()) {
617  for (const int var : UsedVariables(ct)) {
618  already_seen[var] = true;
619  enforcement_intersection[var].clear();
620  }
621  } else {
622  literals_set.clear();
623  literals_set.insert(ct.enforcement_literal().begin(),
624  ct.enforcement_literal().end());
625  for (const int var : UsedVariables(ct)) {
626  if (!already_seen[var]) {
627  enforcement_intersection[var].assign(ct.enforcement_literal().begin(),
628  ct.enforcement_literal().end());
629  } else {
630  // Take the intersection.
631  std::vector<int>& vector_ref = enforcement_intersection[var];
632  int new_size = 0;
633  for (const int literal : vector_ref) {
634  if (gtl::ContainsKey(literals_set, literal)) {
635  vector_ref[new_size++] = literal;
636  }
637  }
638  vector_ref.resize(new_size);
639  }
640  already_seen[var] = true;
641  }
642  }
643  }
644 
645  // Auto-detect optional variables.
646  int num_optionals = 0;
647  auto* integer_trail = m->GetOrCreate<IntegerTrail>();
648  for (int var = 0; var < num_proto_variables; ++var) {
649  const IntegerVariableProto& var_proto = model_proto.variables(var);
650  const int64 min = var_proto.domain(0);
651  const int64 max = var_proto.domain(var_proto.domain().size() - 1);
652  if (min == max) continue;
653  if (min == 0 && max == 1) continue;
654  if (enforcement_intersection[var].empty()) continue;
655 
656  ++num_optionals;
657  integer_trail->MarkIntegerVariableAsOptional(
658  Integer(var), Literal(enforcement_intersection[var].front()));
659  }
660  VLOG(2) << "Auto-detected " << num_optionals << " optional variables.";
661 }
662 
663 // ============================================================================
664 // A class that detects when variables should be fully encoded by computing a
665 // fixed point. It also fully encodes such variables.
666 // ============================================================================
667 
669  public:
671  : model_proto_(model_proto),
672  parameters_(*(model->GetOrCreate<SatParameters>())),
673  model_(model),
674  mapping_(model->GetOrCreate<CpModelMapping>()),
675  integer_encoder_(model->GetOrCreate<IntegerEncoder>()),
676  integer_trail_(model->GetOrCreate<IntegerTrail>()) {}
677 
678  void ComputeFixedPoint();
679 
680  private:
681  DEFINE_INT_TYPE(ConstraintIndex, int32);
682 
683  // Constraint ct is interested by (full-encoding) state of variable.
684  void Register(ConstraintIndex ct_index, int variable) {
685  variable = PositiveRef(variable);
686  constraint_is_registered_[ct_index] = true;
687  if (variable_watchers_.size() <= variable) {
688  variable_watchers_.resize(variable + 1);
689  variable_was_added_in_to_propagate_.resize(variable + 1);
690  }
691  variable_watchers_[variable].push_back(ct_index);
692  }
693 
694  void AddVariableToPropagationQueue(int variable) {
695  variable = PositiveRef(variable);
696  if (variable_was_added_in_to_propagate_.size() <= variable) {
697  variable_watchers_.resize(variable + 1);
698  variable_was_added_in_to_propagate_.resize(variable + 1);
699  }
700  if (!variable_was_added_in_to_propagate_[variable]) {
701  variable_was_added_in_to_propagate_[variable] = true;
702  variables_to_propagate_.push_back(variable);
703  }
704  }
705 
706  // Note that we always consider a fixed variable to be fully encoded here.
707  const bool IsFullyEncoded(int v) {
708  const IntegerVariable variable = mapping_->Integer(v);
709  if (v == kNoIntegerVariable) return false;
710  return integer_trail_->IsFixed(variable) ||
711  integer_encoder_->VariableIsFullyEncoded(variable);
712  }
713 
714  const bool VariableIsFixed(int v) {
715  const IntegerVariable variable = mapping_->Integer(v);
716  if (v == kNoIntegerVariable) return false;
717  return integer_trail_->IsFixed(variable);
718  }
719 
720  void FullyEncode(int v) {
721  v = PositiveRef(v);
722  const IntegerVariable variable = mapping_->Integer(v);
723  if (v == kNoIntegerVariable) return;
724  if (!integer_trail_->IsFixed(variable)) {
725  model_->Add(FullyEncodeVariable(variable));
726  }
727  AddVariableToPropagationQueue(v);
728  }
729 
730  bool ProcessConstraint(ConstraintIndex ct_index);
731  bool ProcessElement(ConstraintIndex ct_index);
732  bool ProcessTable(ConstraintIndex ct_index);
733  bool ProcessAutomaton(ConstraintIndex ct_index);
734  bool ProcessLinear(ConstraintIndex ct_index);
735 
736  const CpModelProto& model_proto_;
737  const SatParameters& parameters_;
738 
739  Model* model_;
740  CpModelMapping* mapping_;
741  IntegerEncoder* integer_encoder_;
742  IntegerTrail* integer_trail_;
743 
744  std::vector<bool> variable_was_added_in_to_propagate_;
745  std::vector<int> variables_to_propagate_;
746  std::vector<std::vector<ConstraintIndex>> variable_watchers_;
747 
748  gtl::ITIVector<ConstraintIndex, bool> constraint_is_finished_;
749  gtl::ITIVector<ConstraintIndex, bool> constraint_is_registered_;
750 
751  absl::flat_hash_map<int, absl::flat_hash_set<int>>
752  variables_to_equal_or_diff_variables_;
753 };
754 
755 // We only add to the propagation queue variable that are fully encoded.
756 // Note that if a variable was already added once, we never add it again.
758  const int num_constraints = model_proto_.constraints_size();
759  const int num_vars = model_proto_.variables_size();
760  constraint_is_finished_.assign(num_constraints, false);
761  constraint_is_registered_.assign(num_constraints, false);
762 
763  // Process all constraint once.
764  for (ConstraintIndex ct_index(0); ct_index < num_constraints; ++ct_index) {
765  constraint_is_finished_[ct_index] = ProcessConstraint(ct_index);
766  }
767 
768  // We run a heuristics to decide if we want to fully encode a variable or not.
769  // We decide to fully encode a variable if:
770  // - a variable appears in enough a1 * x1 + a2 + x2 ==/!= value and the
771  // domain is small.
772  // - the number of values that appears in b => x ==/!= value that are not
773  // the bounds of the variables is more that half the size of the domain.
774  // . - the size of the domain is > 2
775  int num_variables_fully_encoded_by_heuristics = 0;
776  for (int var = 0; var < num_vars; ++var) {
777  if (!mapping_->IsInteger(var) || IsFullyEncoded(var)) continue;
778  const IntegerVariableProto& int_var_proto = model_proto_.variables(var);
779  const Domain domain = ReadDomainFromProto(int_var_proto);
780  int64 domain_size = domain.Size();
781  int64 num_diff_or_equal_var_constraints = 0;
782  int64 num_potential_encoded_values_without_bounds = 0;
783 
784  if (domain_size <= 2) continue;
785 
786  const absl::flat_hash_set<int64>& value_set =
787  mapping_->PotentialEncodedValues(var);
788  for (const int value : value_set) {
789  if (value > domain.Min() && value < domain.Max() &&
790  domain.Contains(value)) {
791  num_potential_encoded_values_without_bounds++;
792  }
793  }
794 
795  const auto& it = variables_to_equal_or_diff_variables_.find(var);
796  if (it != variables_to_equal_or_diff_variables_.end()) {
797  num_diff_or_equal_var_constraints = it->second.size();
798  }
799 
800  if (num_potential_encoded_values_without_bounds >= domain_size / 2 ||
801  (num_diff_or_equal_var_constraints >= domain_size / 2 &&
802  domain_size < 16)) {
803  VLOG(3) << model_proto_.variables(var).ShortDebugString()
804  << " is encoded with "
805  << num_potential_encoded_values_without_bounds
806  << " unary constraints, and " << num_diff_or_equal_var_constraints
807  << " binary constraints on a domain of size " << domain_size;
808  FullyEncode(var);
809  num_variables_fully_encoded_by_heuristics++;
810  }
811  }
812  if (num_variables_fully_encoded_by_heuristics > 0) {
813  VLOG(2) << num_variables_fully_encoded_by_heuristics
814  << " variables fully encoded after model introspection.";
815  }
816 
817  // Make sure all fully encoded variables of interest are in the queue.
818  for (int v = 0; v < variable_watchers_.size(); v++) {
819  if (!variable_watchers_[v].empty() && IsFullyEncoded(v)) {
820  AddVariableToPropagationQueue(v);
821  }
822  }
823 
824  // Loop until no additional variable can be fully encoded.
825  while (!variables_to_propagate_.empty()) {
826  const int variable = variables_to_propagate_.back();
827  variables_to_propagate_.pop_back();
828  for (const ConstraintIndex ct_index : variable_watchers_[variable]) {
829  if (constraint_is_finished_[ct_index]) continue;
830  constraint_is_finished_[ct_index] = ProcessConstraint(ct_index);
831  }
832  }
833 }
834 
835 // Returns true if the constraint has finished encoding what it wants.
836 bool FullEncodingFixedPointComputer::ProcessConstraint(
837  ConstraintIndex ct_index) {
838  const ConstraintProto& ct = model_proto_.constraints(ct_index.value());
839  switch (ct.constraint_case()) {
840  case ConstraintProto::ConstraintProto::kElement:
841  return ProcessElement(ct_index);
842  case ConstraintProto::ConstraintProto::kTable:
843  return ProcessTable(ct_index);
844  case ConstraintProto::ConstraintProto::kAutomaton:
845  return ProcessAutomaton(ct_index);
846  case ConstraintProto::ConstraintProto::kLinear:
847  return ProcessLinear(ct_index);
848  default:
849  return true;
850  }
851 }
852 
853 bool FullEncodingFixedPointComputer::ProcessElement(ConstraintIndex ct_index) {
854  const ConstraintProto& ct = model_proto_.constraints(ct_index.value());
855 
856  // Index must always be full encoded.
857  FullyEncode(ct.element().index());
858 
859  const int target = ct.element().target();
860 
861  // If target is fixed, do not encode variables.
862  if (VariableIsFixed(target)) return true;
863 
864  // If target is a constant or fully encoded, variables must be fully encoded.
865  if (IsFullyEncoded(target)) {
866  for (const int v : ct.element().vars()) FullyEncode(v);
867  }
868 
869  // If all non-target variables are fully encoded, target must be too.
870  bool all_variables_are_fully_encoded = true;
871  for (const int v : ct.element().vars()) {
872  if (v == target) continue;
873  if (!IsFullyEncoded(v)) {
874  all_variables_are_fully_encoded = false;
875  break;
876  }
877  }
878  if (all_variables_are_fully_encoded) {
879  if (!IsFullyEncoded(target)) FullyEncode(target);
880  return true;
881  }
882 
883  // If some variables are not fully encoded, register on those.
884  if (constraint_is_registered_[ct_index]) {
885  for (const int v : ct.element().vars()) Register(ct_index, v);
886  Register(ct_index, target);
887  }
888  return false;
889 }
890 
891 bool FullEncodingFixedPointComputer::ProcessTable(ConstraintIndex ct_index) {
892  const ConstraintProto& ct = model_proto_.constraints(ct_index.value());
893 
894  if (ct.table().negated()) return true;
895 
896  for (const int variable : ct.table().vars()) {
897  FullyEncode(variable);
898  }
899 
900  return true;
901 }
902 
903 bool FullEncodingFixedPointComputer::ProcessAutomaton(
904  ConstraintIndex ct_index) {
905  const ConstraintProto& ct = model_proto_.constraints(ct_index.value());
906  for (const int variable : ct.automaton().vars()) {
907  FullyEncode(variable);
908  }
909  return true;
910 }
911 
912 bool FullEncodingFixedPointComputer::ProcessLinear(ConstraintIndex ct_index) {
913  // We are only interested in linear equations of the form:
914  // [b =>] a1 * x1 + a2 * x2 ==|!= value
915  const ConstraintProto& ct = model_proto_.constraints(ct_index.value());
916  if (parameters_.boolean_encoding_level() == 0 ||
917  ct.linear().vars_size() != 2) {
918  return true;
919  }
920 
921  if (!ConstraintIsEq(ct.linear()) &&
922  !ConstraintIsNEq(ct.linear(), mapping_, integer_trail_, nullptr)) {
923  return true;
924  }
925 
926  const int var0 = ct.linear().vars(0);
927  const int var1 = ct.linear().vars(1);
928  if (!IsFullyEncoded(var0)) {
929  variables_to_equal_or_diff_variables_[var0].insert(var1);
930  }
931  if (!IsFullyEncoded(var1)) {
932  variables_to_equal_or_diff_variables_[var1].insert(var0);
933  }
934  return true;
935 }
936 
937 void MaybeFullyEncodeMoreVariables(const CpModelProto& model_proto, Model* m) {
939  fixpoint.ComputeFixedPoint();
940 }
941 
942 // ============================================================================
943 // Constraint loading functions.
944 // ============================================================================
945 
946 void LoadBoolOrConstraint(const ConstraintProto& ct, Model* m) {
947  auto* mapping = m->GetOrCreate<CpModelMapping>();
948  std::vector<Literal> literals = mapping->Literals(ct.bool_or().literals());
949  for (const int ref : ct.enforcement_literal()) {
950  literals.push_back(mapping->Literal(ref).Negated());
951  }
952  m->Add(ClauseConstraint(literals));
953 }
954 
955 void LoadBoolAndConstraint(const ConstraintProto& ct, Model* m) {
956  auto* mapping = m->GetOrCreate<CpModelMapping>();
957  std::vector<Literal> literals;
958  for (const int ref : ct.enforcement_literal()) {
959  literals.push_back(mapping->Literal(ref).Negated());
960  }
961  auto* sat_solver = m->GetOrCreate<SatSolver>();
962  for (const Literal literal : mapping->Literals(ct.bool_and().literals())) {
963  literals.push_back(literal);
964  sat_solver->AddProblemClause(literals);
965  literals.pop_back();
966  }
967 }
968 
969 void LoadAtMostOneConstraint(const ConstraintProto& ct, Model* m) {
970  auto* mapping = m->GetOrCreate<CpModelMapping>();
971  CHECK(!HasEnforcementLiteral(ct)) << "Not supported.";
972  m->Add(AtMostOneConstraint(mapping->Literals(ct.at_most_one().literals())));
973 }
974 
975 void LoadBoolXorConstraint(const ConstraintProto& ct, Model* m) {
976  auto* mapping = m->GetOrCreate<CpModelMapping>();
977  CHECK(!HasEnforcementLiteral(ct)) << "Not supported.";
978  m->Add(LiteralXorIs(mapping->Literals(ct.bool_xor().literals()), true));
979 }
980 
981 namespace {
982 
983 // Boolean encoding of:
984 // enforcement_literal => coeff1 * var1 + coeff2 * var2 == rhs;
985 void LoadEquivalenceAC(const std::vector<Literal> enforcement_literal,
986  IntegerValue coeff1, IntegerVariable var1,
987  IntegerValue coeff2, IntegerVariable var2,
988  const IntegerValue rhs, Model* m) {
989  auto* encoder = m->GetOrCreate<IntegerEncoder>();
990  CHECK(encoder->VariableIsFullyEncoded(var1));
991  CHECK(encoder->VariableIsFullyEncoded(var2));
992  absl::flat_hash_map<IntegerValue, Literal> term1_value_to_literal;
993  for (const auto value_literal : encoder->FullDomainEncoding(var1)) {
994  term1_value_to_literal[coeff1 * value_literal.value] =
995  value_literal.literal;
996  }
997  for (const auto value_literal : encoder->FullDomainEncoding(var2)) {
998  const IntegerValue target = rhs - value_literal.value * coeff2;
999  if (!gtl::ContainsKey(term1_value_to_literal, target)) {
1000  m->Add(EnforcedClause(enforcement_literal,
1001  {value_literal.literal.Negated()}));
1002  } else {
1003  const Literal target_literal = term1_value_to_literal[target];
1004  m->Add(EnforcedClause(enforcement_literal,
1005  {value_literal.literal.Negated(), target_literal}));
1006  m->Add(EnforcedClause(enforcement_literal,
1007  {value_literal.literal, target_literal.Negated()}));
1008 
1009  // This "target" can never be reached again, so it is safe to remove it.
1010  // We do that so we know the term1 values that are never reached.
1011  term1_value_to_literal.erase(target);
1012  }
1013  }
1014 
1015  // Exclude the values that can never be "matched" by coeff2 * var2.
1016  // We need the std::sort() to be deterministic!
1017  std::vector<Literal> implied_false;
1018  for (const auto entry : term1_value_to_literal) {
1019  implied_false.push_back(entry.second);
1020  }
1021  std::sort(implied_false.begin(), implied_false.end());
1022  for (const Literal l : implied_false) {
1023  m->Add(EnforcedClause(enforcement_literal, {l.Negated()}));
1024  }
1025 }
1026 
1027 // Boolean encoding of:
1028 // enforcement_literal => coeff1 * var1 + coeff2 * var2 != rhs;
1029 void LoadEquivalenceNeqAC(const std::vector<Literal> enforcement_literal,
1030  IntegerValue coeff1, IntegerVariable var1,
1031  IntegerValue coeff2, IntegerVariable var2,
1032  const IntegerValue rhs, Model* m) {
1033  auto* encoder = m->GetOrCreate<IntegerEncoder>();
1034  CHECK(encoder->VariableIsFullyEncoded(var1));
1035  CHECK(encoder->VariableIsFullyEncoded(var2));
1036  absl::flat_hash_map<IntegerValue, Literal> term1_value_to_literal;
1037  for (const auto value_literal : encoder->FullDomainEncoding(var1)) {
1038  term1_value_to_literal[coeff1 * value_literal.value] =
1039  value_literal.literal;
1040  }
1041  for (const auto value_literal : encoder->FullDomainEncoding(var2)) {
1042  const IntegerValue target_value = rhs - value_literal.value * coeff2;
1043  const auto& it = term1_value_to_literal.find(target_value);
1044  if (it != term1_value_to_literal.end()) {
1045  const Literal target_literal = it->second;
1046  m->Add(EnforcedClause(
1047  enforcement_literal,
1048  {value_literal.literal.Negated(), target_literal.Negated()}));
1049  }
1050  }
1051 }
1052 
1053 } // namespace
1054 
1055 void LoadLinearConstraint(const ConstraintProto& ct, Model* m) {
1056  auto* mapping = m->GetOrCreate<CpModelMapping>();
1057 
1058  if (ct.linear().vars().empty()) {
1059  const Domain rhs = ReadDomainFromProto(ct.linear());
1060  if (rhs.Contains(0)) return;
1061  if (HasEnforcementLiteral(ct)) {
1062  std::vector<Literal> clause;
1063  for (const int ref : ct.enforcement_literal()) {
1064  clause.push_back(mapping->Literal(ref).Negated());
1065  }
1066  m->Add(ClauseConstraint(clause));
1067  } else {
1068  VLOG(1) << "Trivially UNSAT constraint: " << ct.DebugString();
1069  m->GetOrCreate<SatSolver>()->NotifyThatModelIsUnsat();
1070  }
1071  return;
1072  }
1073 
1074  auto* integer_trail = m->GetOrCreate<IntegerTrail>();
1075  const std::vector<IntegerVariable> vars =
1076  mapping->Integers(ct.linear().vars());
1077  const std::vector<int64> coeffs = ValuesFromProto(ct.linear().coeffs());
1078 
1079  // Compute the min/max to relax the bounds if needed.
1080  //
1081  // TODO(user): Reuse ComputeLinearBounds()? but then we need another loop
1082  // to detect if we only have Booleans.
1083  IntegerValue min_sum(0);
1084  IntegerValue max_sum(0);
1085  IntegerValue max_domain_size(0);
1086  bool all_booleans = true;
1087  for (int i = 0; i < vars.size(); ++i) {
1088  if (all_booleans && !mapping->IsBoolean(ct.linear().vars(i))) {
1089  all_booleans = false;
1090  }
1091  const IntegerValue lb = integer_trail->LowerBound(vars[i]);
1092  const IntegerValue ub = integer_trail->UpperBound(vars[i]);
1093  max_domain_size = std::max(max_domain_size, ub - lb + 1);
1094  const IntegerValue term_a = coeffs[i] * lb;
1095  const IntegerValue term_b = coeffs[i] * ub;
1096  min_sum += std::min(term_a, term_b);
1097  max_sum += std::max(term_a, term_b);
1098  }
1099 
1100  if (ct.linear().vars_size() == 2 && !integer_trail->IsFixed(vars[0]) &&
1101  !integer_trail->IsFixed(vars[1]) && max_domain_size < 16) {
1102  const SatParameters& params = *m->GetOrCreate<SatParameters>();
1103  auto* encoder = m->GetOrCreate<IntegerEncoder>();
1104  if (params.boolean_encoding_level() > 0 && ConstraintIsEq(ct.linear()) &&
1105  ct.linear().domain(0) != min_sum && ct.linear().domain(0) != max_sum &&
1106  encoder->VariableIsFullyEncoded(vars[0]) &&
1107  encoder->VariableIsFullyEncoded(vars[1])) {
1108  VLOG(3) << "Load AC version of " << ct.DebugString() << ", var0 domain = "
1109  << integer_trail->InitialVariableDomain(vars[0])
1110  << ", var1 domain = "
1111  << integer_trail->InitialVariableDomain(vars[1]);
1112  return LoadEquivalenceAC(mapping->Literals(ct.enforcement_literal()),
1113  IntegerValue(coeffs[0]), vars[0],
1114  IntegerValue(coeffs[1]), vars[1],
1115  IntegerValue(ct.linear().domain(0)), m);
1116  }
1117 
1118  int64 single_value = 0;
1119  if (params.boolean_encoding_level() > 0 &&
1120  ConstraintIsNEq(ct.linear(), mapping, integer_trail, &single_value) &&
1121  single_value != min_sum && single_value != max_sum &&
1122  encoder->VariableIsFullyEncoded(vars[0]) &&
1123  encoder->VariableIsFullyEncoded(vars[1])) {
1124  VLOG(3) << "Load NAC version of " << ct.DebugString()
1125  << ", var0 domain = "
1126  << integer_trail->InitialVariableDomain(vars[0])
1127  << ", var1 domain = "
1128  << integer_trail->InitialVariableDomain(vars[1])
1129  << ", value = " << single_value;
1130  return LoadEquivalenceNeqAC(mapping->Literals(ct.enforcement_literal()),
1131  IntegerValue(coeffs[0]), vars[0],
1132  IntegerValue(coeffs[1]), vars[1],
1133  IntegerValue(single_value), m);
1134  }
1135  }
1136 
1137  if (ct.linear().domain_size() == 2) {
1138  int64 lb = ct.linear().domain(0);
1139  int64 ub = ct.linear().domain(1);
1140  if (min_sum >= lb) lb = kint64min;
1141  if (max_sum <= ub) ub = kint64max;
1142 
1143  if (!HasEnforcementLiteral(ct)) {
1144  if (all_booleans) {
1145  // TODO(user): we should probably also implement an
1146  // half-reified version of this constraint.
1147  std::vector<LiteralWithCoeff> cst;
1148  for (int i = 0; i < vars.size(); ++i) {
1149  const int ref = ct.linear().vars(i);
1150  cst.push_back({mapping->Literal(ref), coeffs[i]});
1151  }
1152  m->Add(BooleanLinearConstraint(lb, ub, &cst));
1153  } else {
1154  if (lb != kint64min) {
1155  m->Add(WeightedSumGreaterOrEqual(vars, coeffs, lb));
1156  }
1157  if (ub != kint64max) {
1158  m->Add(WeightedSumLowerOrEqual(vars, coeffs, ub));
1159  }
1160  }
1161  } else {
1162  const std::vector<Literal> enforcement_literals =
1163  mapping->Literals(ct.enforcement_literal());
1164  if (lb != kint64min) {
1165  m->Add(ConditionalWeightedSumGreaterOrEqual(enforcement_literals, vars,
1166  coeffs, lb));
1167  }
1168  if (ub != kint64max) {
1169  m->Add(ConditionalWeightedSumLowerOrEqual(enforcement_literals, vars,
1170  coeffs, ub));
1171  }
1172  }
1173  } else {
1174  std::vector<Literal> clause;
1175  for (int i = 0; i < ct.linear().domain_size(); i += 2) {
1176  int64 lb = ct.linear().domain(i);
1177  int64 ub = ct.linear().domain(i + 1);
1178  if (min_sum >= lb) lb = kint64min;
1179  if (max_sum <= ub) ub = kint64max;
1180 
1181  const Literal subdomain_literal(m->Add(NewBooleanVariable()), true);
1182  clause.push_back(subdomain_literal);
1183  if (lb != kint64min) {
1184  m->Add(ConditionalWeightedSumGreaterOrEqual({subdomain_literal}, vars,
1185  coeffs, lb));
1186  }
1187  if (ub != kint64max) {
1188  m->Add(ConditionalWeightedSumLowerOrEqual({subdomain_literal}, vars,
1189  coeffs, ub));
1190  }
1191  }
1192  for (const int ref : ct.enforcement_literal()) {
1193  clause.push_back(mapping->Literal(ref).Negated());
1194  }
1195 
1196  // TODO(user): In the cases where this clause only contains two literals,
1197  // then we could have only used one literal and its negation above.
1198  m->Add(ClauseConstraint(clause));
1199  }
1200 }
1201 
1202 void LoadAllDiffConstraint(const ConstraintProto& ct, Model* m) {
1203  auto* mapping = m->GetOrCreate<CpModelMapping>();
1204  const std::vector<IntegerVariable> vars =
1205  mapping->Integers(ct.all_diff().vars());
1206  // If all variables are fully encoded and domains are not too large, use
1207  // arc-consistent reasoning. Otherwise, use bounds-consistent reasoning.
1208  IntegerTrail* integer_trail = m->GetOrCreate<IntegerTrail>();
1209  IntegerEncoder* encoder = m->GetOrCreate<IntegerEncoder>();
1210  int num_fully_encoded = 0;
1211  int64 max_domain_size = 0;
1212  for (const IntegerVariable variable : vars) {
1213  if (encoder->VariableIsFullyEncoded(variable)) num_fully_encoded++;
1214 
1215  IntegerValue lb = integer_trail->LowerBound(variable);
1216  IntegerValue ub = integer_trail->UpperBound(variable);
1217  const int64 domain_size = ub.value() - lb.value() + 1;
1218  max_domain_size = std::max(max_domain_size, domain_size);
1219  }
1220 
1221  if (num_fully_encoded == vars.size() && max_domain_size < 1024) {
1222  m->Add(AllDifferentBinary(vars));
1223  m->Add(AllDifferentAC(vars));
1224  } else {
1225  m->Add(AllDifferentOnBounds(vars));
1226  }
1227 }
1228 
1229 void LoadIntProdConstraint(const ConstraintProto& ct, Model* m) {
1230  auto* mapping = m->GetOrCreate<CpModelMapping>();
1231  const IntegerVariable prod = mapping->Integer(ct.int_prod().target());
1232  const std::vector<IntegerVariable> vars =
1233  mapping->Integers(ct.int_prod().vars());
1234  CHECK_EQ(vars.size(), 2) << "General int_prod not supported yet.";
1235  m->Add(ProductConstraint(vars[0], vars[1], prod));
1236 }
1237 
1238 void LoadIntDivConstraint(const ConstraintProto& ct, Model* m) {
1239  auto* mapping = m->GetOrCreate<CpModelMapping>();
1240  const IntegerVariable div = mapping->Integer(ct.int_div().target());
1241  const std::vector<IntegerVariable> vars =
1242  mapping->Integers(ct.int_div().vars());
1243  if (m->Get(IsFixed(vars[1]))) {
1244  const IntegerValue denom(m->Get(Value(vars[1])));
1245  if (denom == 1) {
1246  m->Add(Equality(vars[0], div));
1247  } else {
1248  m->Add(FixedDivisionConstraint(vars[0], denom, div));
1249  }
1250  } else {
1251  m->Add(DivisionConstraint(vars[0], vars[1], div));
1252  }
1253 }
1254 
1255 void LoadIntMinConstraint(const ConstraintProto& ct, Model* m) {
1256  auto* mapping = m->GetOrCreate<CpModelMapping>();
1257  const IntegerVariable min = mapping->Integer(ct.int_min().target());
1258  const std::vector<IntegerVariable> vars =
1259  mapping->Integers(ct.int_min().vars());
1260  m->Add(IsEqualToMinOf(min, vars));
1261 }
1262 
1263 LinearExpression GetExprFromProto(const LinearExpressionProto& expr_proto,
1264  const CpModelMapping& mapping) {
1265  LinearExpression expr;
1266  expr.vars = mapping.Integers(expr_proto.vars());
1267  for (int j = 0; j < expr_proto.coeffs_size(); ++j) {
1268  expr.coeffs.push_back(IntegerValue(expr_proto.coeffs(j)));
1269  }
1270  expr.offset = IntegerValue(expr_proto.offset());
1271  return CanonicalizeExpr(expr);
1272 }
1273 
1274 void LoadLinMaxConstraint(const ConstraintProto& ct, Model* m) {
1275  auto* mapping = m->GetOrCreate<CpModelMapping>();
1276  const LinearExpression max =
1277  GetExprFromProto(ct.lin_max().target(), *mapping);
1278  std::vector<LinearExpression> negated_exprs;
1279  negated_exprs.reserve(ct.lin_max().exprs_size());
1280  for (int i = 0; i < ct.lin_max().exprs_size(); ++i) {
1281  negated_exprs.push_back(
1282  NegationOf(GetExprFromProto(ct.lin_max().exprs(i), *mapping)));
1283  }
1284  // TODO(user): Consider replacing the min propagator by max.
1285  m->Add(IsEqualToMinOf(NegationOf(max), negated_exprs));
1286 }
1287 
1288 void LoadIntMaxConstraint(const ConstraintProto& ct, Model* m) {
1289  auto* mapping = m->GetOrCreate<CpModelMapping>();
1290  const IntegerVariable max = mapping->Integer(ct.int_max().target());
1291  const std::vector<IntegerVariable> vars =
1292  mapping->Integers(ct.int_max().vars());
1293  m->Add(IsEqualToMaxOf(max, vars));
1294 }
1295 
1296 void LoadNoOverlapConstraint(const ConstraintProto& ct, Model* m) {
1297  auto* mapping = m->GetOrCreate<CpModelMapping>();
1298  m->Add(Disjunctive(mapping->Intervals(ct.no_overlap().intervals())));
1299 }
1300 
1301 void LoadNoOverlap2dConstraint(const ConstraintProto& ct, Model* m) {
1302  if (ct.no_overlap_2d().x_intervals().empty()) return;
1303  auto* mapping = m->GetOrCreate<CpModelMapping>();
1304  const std::vector<IntervalVariable> x_intervals =
1305  mapping->Intervals(ct.no_overlap_2d().x_intervals());
1306  const std::vector<IntervalVariable> y_intervals =
1307  mapping->Intervals(ct.no_overlap_2d().y_intervals());
1309  x_intervals, y_intervals,
1310  !ct.no_overlap_2d().boxes_with_null_area_can_overlap()));
1311 }
1312 
1313 void LoadCumulativeConstraint(const ConstraintProto& ct, Model* m) {
1314  auto* mapping = m->GetOrCreate<CpModelMapping>();
1315  const std::vector<IntervalVariable> intervals =
1316  mapping->Intervals(ct.cumulative().intervals());
1317  const AffineExpression capacity(mapping->Integer(ct.cumulative().capacity()));
1318  std::vector<AffineExpression> demands;
1319  for (const IntegerVariable var :
1320  mapping->Integers(ct.cumulative().demands())) {
1321  demands.push_back(AffineExpression(var));
1322  }
1323  m->Add(Cumulative(intervals, demands, capacity));
1324 }
1325 
1326 // If a variable is constant and its value appear in no other variable domains,
1327 // then the literal encoding the index and the one encoding the target at this
1328 // value are equivalent.
1329 bool DetectEquivalencesInElementConstraint(const ConstraintProto& ct,
1330  Model* m) {
1331  auto* mapping = m->GetOrCreate<CpModelMapping>();
1332  IntegerEncoder* encoder = m->GetOrCreate<IntegerEncoder>();
1333  IntegerTrail* integer_trail = m->GetOrCreate<IntegerTrail>();
1334 
1335  const IntegerVariable index = mapping->Integer(ct.element().index());
1336  const IntegerVariable target = mapping->Integer(ct.element().target());
1337  const std::vector<IntegerVariable> vars =
1338  mapping->Integers(ct.element().vars());
1339  CHECK(!m->Get(IsFixed(index)));
1340  CHECK(!m->Get(IsFixed(target)));
1341 
1342  Domain union_of_non_constant_domains;
1343  std::map<IntegerValue, int> constant_to_num;
1344  for (const auto literal_value : m->Add(FullyEncodeVariable(index))) {
1345  const int i = literal_value.value.value();
1346  if (m->Get(IsFixed(vars[i]))) {
1347  const IntegerValue value(m->Get(Value(vars[i])));
1348  constant_to_num[value]++;
1349  } else {
1350  union_of_non_constant_domains = union_of_non_constant_domains.UnionWith(
1351  integer_trail->InitialVariableDomain(vars[i]));
1352  }
1353  }
1354 
1355  // Bump the number if the constant appear in union_of_non_constant_domains.
1356  for (const auto entry : constant_to_num) {
1357  if (union_of_non_constant_domains.Contains(entry.first.value())) {
1358  constant_to_num[entry.first]++;
1359  }
1360  }
1361 
1362  // Use the literal from the index encoding to encode the target at the
1363  // "unique" values.
1364  bool is_one_to_one_mapping = true;
1365  for (const auto literal_value : m->Add(FullyEncodeVariable(index))) {
1366  const int i = literal_value.value.value();
1367  if (!m->Get(IsFixed(vars[i]))) {
1368  is_one_to_one_mapping = false;
1369  continue;
1370  }
1371 
1372  const IntegerValue value(m->Get(Value(vars[i])));
1373  if (constant_to_num[value] == 1) {
1374  const Literal r = literal_value.literal;
1375  encoder->AssociateToIntegerEqualValue(r, target, value);
1376  } else {
1377  is_one_to_one_mapping = false;
1378  }
1379  }
1380 
1381  return is_one_to_one_mapping;
1382 }
1383 
1384 // TODO(user): Be more efficient when the element().vars() are constants.
1385 // Ideally we should avoid creating them as integer variable since we don't
1386 // use them.
1387 void LoadElementConstraintBounds(const ConstraintProto& ct, Model* m) {
1388  auto* mapping = m->GetOrCreate<CpModelMapping>();
1389  const IntegerVariable index = mapping->Integer(ct.element().index());
1390  const IntegerVariable target = mapping->Integer(ct.element().target());
1391  const std::vector<IntegerVariable> vars =
1392  mapping->Integers(ct.element().vars());
1393  CHECK(!m->Get(IsFixed(index)));
1394 
1395  // We always fully encode the index on an element constraint.
1396  const auto encoding = m->Add(FullyEncodeVariable((index)));
1397  std::vector<Literal> selectors;
1398  std::vector<IntegerVariable> possible_vars;
1399  for (const auto literal_value : encoding) {
1400  const int i = literal_value.value.value();
1401  CHECK_GE(i, 0);
1402  CHECK_LT(i, vars.size());
1403  possible_vars.push_back(vars[i]);
1404  selectors.push_back(literal_value.literal);
1405  const Literal r = literal_value.literal;
1406 
1407  if (vars[i] == target) continue;
1408  if (m->Get(IsFixed(target))) {
1409  const int64 value = m->Get(Value(target));
1410  m->Add(ImpliesInInterval(r, vars[i], value, value));
1411  } else if (m->Get(IsFixed(vars[i]))) {
1412  const int64 value = m->Get(Value(vars[i]));
1413  m->Add(ImpliesInInterval(r, target, value, value));
1414  } else {
1415  m->Add(ConditionalLowerOrEqualWithOffset(vars[i], target, 0, r));
1416  m->Add(ConditionalLowerOrEqualWithOffset(target, vars[i], 0, r));
1417  }
1418  }
1419 
1420  if (!m->Get(IsFixed(target))) {
1421  m->Add(PartialIsOneOfVar(target, possible_vars, selectors));
1422  }
1423 }
1424 
1425 // Arc-Consistent encoding of the element constraint as SAT clauses.
1426 // The constraint enforces vars[index] == target.
1427 //
1428 // The AC propagation can be decomposed in three rules:
1429 // Rule 1: dom(index) == i => dom(vars[i]) == dom(target).
1430 // Rule 2: dom(target) \subseteq \Union_{i \in dom(index)} dom(vars[i]).
1431 // Rule 3: dom(index) \subseteq { i | |dom(vars[i]) \inter dom(target)| > 0 }.
1432 //
1433 // We encode this in a way similar to the table constraint, except that the
1434 // set of admissible tuples is not explicit.
1435 // First, we add Booleans selected[i][value] <=> (index == i /\ vars[i] ==
1436 // value). Rules 1 and 2 are enforced by target == value <=> \Or_{i}
1437 // selected[i][value]. Rule 3 is enforced by index == i <=> \Or_{value}
1438 // selected[i][value].
1439 void LoadElementConstraintAC(const ConstraintProto& ct, Model* m) {
1440  auto* mapping = m->GetOrCreate<CpModelMapping>();
1441  const IntegerVariable index = mapping->Integer(ct.element().index());
1442  const IntegerVariable target = mapping->Integer(ct.element().target());
1443  const std::vector<IntegerVariable> vars =
1444  mapping->Integers(ct.element().vars());
1445  CHECK(!m->Get(IsFixed(index)));
1446  CHECK(!m->Get(IsFixed(target)));
1447 
1448  absl::flat_hash_map<IntegerValue, Literal> target_map;
1449  const auto target_encoding = m->Add(FullyEncodeVariable(target));
1450  for (const auto literal_value : target_encoding) {
1451  target_map[literal_value.value] = literal_value.literal;
1452  }
1453 
1454  // For i \in index and value in vars[i], make (index == i /\ vars[i] == value)
1455  // literals and store them by value in vectors.
1456  absl::flat_hash_map<IntegerValue, std::vector<Literal>> value_to_literals;
1457  const auto index_encoding = m->Add(FullyEncodeVariable(index));
1458  IntegerTrail* integer_trail = m->GetOrCreate<IntegerTrail>();
1459  for (const auto literal_value : index_encoding) {
1460  const int i = literal_value.value.value();
1461  const Literal i_lit = literal_value.literal;
1462 
1463  // Special case where vars[i] == value /\ i_lit is actually i_lit.
1464  if (m->Get(IsFixed(vars[i]))) {
1465  value_to_literals[integer_trail->LowerBound(vars[i])].push_back(i_lit);
1466  continue;
1467  }
1468 
1469  const auto var_encoding = m->Add(FullyEncodeVariable(vars[i]));
1470  std::vector<Literal> var_selected_literals;
1471  for (const auto var_literal_value : var_encoding) {
1472  const IntegerValue value = var_literal_value.value;
1473  const Literal var_is_value = var_literal_value.literal;
1474 
1475  if (!gtl::ContainsKey(target_map, value)) {
1476  // No need to add to value_to_literals, selected[i][value] is always
1477  // false.
1478  m->Add(Implication(i_lit, var_is_value.Negated()));
1479  continue;
1480  }
1481 
1482  const Literal var_is_value_and_selected =
1483  Literal(m->Add(NewBooleanVariable()), true);
1484  m->Add(ReifiedBoolAnd({i_lit, var_is_value}, var_is_value_and_selected));
1485  value_to_literals[value].push_back(var_is_value_and_selected);
1486  var_selected_literals.push_back(var_is_value_and_selected);
1487  }
1488  // index == i <=> \Or_{value} selected[i][value].
1489  m->Add(ReifiedBoolOr(var_selected_literals, i_lit));
1490  }
1491 
1492  // target == value <=> \Or_{i \in index} (vars[i] == value /\ index == i).
1493  for (const auto& entry : target_map) {
1494  const IntegerValue value = entry.first;
1495  const Literal target_is_value = entry.second;
1496 
1497  if (!gtl::ContainsKey(value_to_literals, value)) {
1498  m->Add(ClauseConstraint({target_is_value.Negated()}));
1499  } else {
1500  m->Add(ReifiedBoolOr(value_to_literals[value], target_is_value));
1501  }
1502  }
1503 }
1504 
1505 namespace {
1506 
1507 // This Boolean encoding is enough for consistency, but does not propagate as
1508 // much as LoadElementConstraintAC(). However, setting any of the non-propagated
1509 // Booleans to its "wrong" value will result directly in a conflict, so the
1510 // solver will easily learn an AC encoding...
1511 //
1512 // The advantage is that this does not introduce extra BooleanVariables.
1513 void LoadElementConstraintHalfAC(const ConstraintProto& ct, Model* m) {
1514  auto* mapping = m->GetOrCreate<CpModelMapping>();
1515  const IntegerVariable index = mapping->Integer(ct.element().index());
1516  const IntegerVariable target = mapping->Integer(ct.element().target());
1517  const std::vector<IntegerVariable> vars =
1518  mapping->Integers(ct.element().vars());
1519  CHECK(!m->Get(IsFixed(index)));
1520  CHECK(!m->Get(IsFixed(target)));
1521 
1522  m->Add(FullyEncodeVariable(target));
1523  for (const auto value_literal : m->Add(FullyEncodeVariable(index))) {
1524  const int i = value_literal.value.value();
1525  m->Add(FullyEncodeVariable(vars[i]));
1526  LoadEquivalenceAC({value_literal.literal}, IntegerValue(1), vars[i],
1527  IntegerValue(-1), target, IntegerValue(0), m);
1528  }
1529 }
1530 
1531 void LoadBooleanElement(const ConstraintProto& ct, Model* m) {
1532  auto* mapping = m->GetOrCreate<CpModelMapping>();
1533  const IntegerVariable index = mapping->Integer(ct.element().index());
1534  const std::vector<Literal> literals = mapping->Literals(ct.element().vars());
1535  const Literal target = mapping->Literal(ct.element().target());
1536 
1537  if (m->Get(IsFixed(index))) {
1538  m->Add(Equality(target, literals[m->Get(Value(index))]));
1539  return;
1540  }
1541 
1542  std::vector<Literal> all_true;
1543  std::vector<Literal> all_false;
1544  for (const auto value_literal : m->Add(FullyEncodeVariable(index))) {
1545  const Literal a_lit = literals[value_literal.value.value()];
1546  const Literal i_lit = value_literal.literal;
1547  m->Add(ClauseConstraint({i_lit.Negated(), a_lit.Negated(), target}));
1548  m->Add(ClauseConstraint({i_lit.Negated(), a_lit, target.Negated()}));
1549  all_true.push_back(a_lit.Negated());
1550  all_false.push_back(a_lit);
1551  }
1552  all_true.push_back(target);
1553  all_false.push_back(target.Negated());
1554  m->Add(ClauseConstraint(all_true));
1555  m->Add(ClauseConstraint(all_false));
1556  // TODO(user): Investigate filtering this with active literals.
1557 }
1558 
1559 } // namespace
1560 
1561 void LoadElementConstraint(const ConstraintProto& ct, Model* m) {
1562  auto* mapping = m->GetOrCreate<CpModelMapping>();
1563  const IntegerVariable index = mapping->Integer(ct.element().index());
1564 
1565  bool boolean_array = true;
1566  for (const int ref : ct.element().vars()) {
1567  if (!mapping->IsBoolean(ref)) {
1568  boolean_array = false;
1569  break;
1570  }
1571  }
1572  if (boolean_array && !mapping->IsBoolean(ct.element().target())) {
1573  // Should have been reduced but presolve.
1574  VLOG(1) << "Fix boolean_element not propagated on target";
1575  boolean_array = false;
1576  }
1577 
1578  // TODO(user): Move this to presolve. Leads to a larger discussion on
1579  // adding full encoding to model during presolve.
1580  if (boolean_array) {
1581  LoadBooleanElement(ct, m);
1582  return;
1583  }
1584 
1585  const IntegerVariable target = mapping->Integer(ct.element().target());
1586  const std::vector<IntegerVariable> vars =
1587  mapping->Integers(ct.element().vars());
1588 
1589  // Retrict the domain of index in case there was no presolve.
1591  index, Domain(0, vars.size() - 1))) {
1592  return;
1593  }
1594 
1595  // This returns true if there is nothing else to do after the equivalences
1596  // of the form (index literal <=> target_literal) have been added.
1597  if (!m->Get(IsFixed(index)) && !m->Get(IsFixed(target)) &&
1599  return;
1600  }
1601 
1602  // Special case when index is fixed.
1603  if (m->Get(IsFixed(index))) {
1604  m->Add(Equality(target, vars[m->Get(Value(index))]));
1605  return;
1606  }
1607 
1608  // Special case when target is fixed.
1609  if (m->Get(IsFixed(target))) {
1610  return LoadElementConstraintBounds(ct, m);
1611  }
1612 
1613  IntegerEncoder* encoder = m->GetOrCreate<IntegerEncoder>();
1614  const bool target_is_AC = encoder->VariableIsFullyEncoded(target);
1615 
1616  int num_AC_variables = 0;
1617  const int num_vars = ct.element().vars().size();
1618  for (const int v : ct.element().vars()) {
1619  IntegerVariable variable = mapping->Integer(v);
1620  const bool is_full =
1621  m->Get(IsFixed(variable)) || encoder->VariableIsFullyEncoded(variable);
1622  if (is_full) num_AC_variables++;
1623  }
1624 
1625  const SatParameters& params = *m->GetOrCreate<SatParameters>();
1626  if (params.boolean_encoding_level() > 0 &&
1627  (target_is_AC || num_AC_variables >= num_vars - 1)) {
1628  if (params.boolean_encoding_level() > 1) {
1630  } else {
1631  LoadElementConstraintHalfAC(ct, m);
1632  }
1633  } else {
1635  }
1636 }
1637 
1638 void LoadTableConstraint(const ConstraintProto& ct, Model* m) {
1639  auto* mapping = m->GetOrCreate<CpModelMapping>();
1640  const std::vector<IntegerVariable> vars =
1641  mapping->Integers(ct.table().vars());
1642  const std::vector<int64> values = ValuesFromProto(ct.table().values());
1643  const int num_vars = vars.size();
1644  const int num_tuples = values.size() / num_vars;
1645  std::vector<std::vector<int64>> tuples(num_tuples);
1646  int count = 0;
1647  for (int i = 0; i < num_tuples; ++i) {
1648  for (int j = 0; j < num_vars; ++j) {
1649  tuples[i].push_back(values[count++]);
1650  }
1651  }
1652  if (ct.table().negated()) {
1653  AddNegatedTableConstraint(vars, std::move(tuples), m);
1654  } else {
1655  AddTableConstraint(vars, std::move(tuples), m);
1656  }
1657 }
1658 
1659 void LoadAutomatonConstraint(const ConstraintProto& ct, Model* m) {
1660  auto* mapping = m->GetOrCreate<CpModelMapping>();
1661  const std::vector<IntegerVariable> vars =
1662  mapping->Integers(ct.automaton().vars());
1663 
1664  const int num_transitions = ct.automaton().transition_tail_size();
1665  std::vector<std::vector<int64>> transitions;
1666  transitions.reserve(num_transitions);
1667  for (int i = 0; i < num_transitions; ++i) {
1668  transitions.push_back({ct.automaton().transition_tail(i),
1669  ct.automaton().transition_label(i),
1670  ct.automaton().transition_head(i)});
1671  }
1672 
1673  const int64 starting_state = ct.automaton().starting_state();
1674  const std::vector<int64> final_states =
1675  ValuesFromProto(ct.automaton().final_states());
1676  m->Add(TransitionConstraint(vars, transitions, starting_state, final_states));
1677 }
1678 
1679 // From vector of n IntegerVariables, returns an n x n matrix of Literal
1680 // such that matrix[i][j] is the Literal corresponding to vars[i] == j.
1681 std::vector<std::vector<Literal>> GetSquareMatrixFromIntegerVariables(
1682  const std::vector<IntegerVariable>& vars, Model* m) {
1683  const int n = vars.size();
1684  const Literal kTrueLiteral =
1685  m->GetOrCreate<IntegerEncoder>()->GetTrueLiteral();
1686  const Literal kFalseLiteral =
1687  m->GetOrCreate<IntegerEncoder>()->GetFalseLiteral();
1688  std::vector<std::vector<Literal>> matrix(
1689  n, std::vector<Literal>(n, kFalseLiteral));
1690  for (int i = 0; i < n; i++) {
1691  for (int j = 0; j < n; j++) {
1692  if (m->Get(IsFixed(vars[i]))) {
1693  const int value = m->Get(Value(vars[i]));
1694  DCHECK_LE(0, value);
1695  DCHECK_LT(value, n);
1696  matrix[i][value] = kTrueLiteral;
1697  } else {
1698  const auto encoding = m->Add(FullyEncodeVariable(vars[i]));
1699  for (const auto& entry : encoding) {
1700  const int value = entry.value.value();
1701  DCHECK_LE(0, value);
1702  DCHECK_LT(value, n);
1703  matrix[i][value] = entry.literal;
1704  }
1705  }
1706  }
1707  }
1708  return matrix;
1709 }
1710 
1711 void LoadCircuitConstraint(const ConstraintProto& ct, Model* m) {
1712  const auto& circuit = ct.circuit();
1713  if (circuit.tails().empty()) return;
1714 
1715  std::vector<int> tails(circuit.tails().begin(), circuit.tails().end());
1716  std::vector<int> heads(circuit.heads().begin(), circuit.heads().end());
1717  std::vector<Literal> literals =
1718  m->GetOrCreate<CpModelMapping>()->Literals(circuit.literals());
1719  const int num_nodes = ReindexArcs(&tails, &heads, &literals);
1720  m->Add(SubcircuitConstraint(num_nodes, tails, heads, literals));
1721 }
1722 
1723 void LoadRoutesConstraint(const ConstraintProto& ct, Model* m) {
1724  const auto& routes = ct.routes();
1725  if (routes.tails().empty()) return;
1726 
1727  std::vector<int> tails(routes.tails().begin(), routes.tails().end());
1728  std::vector<int> heads(routes.heads().begin(), routes.heads().end());
1729  std::vector<Literal> literals =
1730  m->GetOrCreate<CpModelMapping>()->Literals(routes.literals());
1731  const int num_nodes = ReindexArcs(&tails, &heads, &literals);
1732  m->Add(SubcircuitConstraint(num_nodes, tails, heads, literals,
1733  /*multiple_subcircuit_through_zero=*/true));
1734 }
1735 
1736 void LoadCircuitCoveringConstraint(const ConstraintProto& ct, Model* m) {
1737  auto* mapping = m->GetOrCreate<CpModelMapping>();
1738  const std::vector<IntegerVariable> nexts =
1739  mapping->Integers(ct.circuit_covering().nexts());
1740  const std::vector<std::vector<Literal>> graph =
1742  const std::vector<int> distinguished(
1743  ct.circuit_covering().distinguished_nodes().begin(),
1744  ct.circuit_covering().distinguished_nodes().end());
1745  m->Add(ExactlyOnePerRowAndPerColumn(graph));
1746  m->Add(CircuitCovering(graph, distinguished));
1747 }
1748 
1749 bool LoadConstraint(const ConstraintProto& ct, Model* m) {
1750  switch (ct.constraint_case()) {
1751  case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
1752  return true;
1753  case ConstraintProto::ConstraintCase::kBoolOr:
1755  return true;
1756  case ConstraintProto::ConstraintCase::kBoolAnd:
1758  return true;
1759  case ConstraintProto::ConstraintCase::kAtMostOne:
1761  return true;
1762  case ConstraintProto::ConstraintCase::kBoolXor:
1764  return true;
1765  case ConstraintProto::ConstraintProto::kLinear:
1767  return true;
1768  case ConstraintProto::ConstraintProto::kAllDiff:
1770  return true;
1771  case ConstraintProto::ConstraintProto::kIntProd:
1773  return true;
1774  case ConstraintProto::ConstraintProto::kIntDiv:
1776  return true;
1777  case ConstraintProto::ConstraintProto::kIntMin:
1779  return true;
1780  case ConstraintProto::ConstraintProto::kLinMax:
1782  return true;
1783  case ConstraintProto::ConstraintProto::kIntMax:
1785  return true;
1786  case ConstraintProto::ConstraintProto::kInterval:
1787  // Already dealt with.
1788  return true;
1789  case ConstraintProto::ConstraintProto::kNoOverlap:
1791  return true;
1792  case ConstraintProto::ConstraintProto::kNoOverlap2D:
1794  return true;
1795  case ConstraintProto::ConstraintProto::kCumulative:
1797  return true;
1798  case ConstraintProto::ConstraintProto::kElement:
1800  return true;
1801  case ConstraintProto::ConstraintProto::kTable:
1802  LoadTableConstraint(ct, m);
1803  return true;
1804  case ConstraintProto::ConstraintProto::kAutomaton:
1806  return true;
1807  case ConstraintProto::ConstraintProto::kCircuit:
1809  return true;
1810  case ConstraintProto::ConstraintProto::kRoutes:
1812  return true;
1813  case ConstraintProto::ConstraintProto::kCircuitCovering:
1815  return true;
1816  default:
1817  return false;
1818  }
1819 }
1820 
1821 } // namespace sat
1822 } // namespace operations_research
var
IntVar * var
Definition: expr_array.cc:1858
operations_research::sat::LinearExpression::vars
std::vector< IntegerVariable > vars
Definition: linear_constraint.h:166
operations_research::sat::IntegerTrail::IsFixed
bool IsFixed(IntegerVariable i) const
Definition: integer.h:1225
operations_research::sat::IntegerLiteral
Definition: integer.h:164
min
int64 min
Definition: alldiff_cst.cc:138
operations_research::sat::ConditionalLowerOrEqualWithOffset
std::function< void(Model *)> ConditionalLowerOrEqualWithOffset(IntegerVariable a, IntegerVariable b, int64 offset, Literal is_le)
Definition: precedences.h:419
map_util.h
operations_research::sat::LoadIntProdConstraint
void LoadIntProdConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1229
operations_research::sat::IntegerLiteral::GreaterOrEqual
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1197
cp_model.pb.h
operations_research::sat::kNoIntegerVariable
const IntegerVariable kNoIntegerVariable(-1)
operations_research::sat::LiteralXorIs
std::function< void(Model *)> LiteralXorIs(const std::vector< Literal > &literals, bool value)
Definition: cp_constraints.h:111
operations_research::sat::FloorRatio
IntegerValue FloorRatio(IntegerValue dividend, IntegerValue positive_divisor)
Definition: integer.h:101
max
int64 max
Definition: alldiff_cst.cc:139
operations_research::sat::DetectEquivalencesInElementConstraint
bool DetectEquivalencesInElementConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1329
operations_research::sat::LoadElementConstraint
void LoadElementConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1561
operations_research::sat::CpModelMapping::Literal
sat::Literal Literal(int ref) const
Definition: cp_model_loader.h:110
operations_research::sat::CpModelMapping::CreateVariables
void CreateVariables(const CpModelProto &model_proto, bool view_all_booleans_as_integers, Model *m)
Definition: cp_model_loader.cc:113
operations_research::sat::IntegerLiteral::var
IntegerVariable var
Definition: integer.h:198
operations_research::sat::LoadRoutesConstraint
void LoadRoutesConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1723
operations_research::sat::ImpliedBounds
Definition: implied_bounds.h:77
operations_research::Domain::NumIntervals
int NumIntervals() const
Basic read-only std::vector<> wrapping to view a Domain as a sorted list of non-adjacent intervals.
Definition: sorted_interval_list.h:336
operations_research::sat::ReifiedBoolOr
std::function< void(Model *)> ReifiedBoolOr(const std::vector< Literal > &literals, Literal r)
Definition: sat_solver.h:914
operations_research::sat::LoadElementConstraintBounds
void LoadElementConstraintBounds(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1387
operations_research::sat::LoadCircuitCoveringConstraint
void LoadCircuitCoveringConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1736
all_different.h
operations_research::sat::IntegerTrail::UpperBound
IntegerValue UpperBound(IntegerVariable i) const
Definition: integer.h:1221
operations_research::sat::AllDifferentAC
std::function< void(Model *)> AllDifferentAC(const std::vector< IntegerVariable > &variables)
Definition: all_different.cc:76
operations_research::sat::FullEncodingFixedPointComputer
Definition: cp_model_loader.cc:668
operations_research::sat::UsedVariables
std::vector< int > UsedVariables(const ConstraintProto &ct)
Definition: cp_model_utils.cc:441
logging.h
disjunctive.h
operations_research::Domain::Size
int64 Size() const
Returns the number of elements in the domain.
Definition: sorted_interval_list.cc:194
operations_research::sat::SatSolver::AddProblemClause
bool AddProblemClause(absl::Span< const Literal > literals)
Definition: sat_solver.cc:201
operations_research::sat::CpModelMapping::IsInteger
bool IsInteger(int ref) const
Definition: cp_model_loader.h:105
operations_research::Domain::UnionWith
Domain UnionWith(const Domain &domain) const
Returns the union of D and domain.
Definition: sorted_interval_list.cc:321
operations_research::sat::NonOverlappingRectangles
std::function< void(Model *)> NonOverlappingRectangles(const std::vector< IntervalVariable > &x, const std::vector< IntervalVariable > &y, bool is_strict)
Definition: diffn.h:155
model_proto
CpModelProto const * model_proto
Definition: cp_model_solver.cc:2023
value
int64 value
Definition: demon_profiler.cc:43
operations_research::sat::LinearExpression
Definition: linear_constraint.h:165
operations_research::sat::ExactlyOnePerRowAndPerColumn
std::function< void(Model *)> ExactlyOnePerRowAndPerColumn(const std::vector< std::vector< Literal >> &graph)
Definition: circuit.cc:452
gtl::ITIVector::resize
void resize(size_type new_size)
Definition: int_type_indexed_vector.h:149
operations_research::sat::AddNegatedTableConstraint
void AddNegatedTableConstraint(absl::Span< const IntegerVariable > vars, std::vector< std::vector< int64 >> tuples, Model *model)
Definition: sat/table.cc:457
saturated_arithmetic.h
operations_research
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
Definition: dense_doubly_linked_list.h:21
circuit.h
operations_research::sat::GetReferencesUsedByConstraint
IndexReferences GetReferencesUsedByConstraint(const ConstraintProto &ct)
Definition: cp_model_utils.cc:46
operations_research::sat::NegationOf
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Definition: integer.cc:42
kint64min
static const int64 kint64min
Definition: integral_types.h:60
operations_research::sat::ReindexArcs
int ReindexArcs(std::vector< int > *tails, std::vector< int > *heads, std::vector< Literal > *literals)
Definition: circuit.cc:471
operations_research::sat::IntegerTrail
Definition: integer.h:534
operations_research::sat::CpModelMapping::ConstraintIsAlreadyLoaded
bool ConstraintIsAlreadyLoaded(const ConstraintProto *ct) const
Definition: cp_model_loader.h:153
operations_research::sat::LinearExpression::coeffs
std::vector< IntegerValue > coeffs
Definition: linear_constraint.h:167
operations_research::sat::CpModelMapping::Literals
std::vector< sat::Literal > Literals(const ProtoIndices &indices) const
Definition: cp_model_loader.h:136
operations_research::sat::FullEncodingFixedPointComputer::ComputeFixedPoint
void ComputeFixedPoint()
Definition: cp_model_loader.cc:757
int64
int64_t int64
Definition: integral_types.h:34
operations_research::sat::EnforcedClause
std::function< void(Model *)> EnforcedClause(absl::Span< const Literal > enforcement_literals, absl::Span< const Literal > clause)
Definition: sat_solver.h:930
gtl::ITIVector::size
size_type size() const
Definition: int_type_indexed_vector.h:146
operations_research::sat::LoadIntDivConstraint
void LoadIntDivConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1238
operations_research::sat::FixedDivisionConstraint
std::function< void(Model *)> FixedDivisionConstraint(IntegerVariable a, IntegerValue b, IntegerVariable c)
Definition: integer_expr.h:805
sat_solver.h
operations_research::Domain
We call domain any subset of Int64 = [kint64min, kint64max].
Definition: sorted_interval_list.h:81
operations_research::sat::LoadCircuitConstraint
void LoadCircuitConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1711
operations_research::sat::Model
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:38
index
int index
Definition: pack.cc:508
sat_base.h
int32
int int32
Definition: integral_types.h:33
operations_research::sat::IntegerEncoder::AssociateToIntegerEqualValue
void AssociateToIntegerEqualValue(Literal literal, IntegerVariable var, IntegerValue value)
Definition: integer.cc:323
operations_research::sat::LoadBoolAndConstraint
void LoadBoolAndConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:955
pb_constraint.h
operations_research::sat::Model::Get
T Get(std::function< T(const Model &)> f) const
Similar to Add() but this is const.
Definition: sat/model.h:87
operations_research::sat::SatSolver
Definition: sat_solver.h:58
operations_research::sat::LoadLinMaxConstraint
void LoadLinMaxConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1274
operations_research::sat::SubcircuitConstraint
std::function< void(Model *)> SubcircuitConstraint(int num_nodes, const std::vector< int > &tails, const std::vector< int > &heads, const std::vector< Literal > &literals, bool multiple_subcircuit_through_zero)
Definition: circuit.cc:498
operations_research::sat::LoadAtMostOneConstraint
void LoadAtMostOneConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:969
operations_research::sat::IndexReferences::variables
std::vector< int > variables
Definition: cp_model_utils.h:53
operations_research::sat::Literal
Definition: sat_base.h:64
operations_research::Domain::IntersectionWith
Domain IntersectionWith(const Domain &domain) const
Returns the intersection of D and domain.
Definition: sorted_interval_list.cc:282
operations_research::sat::PositiveRef
int PositiveRef(int ref)
Definition: cp_model_utils.h:33
operations_research::sat::LoadBoolOrConstraint
void LoadBoolOrConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:946
operations_research::sat::FullEncodingFixedPointComputer::FullEncodingFixedPointComputer
FullEncodingFixedPointComputer(const CpModelProto &model_proto, Model *model)
Definition: cp_model_loader.cc:670
operations_research::sat::WeightedSumGreaterOrEqual
std::function< void(Model *)> WeightedSumGreaterOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64 lower_bound)
Definition: integer_expr.h:371
operations_research::sat::CpModelMapping::Integers
std::vector< IntegerVariable > Integers(const List &list) const
Definition: cp_model_loader.h:129
operations_research::sat::LoadConstraint
bool LoadConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1749
operations_research::sat::NewBooleanVariable
std::function< BooleanVariable(Model *)> NewBooleanVariable()
Definition: integer.h:1315
operations_research::Domain::IsEmpty
bool IsEmpty() const
Returns true if this is the empty set.
Definition: sorted_interval_list.cc:190
operations_research::sat::CpModelMapping::Intervals
std::vector< IntervalVariable > Intervals(const ProtoIndices &indices) const
Definition: cp_model_loader.h:143
operations_research::sat::BooleanLinearConstraint
std::function< void(Model *)> BooleanLinearConstraint(int64 lower_bound, int64 upper_bound, std::vector< LiteralWithCoeff > *cst)
Definition: sat_solver.h:832
operations_research::sat::ConditionalWeightedSumLowerOrEqual
std::function< void(Model *)> ConditionalWeightedSumLowerOrEqual(const std::vector< Literal > &enforcement_literals, const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64 upper_bound)
Definition: integer_expr.h:393
operations_research::sat::LoadAllDiffConstraint
void LoadAllDiffConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1202
operations_research::sat::IntegerEncoder
Definition: integer.h:278
operations_research::sat::Literal::Negated
Literal Negated() const
Definition: sat_base.h:91
sat_parameters.pb.h
operations_research::sat::TransitionConstraint
std::function< void(Model *)> TransitionConstraint(const std::vector< IntegerVariable > &vars, const std::vector< std::vector< int64 >> &automaton, int64 initial_state, const std::vector< int64 > &final_states)
Definition: sat/table.cc:591
int_type.h
precedences.h
intervals.h
operations_research::sat::IndexReferences
Definition: cp_model_utils.h:52
operations_research::sat::AffineExpression
Definition: integer.h:214
operations_research::sat::CpModelMapping::DetectOptionalVariables
void DetectOptionalVariables(const CpModelProto &model_proto, Model *m)
Definition: cp_model_loader.cc:589
gtl::STLSortAndRemoveDuplicates
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
Definition: stl_util.h:58
operations_research::sat::AddTableConstraint
void AddTableConstraint(absl::Span< const IntegerVariable > vars, std::vector< std::vector< int64 >> tuples, Model *model)
Definition: sat/table.cc:248
operations_research::sat::CanonicalizeExpr
LinearExpression CanonicalizeExpr(const LinearExpression &expr)
Definition: linear_constraint.cc:271
integer_expr.h
operations_research::sat::Cumulative
std::function< void(Model *)> Cumulative(const std::vector< IntervalVariable > &vars, const std::vector< AffineExpression > &demands, AffineExpression capacity, SchedulingConstraintHelper *helper)
Definition: cumulative.cc:35
int_type_indexed_vector.h
operations_research::sat::PartialIsOneOfVar
std::function< void(Model *)> PartialIsOneOfVar(IntegerVariable target_var, const std::vector< IntegerVariable > &vars, const std::vector< Literal > &selectors)
Definition: cp_constraints.h:159
operations_research::sat::HasEnforcementLiteral
bool HasEnforcementLiteral(const ConstraintProto &ct)
Definition: cp_model_utils.h:37
operations_research::sat::LoadLinearConstraint
void LoadLinearConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1055
operations_research::sat::CircuitCovering
std::function< void(Model *)> CircuitCovering(const std::vector< std::vector< Literal >> &graph, const std::vector< int > &distinguished_nodes)
Definition: circuit.cc:540
ct
const Constraint * ct
Definition: demon_profiler.cc:42
operations_research::sat::IntegerTrail::ReserveSpaceForNumVariables
void ReserveSpaceForNumVariables(int num_vars)
Definition: integer.cc:580
operations_research::sat::Value
std::function< int64(const Model &)> Value(IntegerVariable v)
Definition: integer.h:1396
operations_research::sat::kNoBooleanVariable
const BooleanVariable kNoBooleanVariable(-1)
operations_research::sat::WeightedSumLowerOrEqual
std::function< void(Model *)> WeightedSumLowerOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64 upper_bound)
Definition: integer_expr.h:266
cp_constraints.h
operations_research::sat::IsFixed
std::function< bool(const Model &)> IsFixed(IntegerVariable v)
Definition: integer.h:1388
operations_research::sat::AllDifferentOnBounds
std::function< void(Model *)> AllDifferentOnBounds(const std::vector< IntegerVariable > &vars)
Definition: all_different.cc:65
implied_bounds.h
operations_research::sat::NewInterval
std::function< IntervalVariable(Model *)> NewInterval(int64 min_start, int64 max_end, int64 size)
Definition: intervals.h:546
gtl::ITIVector::assign
void assign(size_type n, const value_type &val)
Definition: int_type_indexed_vector.h:130
operations_research::sat::CpModelMapping::PropagateEncodingFromEquivalenceRelations
void PropagateEncodingFromEquivalenceRelations(const CpModelProto &model_proto, Model *m)
Definition: cp_model_loader.cc:506
operations_research::sat::CpModelMapping::Integer
IntegerVariable Integer(int ref) const
Definition: cp_model_loader.h:115
operations_research::sat::ImpliesInInterval
std::function< void(Model *)> ImpliesInInterval(Literal in_interval, IntegerVariable v, int64 lb, int64 ub)
Definition: integer.h:1473
diffn.h
sorted_interval_list.h
operations_research::sat::LoadIntMinConstraint
void LoadIntMinConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1255
operations_research::sat::ClauseConstraint
std::function< void(Model *)> ClauseConstraint(absl::Span< const Literal > literals)
Definition: sat_solver.h:884
operations_research::sat::LoadNoOverlap2dConstraint
void LoadNoOverlap2dConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1301
model
GRBmodel * model
Definition: gurobi_interface.cc:195
operations_research::Domain::InverseMultiplicationBy
Domain InverseMultiplicationBy(const int64 coeff) const
Returns {x ∈ Int64, ∃ e ∈ D, x * coeff = e}.
Definition: sorted_interval_list.cc:433
operations_research::sat::LoadNoOverlapConstraint
void LoadNoOverlapConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1296
operations_research::sat::LinearExpression::offset
IntegerValue offset
Definition: linear_constraint.h:168
operations_research::sat::LoadBoolXorConstraint
void LoadBoolXorConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:975
operations_research::sat::RefIsPositive
bool RefIsPositive(int ref)
Definition: cp_model_utils.h:34
operations_research::sat::CpModelMapping
Definition: cp_model_loader.h:63
operations_research::sat::IntegerTrail::LowerBound
IntegerValue LowerBound(IntegerVariable i) const
Definition: integer.h:1217
operations_research::sat::IntegerTrail::UpdateInitialDomain
bool UpdateInitialDomain(IntegerVariable var, Domain domain)
Definition: integer.cc:636
operations_research::sat::AtMostOneConstraint
std::function< void(Model *)> AtMostOneConstraint(const std::vector< Literal > &literals)
Definition: sat_solver.h:870
stl_util.h
operations_research::sat::LoadElementConstraintAC
void LoadElementConstraintAC(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1439
operations_research::sat::AllDifferentBinary
std::function< void(Model *)> AllDifferentBinary(const std::vector< IntegerVariable > &vars)
Definition: all_different.cc:31
operations_research::sat::ConditionalWeightedSumGreaterOrEqual
std::function< void(Model *)> ConditionalWeightedSumGreaterOrEqual(const std::vector< Literal > &enforcement_literals, const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64 lower_bound)
Definition: integer_expr.h:470
operations_research::sat::MaybeFullyEncodeMoreVariables
void MaybeFullyEncodeMoreVariables(const CpModelProto &model_proto, Model *m)
Definition: cp_model_loader.cc:937
operations_research::sat::LoadTableConstraint
void LoadTableConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1638
operations_research::Domain::Complement
Domain Complement() const
Returns the set Int64 ∖ D.
Definition: sorted_interval_list.cc:245
operations_research::sat::Disjunctive
std::function< void(Model *)> Disjunctive(const std::vector< IntervalVariable > &vars)
Definition: disjunctive.cc:30
operations_research::sat::CpModelMapping::ExtractEncoding
void ExtractEncoding(const CpModelProto &model_proto, Model *m)
Definition: cp_model_loader.cc:259
operations_research::sat::IntegerLiteral::LowerOrEqual
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1203
operations_research::sat::IsEqualToMinOf
std::function< void(Model *)> IsEqualToMinOf(IntegerVariable min_var, const std::vector< IntegerVariable > &vars)
Definition: integer_expr.h:628
operations_research::sat::LoadCumulativeConstraint
void LoadCumulativeConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1313
cp_model_loader.h
operations_research::sat::DivisionConstraint
std::function< void(Model *)> DivisionConstraint(IntegerVariable a, IntegerVariable b, IntegerVariable c)
Definition: integer_expr.h:792
operations_research::sat::Implication
std::function< void(Model *)> Implication(const std::vector< Literal > &enforcement_literals, IntegerLiteral i)
Definition: integer.h:1446
operations_research::sat::Equality
std::function< void(Model *)> Equality(IntegerVariable v, int64 value)
Definition: integer.h:1433
operations_research::sat::CpModelMapping::PotentialEncodedValues
const absl::flat_hash_set< int64 > & PotentialEncodedValues(int var)
Definition: cp_model_loader.h:200
gtl::ITIVector< ConstraintIndex, bool >
capacity
int64 capacity
Definition: routing_flow.cc:129
proto
CpModelProto proto
Definition: cp_model_fz_solver.cc:106
operations_research::sat::GetExprFromProto
LinearExpression GetExprFromProto(const LinearExpressionProto &expr_proto, const CpModelMapping &mapping)
Definition: cp_model_loader.cc:1263
operations_research::sat::IntegerEncoder::VariableIsFullyEncoded
bool VariableIsFullyEncoded(IntegerVariable var) const
Definition: integer.cc:83
operations_research::sat::Model::GetOrCreate
T * GetOrCreate()
Returns an object of type T that is unique to this model (like a "local" singleton).
Definition: sat/model.h:106
operations_research::Domain::Max
int64 Max() const
Returns the max value of the domain.
Definition: sorted_interval_list.cc:211
operations_research::Domain::Min
int64 Min() const
Returns the min value of the domain.
Definition: sorted_interval_list.cc:206
operations_research::sat::Model::Add
T Add(std::function< T(Model *)> f)
This makes it possible to have a nicer API on the client side, and it allows both of these forms:
Definition: sat/model.h:81
operations_research::sat::LoadAutomatonConstraint
void LoadAutomatonConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1659
operations_research::sat::IsEqualToMaxOf
std::function< void(Model *)> IsEqualToMaxOf(IntegerVariable max_var, const std::vector< IntegerVariable > &vars)
Definition: integer_expr.h:697
literal
Literal literal
Definition: optimization.cc:84
operations_research::sat::NewOptionalInterval
std::function< IntervalVariable(Model *)> NewOptionalInterval(int64 min_start, int64 max_end, int64 size, Literal is_present)
Definition: intervals.h:576
operations_research::sat::ReadDomainFromProto
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
Definition: cp_model_utils.h:102
operations_research::sat::ReifiedBoolAnd
std::function< void(Model *)> ReifiedBoolAnd(const std::vector< Literal > &literals, Literal r)
Definition: sat_solver.h:948
cumulative.h
operations_research::sat::GetSquareMatrixFromIntegerVariables
std::vector< std::vector< Literal > > GetSquareMatrixFromIntegerVariables(const std::vector< IntegerVariable > &vars, Model *m)
Definition: cp_model_loader.cc:1681
operations_research::sat::ProductConstraint
std::function< void(Model *)> ProductConstraint(IntegerVariable a, IntegerVariable b, IntegerVariable p)
Definition: integer_expr.h:751
operations_research::sat::LoadIntMaxConstraint
void LoadIntMaxConstraint(const ConstraintProto &ct, Model *m)
Definition: cp_model_loader.cc:1288
operations_research::sat::FullyEncodeVariable
std::function< std::vector< IntegerEncoder::ValueLiteralPair >Model *)> FullyEncodeVariable(IntegerVariable var)
Definition: integer.h:1496
parameters
SatParameters parameters
Definition: cp_model_fz_solver.cc:107
table.h
integer.h
kint64max
static const int64 kint64max
Definition: integral_types.h:62
operations_research::Domain::Contains
bool Contains(int64 value) const
Returns true iff value is in Domain.
Definition: sorted_interval_list.cc:221
operations_research::sat::kNoIntervalVariable
const IntervalVariable kNoIntervalVariable(-1)
cp_model_utils.h
gtl::ContainsKey
bool ContainsKey(const Collection &collection, const Key &key)
Definition: map_util.h:170