OR-Tools  9.0
cp_model.cc
Go to the documentation of this file.
1 // Copyright 2010-2021 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 
14 #include "ortools/sat/cp_model.h"
15 
16 #include <cstdint>
17 #include <limits>
18 
19 #include "absl/strings/str_format.h"
20 #include "ortools/base/map_util.h"
25 
26 namespace operations_research {
27 namespace sat {
28 
29 BoolVar::BoolVar() : cp_model_(nullptr), index_(0) {}
30 
31 BoolVar::BoolVar(int index, CpModelProto* cp_model)
32  : cp_model_(cp_model), index_(index) {}
33 
34 BoolVar BoolVar::WithName(const std::string& name) {
35  cp_model_->mutable_variables(index_)->set_name(name);
36  return *this;
37 }
38 
39 std::string BoolVar::DebugString() const {
40  if (index_ < 0) {
41  return absl::StrFormat("Not(%s)", Not().DebugString());
42  } else {
43  std::string output;
44  const IntegerVariableProto& var_proto = cp_model_->variables(index_);
45  // Special case for constant variables without names.
46  if (var_proto.name().empty() && var_proto.domain_size() == 2 &&
47  var_proto.domain(0) == var_proto.domain(1)) {
48  output.append(var_proto.domain(0) == 0 ? "false" : "true");
49  } else {
50  if (var_proto.name().empty()) {
51  absl::StrAppendFormat(&output, "BoolVar%i(", index_);
52  } else {
53  absl::StrAppendFormat(&output, "%s(", var_proto.name());
54  }
55  if (var_proto.domain(0) == var_proto.domain(1)) {
56  output.append(var_proto.domain(0) == 0 ? "false)" : "true)");
57  } else {
58  absl::StrAppend(&output, var_proto.domain(0), ", ", var_proto.domain(1),
59  ")");
60  }
61  }
62  return output;
63  }
64 }
65 
66 BoolVar Not(BoolVar x) { return x.Not(); }
67 
68 std::ostream& operator<<(std::ostream& os, const BoolVar& var) {
69  os << var.DebugString();
70  return os;
71 }
72 
73 IntVar::IntVar() : cp_model_(nullptr), index_(0) {}
74 
75 IntVar::IntVar(int index, CpModelProto* cp_model)
76  : cp_model_(cp_model), index_(index) {
78 }
79 
80 IntVar IntVar::WithName(const std::string& name) {
81  cp_model_->mutable_variables(index_)->set_name(name);
82  return *this;
83 }
84 
86  cp_model_ = var.cp_model_;
87  index_ = var.index_;
88 }
89 
91  CHECK_EQ(2, Proto().domain_size());
92  CHECK_GE(Proto().domain(0), 0);
93  CHECK_LE(Proto().domain(1), 1);
94  BoolVar var;
95  var.cp_model_ = cp_model_;
96  var.index_ = index();
97  return var;
98 }
99 
101  return LinearExpr(*this).AddConstant(value);
102 }
103 
104 std::string IntVar::DebugString() const {
105  if (index_ < 0) {
106  return absl::StrFormat("Not(%s)",
107  IntVar(NegatedRef(index_), cp_model_).DebugString());
108  }
109  const IntegerVariableProto& var_proto = cp_model_->variables(index_);
110  // Special case for constant variables without names.
111  if (var_proto.name().empty() && var_proto.domain_size() == 2 &&
112  var_proto.domain(0) == var_proto.domain(1)) {
113  return absl::StrCat(var_proto.domain(0));
114  } else {
115  std::string output;
116  if (var_proto.name().empty()) {
117  absl::StrAppend(&output, "IntVar", index_, "(");
118  } else {
119  absl::StrAppend(&output, var_proto.name(), "(");
120  }
121  if (var_proto.domain_size() == 2 &&
122  var_proto.domain(0) == var_proto.domain(1)) {
123  absl::StrAppend(&output, var_proto.domain(0), ")");
124  } else {
125  // TODO(user): Use domain pretty print function.
126  absl::StrAppend(&output, var_proto.domain(0), ", ", var_proto.domain(1),
127  ")");
128  }
129  return output;
130  }
131 }
132 
133 std::ostream& operator<<(std::ostream& os, const IntVar& var) {
134  os << var.DebugString();
135  return os;
136 }
137 
139 
141 
143 
144 LinearExpr::LinearExpr(int64_t constant) { constant_ = constant; }
145 
146 LinearExpr LinearExpr::Sum(absl::Span<const IntVar> vars) {
147  LinearExpr result;
148  for (const IntVar& var : vars) {
149  result.AddVar(var);
150  }
151  return result;
152 }
153 
154 LinearExpr LinearExpr::ScalProd(absl::Span<const IntVar> vars,
155  absl::Span<const int64_t> coeffs) {
156  CHECK_EQ(vars.size(), coeffs.size());
157  LinearExpr result;
158  for (int i = 0; i < vars.size(); ++i) {
159  result.AddTerm(vars[i], coeffs[i]);
160  }
161  return result;
162 }
163 
165  LinearExpr result;
166  result.AddTerm(var, coefficient);
167  return result;
168 }
169 
170 LinearExpr LinearExpr::BooleanSum(absl::Span<const BoolVar> vars) {
171  LinearExpr result;
172  for (const IntVar& var : vars) {
173  result.AddVar(var);
174  }
175  return result;
176 }
177 
178 LinearExpr LinearExpr::BooleanScalProd(absl::Span<const BoolVar> vars,
179  absl::Span<const int64_t> coeffs) {
180  CHECK_EQ(vars.size(), coeffs.size());
181  LinearExpr result;
182  for (int i = 0; i < vars.size(); ++i) {
183  result.AddTerm(vars[i], coeffs[i]);
184  }
185  return result;
186 }
187 
189  constant_ += value;
190  return *this;
191 }
192 
194 
195 void LinearExpr::AddTerm(IntVar var, int64_t coeff) {
196  const int index = var.index_;
197  if (RefIsPositive(index)) {
198  variables_.push_back(var);
199  coefficients_.push_back(coeff);
200  } else {
201  variables_.push_back(IntVar(PositiveRef(var.index_), var.cp_model_));
202  coefficients_.push_back(-coeff);
203  constant_ += coeff;
204  }
205 }
206 
207 Constraint::Constraint(ConstraintProto* proto) : proto_(proto) {}
208 
209 Constraint Constraint::WithName(const std::string& name) {
210  proto_->set_name(name);
211  return *this;
212 }
213 
214 const std::string& Constraint::Name() const { return proto_->name(); }
215 
216 Constraint Constraint::OnlyEnforceIf(absl::Span<const BoolVar> literals) {
217  for (const BoolVar& var : literals) {
218  proto_->add_enforcement_literal(var.index_);
219  }
220  return *this;
221 }
222 
224  proto_->add_enforcement_literal(literal.index_);
225  return *this;
226 }
227 
229  proto_->mutable_circuit()->add_tails(tail);
230  proto_->mutable_circuit()->add_heads(head);
231  proto_->mutable_circuit()->add_literals(literal.index_);
232 }
233 
235  proto_->mutable_routes()->add_tails(tail);
236  proto_->mutable_routes()->add_heads(head);
237  proto_->mutable_routes()->add_literals(literal.index_);
238 }
239 
240 void TableConstraint::AddTuple(absl::Span<const int64_t> tuple) {
241  CHECK_EQ(tuple.size(), proto_->table().vars_size());
242  for (const int64_t t : tuple) {
243  proto_->mutable_table()->add_values(t);
244  }
245 }
246 
247 ReservoirConstraint::ReservoirConstraint(ConstraintProto* proto,
248  CpModelBuilder* builder)
249  : Constraint(proto), builder_(builder) {}
250 
252  proto_->mutable_reservoir()->add_times(
253  builder_->GetOrCreateIntegerIndex(time.index_));
254  proto_->mutable_reservoir()->add_demands(demand);
255  proto_->mutable_reservoir()->add_actives(builder_->IndexFromConstant(1));
256 }
257 
259  BoolVar is_active) {
260  proto_->mutable_reservoir()->add_times(
261  builder_->GetOrCreateIntegerIndex(time.index_));
262  proto_->mutable_reservoir()->add_demands(demand);
263  proto_->mutable_reservoir()->add_actives(is_active.index_);
264 }
265 
267  int64_t transition_label) {
268  proto_->mutable_automaton()->add_transition_tail(tail);
269  proto_->mutable_automaton()->add_transition_head(head);
270  proto_->mutable_automaton()->add_transition_label(transition_label);
271 }
272 
274  IntervalVar y_coordinate) {
275  proto_->mutable_no_overlap_2d()->add_x_intervals(x_coordinate.index_);
276  proto_->mutable_no_overlap_2d()->add_y_intervals(y_coordinate.index_);
277 }
278 
279 CumulativeConstraint::CumulativeConstraint(ConstraintProto* proto,
280  CpModelBuilder* builder)
281  : Constraint(proto), builder_(builder) {}
282 
284  proto_->mutable_cumulative()->add_intervals(interval.index_);
285  proto_->mutable_cumulative()->add_demands(
286  builder_->GetOrCreateIntegerIndex(demand.index_));
287 }
288 
289 IntervalVar::IntervalVar() : cp_model_(nullptr), index_() {}
290 
291 IntervalVar::IntervalVar(int index, CpModelProto* cp_model)
292  : cp_model_(cp_model), index_(index) {}
293 
295  cp_model_->mutable_constraints(index_)->set_name(name);
296  return *this;
297 }
298 
300  return IntVar(Proto().start(), cp_model_);
301 }
302 
304  return IntVar(Proto().size(), cp_model_);
305 }
306 
307 IntVar IntervalVar::EndVar() const { return IntVar(Proto().end(), cp_model_); }
308 
310  return BoolVar(cp_model_->constraints(index_).enforcement_literal(0),
311  cp_model_);
312 }
313 
314 std::string IntervalVar::Name() const {
315  return cp_model_->constraints(index_).name();
316 }
317 
318 std::string IntervalVar::DebugString() const {
319  CHECK_GE(index_, 0);
320  const ConstraintProto& ct_proto = cp_model_->constraints(index_);
321  std::string output;
322  if (ct_proto.name().empty()) {
323  absl::StrAppend(&output, "IntervalVar", index_, "(");
324  } else {
325  absl::StrAppend(&output, ct_proto.name(), "(");
326  }
327  absl::StrAppend(&output, StartVar().DebugString(), ", ",
328  SizeVar().DebugString(), ", ", EndVar().DebugString(), ", ",
329  PresenceBoolVar().DebugString(), ")");
330  return output;
331 }
332 
333 std::ostream& operator<<(std::ostream& os, const IntervalVar& var) {
334  os << var.DebugString();
335  return os;
336 }
337 
338 int CpModelBuilder::IndexFromConstant(int64_t value) {
339  if (!gtl::ContainsKey(constant_to_index_map_, value)) {
340  const int index = cp_model_.variables_size();
341  IntegerVariableProto* const var_proto = cp_model_.add_variables();
342  var_proto->add_domain(value);
343  var_proto->add_domain(value);
344  constant_to_index_map_[value] = index;
345  }
346  return constant_to_index_map_[value];
347 }
348 
349 int CpModelBuilder::GetOrCreateIntegerIndex(int index) {
350  if (index >= 0) {
351  return index;
352  }
353  if (!gtl::ContainsKey(bool_to_integer_index_map_, index)) {
354  const int var = PositiveRef(index);
355  const IntegerVariableProto& old_var = cp_model_.variables(var);
356  const int new_index = cp_model_.variables_size();
357  IntegerVariableProto* const new_var = cp_model_.add_variables();
358  new_var->add_domain(0);
359  new_var->add_domain(1);
360  if (!old_var.name().empty()) {
361  new_var->set_name(absl::StrCat("Not(", old_var.name(), ")"));
362  }
363  AddEquality(IntVar(new_index, &cp_model_), BoolVar(index, &cp_model_));
364  bool_to_integer_index_map_[index] = new_index;
365  return new_index;
366  }
367  return bool_to_integer_index_map_[index];
368 }
369 
371  const int index = cp_model_.variables_size();
372  IntegerVariableProto* const var_proto = cp_model_.add_variables();
373  for (const auto& interval : domain) {
374  var_proto->add_domain(interval.start);
375  var_proto->add_domain(interval.end);
376  }
377  return IntVar(index, &cp_model_);
378 }
379 
381  const int index = cp_model_.variables_size();
382  IntegerVariableProto* const var_proto = cp_model_.add_variables();
383  var_proto->add_domain(0);
384  var_proto->add_domain(1);
385  return BoolVar(index, &cp_model_);
386 }
387 
389  return IntVar(IndexFromConstant(value), &cp_model_);
390 }
391 
393  return BoolVar(IndexFromConstant(1), &cp_model_);
394 }
395 
397  return BoolVar(IndexFromConstant(0), &cp_model_);
398 }
399 
401  IntVar end) {
402  return NewOptionalIntervalVar(start, size, end, TrueVar());
403 }
404 
406  IntVar end,
407  BoolVar presence) {
408  const int index = cp_model_.constraints_size();
409  ConstraintProto* const ct = cp_model_.add_constraints();
410  ct->add_enforcement_literal(presence.index_);
411  IntervalConstraintProto* const interval = ct->mutable_interval();
412  interval->set_start(GetOrCreateIntegerIndex(start.index_));
413  interval->set_size(GetOrCreateIntegerIndex(size.index_));
414  interval->set_end(GetOrCreateIntegerIndex(end.index_));
415  return IntervalVar(index, &cp_model_);
416 }
417 
418 Constraint CpModelBuilder::AddBoolOr(absl::Span<const BoolVar> literals) {
419  ConstraintProto* const proto = cp_model_.add_constraints();
420  for (const BoolVar& lit : literals) {
421  proto->mutable_bool_or()->add_literals(lit.index_);
422  }
423  return Constraint(proto);
424 }
425 
426 Constraint CpModelBuilder::AddBoolAnd(absl::Span<const BoolVar> literals) {
427  ConstraintProto* const proto = cp_model_.add_constraints();
428  for (const BoolVar& lit : literals) {
429  proto->mutable_bool_and()->add_literals(lit.index_);
430  }
431  return Constraint(proto);
432 }
433 
434 Constraint CpModelBuilder::AddBoolXor(absl::Span<const BoolVar> literals) {
435  ConstraintProto* const proto = cp_model_.add_constraints();
436  for (const BoolVar& lit : literals) {
437  proto->mutable_bool_xor()->add_literals(lit.index_);
438  }
439  return Constraint(proto);
440 }
441 
442 void CpModelBuilder::FillLinearTerms(const LinearExpr& left,
443  const LinearExpr& right,
444  LinearConstraintProto* proto) {
445  for (const IntVar& x : left.variables()) {
446  proto->add_vars(x.index_);
447  }
448  for (const int64_t coeff : left.coefficients()) {
449  proto->add_coeffs(coeff);
450  }
451  for (const IntVar& x : right.variables()) {
452  proto->add_vars(x.index_);
453  }
454  for (const int64_t coeff : right.coefficients()) {
455  proto->add_coeffs(-coeff);
456  }
457 }
458 
460  const LinearExpr& right) {
461  ConstraintProto* const proto = cp_model_.add_constraints();
462  FillLinearTerms(left, right, proto->mutable_linear());
463  const int64_t rhs = right.constant() - left.constant();
464  proto->mutable_linear()->add_domain(rhs);
465  proto->mutable_linear()->add_domain(rhs);
466  return Constraint(proto);
467 }
468 
470  const LinearExpr& right) {
471  ConstraintProto* const proto = cp_model_.add_constraints();
472  FillLinearTerms(left, right, proto->mutable_linear());
473  const int64_t rhs = right.constant() - left.constant();
474  proto->mutable_linear()->add_domain(rhs);
475  proto->mutable_linear()->add_domain(std::numeric_limits<int64_t>::max());
476  return Constraint(proto);
477 }
478 
480  const LinearExpr& right) {
481  ConstraintProto* const proto = cp_model_.add_constraints();
482  FillLinearTerms(left, right, proto->mutable_linear());
483  const int64_t rhs = right.constant() - left.constant();
484  proto->mutable_linear()->add_domain(std::numeric_limits<int64_t>::min());
485  proto->mutable_linear()->add_domain(rhs);
486  return Constraint(proto);
487 }
488 
490  const LinearExpr& right) {
491  ConstraintProto* const proto = cp_model_.add_constraints();
492  FillLinearTerms(left, right, proto->mutable_linear());
493  const int64_t rhs = right.constant() - left.constant();
494  proto->mutable_linear()->add_domain(rhs + 1);
495  proto->mutable_linear()->add_domain(std::numeric_limits<int64_t>::max());
496  return Constraint(proto);
497 }
498 
500  const LinearExpr& right) {
501  ConstraintProto* const proto = cp_model_.add_constraints();
502  FillLinearTerms(left, right, proto->mutable_linear());
503  const int64_t rhs = right.constant() - left.constant();
504  proto->mutable_linear()->add_domain(std::numeric_limits<int64_t>::min());
505  proto->mutable_linear()->add_domain(rhs - 1);
506  return Constraint(proto);
507 }
508 
510  const Domain& domain) {
511  ConstraintProto* const proto = cp_model_.add_constraints();
512  for (const IntVar& x : expr.variables()) {
513  proto->mutable_linear()->add_vars(x.index_);
514  }
515  for (const int64_t coeff : expr.coefficients()) {
516  proto->mutable_linear()->add_coeffs(coeff);
517  }
518  const int64_t cst = expr.constant();
519  for (const auto& i : domain) {
520  proto->mutable_linear()->add_domain(i.start - cst);
521  proto->mutable_linear()->add_domain(i.end - cst);
522  }
523  return Constraint(proto);
524 }
525 
527  const LinearExpr& right) {
528  ConstraintProto* const proto = cp_model_.add_constraints();
529  FillLinearTerms(left, right, proto->mutable_linear());
530  const int64_t rhs = right.constant() - left.constant();
531  proto->mutable_linear()->add_domain(std::numeric_limits<int64_t>::min());
532  proto->mutable_linear()->add_domain(rhs - 1);
533  proto->mutable_linear()->add_domain(rhs + 1);
534  proto->mutable_linear()->add_domain(std::numeric_limits<int64_t>::max());
535  return Constraint(proto);
536 }
537 
538 Constraint CpModelBuilder::AddAllDifferent(absl::Span<const IntVar> vars) {
539  ConstraintProto* const proto = cp_model_.add_constraints();
540  for (const IntVar& var : vars) {
541  proto->mutable_all_diff()->add_vars(GetOrCreateIntegerIndex(var.index_));
542  }
543  return Constraint(proto);
544 }
545 
547  IntVar index, absl::Span<const IntVar> variables, IntVar target) {
548  ConstraintProto* const proto = cp_model_.add_constraints();
549  proto->mutable_element()->set_index(GetOrCreateIntegerIndex(index.index_));
550  proto->mutable_element()->set_target(GetOrCreateIntegerIndex(target.index_));
551  for (const IntVar& var : variables) {
552  proto->mutable_element()->add_vars(GetOrCreateIntegerIndex(var.index_));
553  }
554  return Constraint(proto);
555 }
556 
558  absl::Span<const int64_t> values,
559  IntVar target) {
560  ConstraintProto* const proto = cp_model_.add_constraints();
561  proto->mutable_element()->set_index(GetOrCreateIntegerIndex(index.index_));
562  proto->mutable_element()->set_target(GetOrCreateIntegerIndex(target.index_));
563  for (int64_t value : values) {
564  proto->mutable_element()->add_vars(IndexFromConstant(value));
565  }
566  return Constraint(proto);
567 }
568 
570  return CircuitConstraint(cp_model_.add_constraints());
571 }
572 
574  return MultipleCircuitConstraint(cp_model_.add_constraints());
575 }
576 
578  absl::Span<const IntVar> vars) {
579  ConstraintProto* const proto = cp_model_.add_constraints();
580  for (const IntVar& var : vars) {
581  proto->mutable_table()->add_vars(GetOrCreateIntegerIndex(var.index_));
582  }
583  return TableConstraint(proto);
584 }
585 
587  absl::Span<const IntVar> vars) {
588  ConstraintProto* const proto = cp_model_.add_constraints();
589  for (const IntVar& var : vars) {
590  proto->mutable_table()->add_vars(GetOrCreateIntegerIndex(var.index_));
591  }
592  proto->mutable_table()->set_negated(true);
593  return TableConstraint(proto);
594 }
595 
597  absl::Span<const IntVar> variables,
598  absl::Span<const IntVar> inverse_variables) {
599  ConstraintProto* const proto = cp_model_.add_constraints();
600  for (const IntVar& var : variables) {
601  proto->mutable_inverse()->add_f_direct(GetOrCreateIntegerIndex(var.index_));
602  }
603  for (const IntVar& var : inverse_variables) {
604  proto->mutable_inverse()->add_f_inverse(
605  GetOrCreateIntegerIndex(var.index_));
606  }
607  return Constraint(proto);
608 }
609 
611  int64_t max_level) {
612  ConstraintProto* const proto = cp_model_.add_constraints();
613  proto->mutable_reservoir()->set_min_level(min_level);
614  proto->mutable_reservoir()->set_max_level(max_level);
615  return ReservoirConstraint(proto, this);
616 }
617 
619  absl::Span<const IntVar> transition_variables, int starting_state,
620  absl::Span<const int> final_states) {
621  ConstraintProto* const proto = cp_model_.add_constraints();
622  for (const IntVar& var : transition_variables) {
623  proto->mutable_automaton()->add_vars(GetOrCreateIntegerIndex(var.index_));
624  }
625  proto->mutable_automaton()->set_starting_state(starting_state);
626  for (const int final_state : final_states) {
627  proto->mutable_automaton()->add_final_states(final_state);
628  }
629  return AutomatonConstraint(proto);
630 }
631 
633  absl::Span<const IntVar> vars) {
634  ConstraintProto* const proto = cp_model_.add_constraints();
635  proto->mutable_int_min()->set_target(GetOrCreateIntegerIndex(target.index_));
636  for (const IntVar& var : vars) {
637  proto->mutable_int_min()->add_vars(GetOrCreateIntegerIndex(var.index_));
638  }
639  return Constraint(proto);
640 }
641 
642 void CpModelBuilder::LinearExprToProto(const LinearExpr& expr,
643  LinearExpressionProto* expr_proto) {
644  for (const IntVar var : expr.variables()) {
645  expr_proto->add_vars(GetOrCreateIntegerIndex(var.index_));
646  }
647  for (const int64_t coeff : expr.coefficients()) {
648  expr_proto->add_coeffs(coeff);
649  }
650  expr_proto->set_offset(expr.constant());
651 }
652 
654  const LinearExpr& target, absl::Span<const LinearExpr> exprs) {
655  ConstraintProto* const proto = cp_model_.add_constraints();
656  LinearExprToProto(target, proto->mutable_lin_min()->mutable_target());
657  for (const LinearExpr& expr : exprs) {
658  LinearExpressionProto* expr_proto = proto->mutable_lin_min()->add_exprs();
659  LinearExprToProto(expr, expr_proto);
660  }
661  return Constraint(proto);
662 }
663 
665  absl::Span<const IntVar> vars) {
666  ConstraintProto* const proto = cp_model_.add_constraints();
667  proto->mutable_int_max()->set_target(GetOrCreateIntegerIndex(target.index_));
668  for (const IntVar& var : vars) {
669  proto->mutable_int_max()->add_vars(GetOrCreateIntegerIndex(var.index_));
670  }
671  return Constraint(proto);
672 }
673 
675  const LinearExpr& target, absl::Span<const LinearExpr> exprs) {
676  ConstraintProto* const proto = cp_model_.add_constraints();
677  LinearExprToProto(target, proto->mutable_lin_max()->mutable_target());
678  for (const LinearExpr& expr : exprs) {
679  LinearExpressionProto* expr_proto = proto->mutable_lin_max()->add_exprs();
680  LinearExprToProto(expr, expr_proto);
681  }
682  return Constraint(proto);
683 }
684 
686  IntVar denominator) {
687  ConstraintProto* const proto = cp_model_.add_constraints();
688  proto->mutable_int_div()->set_target(GetOrCreateIntegerIndex(target.index_));
689  proto->mutable_int_div()->add_vars(GetOrCreateIntegerIndex(numerator.index_));
690  proto->mutable_int_div()->add_vars(
691  GetOrCreateIntegerIndex(denominator.index_));
692  return Constraint(proto);
693 }
694 
696  ConstraintProto* const proto = cp_model_.add_constraints();
697  proto->mutable_int_max()->set_target(GetOrCreateIntegerIndex(target.index_));
698  proto->mutable_int_max()->add_vars(GetOrCreateIntegerIndex(var.index_));
699  proto->mutable_int_max()->add_vars(
700  NegatedRef(GetOrCreateIntegerIndex(var.index_)));
701  return Constraint(proto);
702 }
703 
705  IntVar mod) {
706  ConstraintProto* const proto = cp_model_.add_constraints();
707  proto->mutable_int_mod()->set_target(GetOrCreateIntegerIndex(target.index_));
708  proto->mutable_int_mod()->add_vars(GetOrCreateIntegerIndex(var.index_));
709  proto->mutable_int_mod()->add_vars(GetOrCreateIntegerIndex(mod.index_));
710  return Constraint(proto);
711 }
712 
714  absl::Span<const IntVar> vars) {
715  ConstraintProto* const proto = cp_model_.add_constraints();
716  proto->mutable_int_prod()->set_target(GetOrCreateIntegerIndex(target.index_));
717  for (const IntVar& var : vars) {
718  proto->mutable_int_prod()->add_vars(GetOrCreateIntegerIndex(var.index_));
719  }
720  return Constraint(proto);
721 }
722 
723 Constraint CpModelBuilder::AddNoOverlap(absl::Span<const IntervalVar> vars) {
724  ConstraintProto* const proto = cp_model_.add_constraints();
725  for (const IntervalVar& var : vars) {
726  proto->mutable_no_overlap()->add_intervals(
727  GetOrCreateIntegerIndex(var.index_));
728  }
729  return Constraint(proto);
730 }
731 
733  return NoOverlap2DConstraint(cp_model_.add_constraints());
734 }
735 
737  ConstraintProto* const proto = cp_model_.add_constraints();
738  proto->mutable_cumulative()->set_capacity(
739  GetOrCreateIntegerIndex(capacity.index_));
740  return CumulativeConstraint(proto, this);
741 }
742 
744  cp_model_.mutable_objective()->Clear();
745  for (const IntVar& x : expr.variables()) {
746  cp_model_.mutable_objective()->add_vars(x.index_);
747  }
748  for (const int64_t coeff : expr.coefficients()) {
749  cp_model_.mutable_objective()->add_coeffs(coeff);
750  }
751  cp_model_.mutable_objective()->set_offset(expr.constant());
752 }
753 
755  cp_model_.mutable_objective()->Clear();
756  for (const IntVar& x : expr.variables()) {
757  cp_model_.mutable_objective()->add_vars(x.index_);
758  }
759  for (const int64_t coeff : expr.coefficients()) {
760  cp_model_.mutable_objective()->add_coeffs(-coeff);
761  }
762  cp_model_.mutable_objective()->set_offset(-expr.constant());
763  cp_model_.mutable_objective()->set_scaling_factor(-1.0);
764 }
765 
766 void CpModelBuilder::ScaleObjectiveBy(double scaling) {
767  CHECK(cp_model_.has_objective());
768  cp_model_.mutable_objective()->set_scaling_factor(
769  scaling * cp_model_.objective().scaling_factor());
770 }
771 
773  absl::Span<const IntVar> variables,
774  DecisionStrategyProto::VariableSelectionStrategy var_strategy,
775  DecisionStrategyProto::DomainReductionStrategy domain_strategy) {
776  DecisionStrategyProto* const proto = cp_model_.add_search_strategy();
777  for (const IntVar& var : variables) {
778  proto->add_variables(var.index_);
779  }
780  proto->set_variable_selection_strategy(var_strategy);
781  proto->set_domain_reduction_strategy(domain_strategy);
782 }
783 
785  absl::Span<const BoolVar> variables,
786  DecisionStrategyProto::VariableSelectionStrategy var_strategy,
787  DecisionStrategyProto::DomainReductionStrategy domain_strategy) {
788  DecisionStrategyProto* const proto = cp_model_.add_search_strategy();
789  for (const BoolVar& var : variables) {
790  proto->add_variables(var.index_);
791  }
792  proto->set_variable_selection_strategy(var_strategy);
793  proto->set_domain_reduction_strategy(domain_strategy);
794 }
795 
797  cp_model_.mutable_solution_hint()->add_vars(
798  GetOrCreateIntegerIndex(var.index_));
799  cp_model_.mutable_solution_hint()->add_values(value);
800 }
801 
803  cp_model_.mutable_solution_hint()->Clear();
804 }
805 
807  cp_model_.mutable_assumptions()->Add(lit.index_);
808 }
809 
810 void CpModelBuilder::AddAssumptions(absl::Span<const BoolVar> literals) {
811  for (const BoolVar& lit : literals) {
812  cp_model_.mutable_assumptions()->Add(lit.index_);
813  }
814 }
815 
817  cp_model_.mutable_assumptions()->Clear();
818 }
819 
820 void CpModelBuilder::CopyFrom(const CpModelProto& model_proto) {
821  cp_model_ = model_proto;
822  // Rebuild constant to index map.
823  constant_to_index_map_.clear();
824  for (int i = 0; i < cp_model_.variables_size(); ++i) {
825  const IntegerVariableProto& var = cp_model_.variables(i);
826  if (var.domain_size() == 2 && var.domain(0) == var.domain(1)) {
827  constant_to_index_map_[var.domain(0)] = i;
828  }
829  }
830  // This one would be more complicated to rebuild. Let's just clear it.
831  bool_to_integer_index_map_.clear();
832 }
833 
835  CHECK_GE(index, 0);
836  CHECK_LT(index, cp_model_.variables_size());
837  const IntegerVariableProto& proto = cp_model_.variables(index);
838  CHECK_EQ(2, proto.domain_size())
839  << "CpModelBuilder::GetBoolVarFromProtoIndex: The domain of the variable "
840  "is not Boolean";
841  CHECK_GE(0, proto.domain(0))
842  << "CpModelBuilder::GetBoolVarFromProtoIndex: The domain of the variable "
843  "is not Boolean";
844  CHECK_LE(1, proto.domain(1))
845  << "CpModelBuilder::GetBoolVarFromProtoIndex: The domain of the variable "
846  "is not Boolean";
847  return BoolVar(index, &cp_model_);
848 }
849 
851  CHECK_GE(index, 0);
852  CHECK_LT(index, cp_model_.variables_size());
853  return IntVar(index, &cp_model_);
854 }
855 
857  CHECK_GE(index, 0);
858  CHECK_LT(index, cp_model_.constraints_size());
859  const ConstraintProto& ct = cp_model_.constraints(index);
860  CHECK_EQ(ct.constraint_case(), ConstraintProto::kInterval)
861  << "CpModelBuilder::GetIntervalVarFromProtoIndex: the referenced "
862  "object is not an interval variable";
863  return IntervalVar(index, &cp_model_);
864 }
865 
866 int64_t SolutionIntegerValue(const CpSolverResponse& r,
867  const LinearExpr& expr) {
868  int64_t result = expr.constant();
869  for (int i = 0; i < expr.variables().size(); ++i) {
870  result += r.solution(expr.variables()[i].index_) * expr.coefficients()[i];
871  }
872  return result;
873 }
874 
875 int64_t SolutionIntegerMin(const CpSolverResponse& r, IntVar x) {
876  if (r.solution_size() > 0) {
877  return r.solution(x.index_);
878  } else {
879  return r.solution_lower_bounds(x.index_);
880  }
881 }
882 
883 int64_t SolutionIntegerMax(const CpSolverResponse& r, IntVar x) {
884  if (r.solution_size() > 0) {
885  return r.solution(x.index_);
886  } else {
887  return r.solution_upper_bounds(x.index_);
888  }
889 }
890 
891 bool SolutionBooleanValue(const CpSolverResponse& r, BoolVar x) {
892  const int ref = x.index_;
893  if (RefIsPositive(ref)) {
894  return r.solution(ref) == 1;
895  } else {
896  return r.solution(PositiveRef(ref)) == 0;
897  }
898 }
899 
900 } // namespace sat
901 } // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
#define CHECK(condition)
Definition: base/logging.h:498
#define CHECK_LT(val1, val2)
Definition: base/logging.h:708
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:705
#define CHECK_GE(val1, val2)
Definition: base/logging.h:709
#define CHECK_LE(val1, val2)
Definition: base/logging.h:707
We call domain any subset of Int64 = [kint64min, kint64max].
Specialized automaton constraint.
Definition: cp_model.h:547
void AddTransition(int tail, int head, int64_t transition_label)
Adds a transitions to the automaton.
Definition: cp_model.cc:266
A Boolean variable.
Definition: cp_model.h:69
BoolVar WithName(const std::string &name)
Sets the name of the variable.
Definition: cp_model.cc:34
std::string DebugString() const
Debug string.
Definition: cp_model.cc:39
BoolVar Not() const
Returns the logical negation of the current Boolean variable.
Definition: cp_model.h:80
Specialized circuit constraint.
Definition: cp_model.h:453
void AddArc(int tail, int head, BoolVar literal)
Add an arc to the circuit.
Definition: cp_model.cc:228
Constraint OnlyEnforceIf(absl::Span< const BoolVar > literals)
The constraint will be enforced iff all literals listed here are true.
Definition: cp_model.cc:216
Constraint WithName(const std::string &name)
Sets the name of the constraint.
Definition: cp_model.cc:209
const std::string & Name() const
Returns the name of the constraint (or the empty string if not set).
Definition: cp_model.cc:214
Constraint(ConstraintProto *proto)
Definition: cp_model.cc:207
Wrapper class around the cp_model proto.
Definition: cp_model.h:601
void AddHint(IntVar var, int64_t value)
Adds hinting to a variable.
Definition: cp_model.cc:796
TableConstraint AddForbiddenAssignments(absl::Span< const IntVar > vars)
Adds an forbidden assignments constraint.
Definition: cp_model.cc:586
Constraint AddLinearConstraint(const LinearExpr &expr, const Domain &domain)
Adds expr in domain.
Definition: cp_model.cc:509
void ClearAssumptions()
Remove all assumptions from the model.
Definition: cp_model.cc:816
Constraint AddAbsEquality(IntVar target, IntVar var)
Adds target == abs(var).
Definition: cp_model.cc:695
void AddAssumptions(absl::Span< const BoolVar > literals)
Adds multiple literals to the model as assumptions.
Definition: cp_model.cc:810
MultipleCircuitConstraint AddMultipleCircuitConstraint()
Adds a multiple circuit constraint, aka the "VRP" (Vehicle Routing Problem) constraint.
Definition: cp_model.cc:573
Constraint AddMinEquality(IntVar target, absl::Span< const IntVar > vars)
Adds target == min(vars).
Definition: cp_model.cc:632
BoolVar TrueVar()
Creates an always true Boolean variable.
Definition: cp_model.cc:392
IntVar NewIntVar(const Domain &domain)
Creates an integer variable with the given domain.
Definition: cp_model.cc:370
Constraint AddMaxEquality(IntVar target, absl::Span< const IntVar > vars)
Adds target == max(vars).
Definition: cp_model.cc:664
Constraint AddDivisionEquality(IntVar target, IntVar numerator, IntVar denominator)
Adds target = num / denom (integer division rounded towards 0).
Definition: cp_model.cc:685
void ClearHints()
Remove all hints.
Definition: cp_model.cc:802
void Maximize(const LinearExpr &expr)
Adds a linear maximization objective.
Definition: cp_model.cc:754
IntervalVar NewOptionalIntervalVar(IntVar start, IntVar size, IntVar end, BoolVar presence)
Creates an optional interval variable.
Definition: cp_model.cc:405
BoolVar NewBoolVar()
Creates a Boolean variable.
Definition: cp_model.cc:380
void AddDecisionStrategy(absl::Span< const IntVar > variables, DecisionStrategyProto::VariableSelectionStrategy var_strategy, DecisionStrategyProto::DomainReductionStrategy domain_strategy)
Adds a decision strategy on a list of integer variables.
Definition: cp_model.cc:772
void ScaleObjectiveBy(double scaling)
Sets scaling of the objective.
Definition: cp_model.cc:766
CircuitConstraint AddCircuitConstraint()
Adds a circuit constraint.
Definition: cp_model.cc:569
Constraint AddVariableElement(IntVar index, absl::Span< const IntVar > variables, IntVar target)
Adds the element constraint: variables[index] == target.
Definition: cp_model.cc:546
CumulativeConstraint AddCumulative(IntVar capacity)
The cumulative constraint.
Definition: cp_model.cc:736
Constraint AddGreaterThan(const LinearExpr &left, const LinearExpr &right)
Adds left > right.
Definition: cp_model.cc:489
void CopyFrom(const CpModelProto &model_proto)
Replace the current model with the one from the given proto.
Definition: cp_model.cc:820
Constraint AddLessThan(const LinearExpr &left, const LinearExpr &right)
Adds left < right.
Definition: cp_model.cc:499
Constraint AddBoolXor(absl::Span< const BoolVar > literals)
Adds the constraint that a odd number of literal is true.
Definition: cp_model.cc:434
Constraint AddElement(IntVar index, absl::Span< const int64_t > values, IntVar target)
Adds the element constraint: values[index] == target.
Definition: cp_model.cc:557
void AddAssumption(BoolVar lit)
Adds a literal to the model as assumptions.
Definition: cp_model.cc:806
void Minimize(const LinearExpr &expr)
Adds a linear minimization objective.
Definition: cp_model.cc:743
BoolVar FalseVar()
Creates an always false Boolean variable.
Definition: cp_model.cc:396
Constraint AddBoolAnd(absl::Span< const BoolVar > literals)
Adds the constraint that all literals must be true.
Definition: cp_model.cc:426
IntervalVar GetIntervalVarFromProtoIndex(int index)
Returns the interval variable from its index in the proto.
Definition: cp_model.cc:856
Constraint AddLessOrEqual(const LinearExpr &left, const LinearExpr &right)
Adds left <= right.
Definition: cp_model.cc:479
ReservoirConstraint AddReservoirConstraint(int64_t min_level, int64_t max_level)
Adds a reservoir constraint with optional refill/emptying events.
Definition: cp_model.cc:610
Constraint AddModuloEquality(IntVar target, IntVar var, IntVar mod)
Adds target = var % mod.
Definition: cp_model.cc:704
Constraint AddEquality(const LinearExpr &left, const LinearExpr &right)
Adds left == right.
Definition: cp_model.cc:459
NoOverlap2DConstraint AddNoOverlap2D()
The no_overlap_2d constraint prevents a set of boxes from overlapping.
Definition: cp_model.cc:732
Constraint AddGreaterOrEqual(const LinearExpr &left, const LinearExpr &right)
Adds left >= right.
Definition: cp_model.cc:469
Constraint AddBoolOr(absl::Span< const BoolVar > literals)
Adds the constraint that at least one of the literals must be true.
Definition: cp_model.cc:418
IntVar GetIntVarFromProtoIndex(int index)
Returns the integer variable from its index in the proto.
Definition: cp_model.cc:850
AutomatonConstraint AddAutomaton(absl::Span< const IntVar > transition_variables, int starting_state, absl::Span< const int > final_states)
An automaton constraint/.
Definition: cp_model.cc:618
Constraint AddLinMinEquality(const LinearExpr &target, absl::Span< const LinearExpr > exprs)
Adds target == min(exprs).
Definition: cp_model.cc:653
Constraint AddProductEquality(IntVar target, absl::Span< const IntVar > vars)
Adds target == prod(vars).
Definition: cp_model.cc:713
Constraint AddLinMaxEquality(const LinearExpr &target, absl::Span< const LinearExpr > exprs)
Adds target == max(exprs).
Definition: cp_model.cc:674
BoolVar GetBoolVarFromProtoIndex(int index)
Returns the Boolean variable from its index in the proto.
Definition: cp_model.cc:834
Constraint AddNotEqual(const LinearExpr &left, const LinearExpr &right)
Adds left != right.
Definition: cp_model.cc:526
Constraint AddAllDifferent(absl::Span< const IntVar > vars)
this constraint forces all variables to have different values.
Definition: cp_model.cc:538
TableConstraint AddAllowedAssignments(absl::Span< const IntVar > vars)
Adds an allowed assignments constraint.
Definition: cp_model.cc:577
IntVar NewConstant(int64_t value)
Creates a constant variable.
Definition: cp_model.cc:388
Constraint AddInverseConstraint(absl::Span< const IntVar > variables, absl::Span< const IntVar > inverse_variables)
An inverse constraint.
Definition: cp_model.cc:596
IntervalVar NewIntervalVar(IntVar start, IntVar size, IntVar end)
Creates an interval variable.
Definition: cp_model.cc:400
Constraint AddNoOverlap(absl::Span< const IntervalVar > vars)
Adds a no-overlap constraint that ensures that all present intervals do not overlap in time.
Definition: cp_model.cc:723
Specialized cumulative constraint.
Definition: cp_model.h:581
void AddDemand(IntervalVar interval, IntVar demand)
Adds a pair (interval, demand) to the constraint.
Definition: cp_model.cc:283
An integer variable.
Definition: cp_model.h:148
BoolVar ToBoolVar() const
Cast IntVar -> BoolVar.
Definition: cp_model.cc:90
std::string DebugString() const
Returns a debug string.
Definition: cp_model.cc:104
IntVar WithName(const std::string &name)
Sets the name of the variable.
Definition: cp_model.cc:80
int index() const
Returns the index of the variable in the model.
Definition: cp_model.h:193
LinearExpr AddConstant(int64_t value) const
Adds a constant value to an integer variable and returns a linear expression.
Definition: cp_model.cc:100
const IntegerVariableProto & Proto() const
Returns the underlying protobuf object (useful for testing).
Definition: cp_model.h:183
Represents a Interval variable.
Definition: cp_model.h:328
BoolVar PresenceBoolVar() const
Returns a BoolVar indicating the presence of this interval.
Definition: cp_model.cc:309
std::string Name() const
Returns the name of the interval (or the empty string if not set).
Definition: cp_model.cc:314
IntVar SizeVar() const
Returns the size variable.
Definition: cp_model.cc:303
std::string DebugString() const
Returns a debug string.
Definition: cp_model.cc:318
IntervalVar WithName(const std::string &name)
Sets the name of the variable.
Definition: cp_model.cc:294
IntVar EndVar() const
Returns the end variable.
Definition: cp_model.cc:307
const IntervalConstraintProto & Proto() const
Returns the underlying protobuf object (useful for testing).
Definition: cp_model.h:369
IntVar StartVar() const
Returns the start variable.
Definition: cp_model.cc:299
A dedicated container for linear expressions.
Definition: cp_model.h:250
static LinearExpr Sum(absl::Span< const IntVar > vars)
Constructs the sum of a list of variables.
Definition: cp_model.cc:146
static LinearExpr BooleanSum(absl::Span< const BoolVar > vars)
Constructs the sum of a list of Booleans.
Definition: cp_model.cc:170
void AddTerm(IntVar var, int64_t coeff)
Adds a term (var * coeff) to the linear expression.
Definition: cp_model.cc:195
int64_t constant() const
Returns the constant term.
Definition: cp_model.h:299
const std::vector< IntVar > & variables() const
Returns the vector of variables.
Definition: cp_model.h:293
static LinearExpr BooleanScalProd(absl::Span< const BoolVar > vars, absl::Span< const int64_t > coeffs)
Constructs the scalar product of Booleans and coefficients.
Definition: cp_model.cc:178
void AddVar(IntVar var)
Adds a single integer variable to the linear expression.
Definition: cp_model.cc:193
static LinearExpr ScalProd(absl::Span< const IntVar > vars, absl::Span< const int64_t > coeffs)
Constructs the scalar product of variables and coefficients.
Definition: cp_model.cc:154
LinearExpr & AddConstant(int64_t value)
Adds a constant value to the linear expression.
Definition: cp_model.cc:188
const std::vector< int64_t > & coefficients() const
Returns the vector of coefficients.
Definition: cp_model.h:296
static LinearExpr Term(IntVar var, int64_t coefficient)
Construncts var * coefficient.
Definition: cp_model.cc:164
void AddArc(int tail, int head, BoolVar literal)
Add an arc to the circuit.
Definition: cp_model.cc:234
Specialized no_overlap2D constraint.
Definition: cp_model.h:564
void AddRectangle(IntervalVar x_coordinate, IntervalVar y_coordinate)
Adds a rectangle (parallel to the axis) to the constraint.
Definition: cp_model.cc:273
Specialized reservoir constraint.
Definition: cp_model.h:516
void AddEvent(IntVar time, int64_t demand)
Adds a mandatory event.
Definition: cp_model.cc:251
void AddOptionalEvent(IntVar time, int64_t demand, BoolVar is_active)
Adds a optional event.
Definition: cp_model.cc:258
Specialized assignment constraint.
Definition: cp_model.h:499
void AddTuple(absl::Span< const int64_t > tuple)
Adds a tuple of possible values to the constraint.
Definition: cp_model.cc:240
This file implements a wrapper around the CP-SAT model proto.
CpModelProto proto
CpModelProto const * model_proto
const std::string name
const Constraint * ct
int64_t value
IntVar * var
Definition: expr_array.cc:1874
bool ContainsKey(const Collection &collection, const Key &key)
Definition: map_util.h:200
std::ostream & operator<<(std::ostream &os, const BoolVar &var)
Definition: cp_model.cc:68
bool RefIsPositive(int ref)
int64_t SolutionIntegerMax(const CpSolverResponse &r, IntVar x)
Returns the max of an integer variable in a solution.
Definition: cp_model.cc:883
BoolVar Not(BoolVar x)
A convenient wrapper so we can write Not(x) instead of x.Not() which is sometimes clearer.
Definition: cp_model.cc:66
bool SolutionBooleanValue(const CpSolverResponse &r, BoolVar x)
Evaluates the value of a Boolean literal in a solver response.
Definition: cp_model.cc:891
int64_t SolutionIntegerValue(const CpSolverResponse &r, const LinearExpr &expr)
Evaluates the value of an linear expression in a solver response.
Definition: cp_model.cc:866
int64_t SolutionIntegerMin(const CpSolverResponse &r, IntVar x)
Returns the min of an integer variable in a solution.
Definition: cp_model.cc:875
Collection of objects used to extend the Constraint Solver library.
Literal literal
Definition: optimization.cc:85
int index
Definition: pack.cc:509
int64_t demand
Definition: resource.cc:125
int64_t time
Definition: resource.cc:1691
IntervalVar * interval
Definition: resource.cc:100
int64_t coefficient
int64_t capacity
int64_t tail
int64_t head