Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
cp_model.cc
Go to the documentation of this file.
1// Copyright 2010-2025 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 <cstdint>
17#include <initializer_list>
18#include <limits>
19#include <ostream>
20#include <string>
21#include <vector>
22
23#include "absl/container/flat_hash_map.h"
24#include "absl/log/check.h"
25#include "absl/strings/str_cat.h"
26#include "absl/strings/str_format.h"
27#include "absl/strings/string_view.h"
28#include "absl/types/span.h"
32
33namespace operations_research {
34namespace sat {
35
36BoolVar::BoolVar(int index, CpModelBuilder* builder)
37 : builder_(builder), index_(index) {}
38
39BoolVar BoolVar::WithName(absl::string_view name) {
40 DCHECK(builder_ != nullptr);
41 if (builder_ == nullptr) return *this;
42 builder_->MutableProto()
43 ->mutable_variables(PositiveRef(index_))
44 ->set_name(name);
45 return *this;
46}
47
48std::string BoolVar::Name() const {
49 if (builder_ == nullptr) return "null";
50 absl::string_view name =
51 builder_->Proto().variables(PositiveRef(index_)).name();
52 if (RefIsPositive(index_)) {
53 return std::string(name);
54 } else {
55 return absl::StrCat("Not(", name, ")");
56 }
57}
58
59std::string BoolVar::DebugString() const {
60 if (builder_ == nullptr) return "null";
61 if (index_ < 0) {
62 return absl::StrFormat("Not(%s)", Not().DebugString());
63 } else {
64 std::string output;
65 const IntegerVariableProto& var_proto = builder_->Proto().variables(index_);
66 // Special case for constant variables without names.
67 if (var_proto.name().empty() && var_proto.domain_size() == 2 &&
68 var_proto.domain(0) == var_proto.domain(1)) {
69 output.append(var_proto.domain(0) == 0 ? "false" : "true");
70 } else {
71 if (var_proto.name().empty()) {
72 absl::StrAppendFormat(&output, "BoolVar%i(", index_);
73 } else {
74 absl::StrAppendFormat(&output, "%s(", var_proto.name());
75 }
76 if (var_proto.domain(0) == var_proto.domain(1)) {
77 output.append(var_proto.domain(0) == 0 ? "false)" : "true)");
78 } else {
79 absl::StrAppend(&output, var_proto.domain(0), ", ", var_proto.domain(1),
80 ")");
81 }
82 }
83 return output;
84 }
85}
86
87BoolVar Not(BoolVar x) { return x.Not(); }
88
89std::ostream& operator<<(std::ostream& os, const BoolVar& var) {
90 os << var.DebugString();
91 return os;
92}
93
94IntVar::IntVar(int index, CpModelBuilder* builder)
95 : builder_(builder), index_(index) {
96 DCHECK(RefIsPositive(index_));
97}
98
100 if (var.builder_ == nullptr) {
101 *this = IntVar();
102 return;
103 }
104 builder_ = var.builder_;
105 index_ = builder_->GetOrCreateIntegerIndex(var.index_);
106 DCHECK(RefIsPositive(index_));
107}
108
110 if (builder_ != nullptr) {
111 const IntegerVariableProto& proto = builder_->Proto().variables(index_);
112 DCHECK_EQ(2, proto.domain_size());
113 DCHECK_GE(proto.domain(0), 0);
114 DCHECK_LE(proto.domain(1), 1);
115 }
116 return BoolVar(index_, builder_);
117}
118
119IntVar IntVar::WithName(absl::string_view name) {
120 DCHECK(builder_ != nullptr);
121 if (builder_ == nullptr) return *this;
122 builder_->MutableProto()->mutable_variables(index_)->set_name(name);
123 return *this;
124}
125
126std::string IntVar::Name() const {
127 if (builder_ == nullptr) return "null";
128 return builder_->Proto().variables(index_).name();
129}
130
132 if (builder_ == nullptr) return Domain();
133 return ReadDomainFromProto(builder_->Proto().variables(index_));
134}
135
136std::string IntVar::DebugString() const {
137 if (builder_ == nullptr) return "null";
138 return VarDebugString(builder_->Proto(), index_);
139}
140
141// TODO(user): unfortunately, we need this indirection to get a DebugString()
142// in a const way from an index. Because building an IntVar is non-const.
143std::string VarDebugString(const CpModelProto& proto, int index) {
144 std::string output;
145
146 // Special case for constant variables without names.
147 const IntegerVariableProto& var_proto = proto.variables(index);
148 if (var_proto.name().empty() && var_proto.domain_size() == 2 &&
149 var_proto.domain(0) == var_proto.domain(1)) {
150 absl::StrAppend(&output, var_proto.domain(0));
151 } else {
152 if (var_proto.name().empty()) {
153 absl::StrAppend(&output, "V", index, "(");
154 } else {
155 absl::StrAppend(&output, var_proto.name(), "(");
156 }
157
158 // TODO(user): Use domain pretty print function.
159 if (var_proto.domain_size() == 2 &&
160 var_proto.domain(0) == var_proto.domain(1)) {
161 absl::StrAppend(&output, var_proto.domain(0), ")");
162 } else {
163 absl::StrAppend(&output, var_proto.domain(0), ", ", var_proto.domain(1),
164 ")");
165 }
166 }
167
168 return output;
169}
170
171std::ostream& operator<<(std::ostream& os, const IntVar& var) {
172 os << var.DebugString();
173 return os;
174}
175
177 DCHECK(var.builder_ != nullptr);
178 const int index = var.index_;
179 if (RefIsPositive(index)) {
180 variables_.push_back(index);
181 coefficients_.push_back(1);
182 } else {
183 // We add 1 - var instead.
184 variables_.push_back(PositiveRef(index));
185 coefficients_.push_back(-1);
186 constant_ += 1;
187 }
188}
189
191 DCHECK(var.builder_ != nullptr);
192 variables_.push_back(var.index_);
193 coefficients_.push_back(1);
194}
195
196LinearExpr::LinearExpr(int64_t constant) { constant_ = constant; }
197
199 LinearExpr result(expr_proto.offset());
200 for (int i = 0; i < expr_proto.vars_size(); ++i) {
201 result.variables_.push_back(expr_proto.vars(i));
202 result.coefficients_.push_back(expr_proto.coeffs(i));
203 }
204 return result;
205}
206
207LinearExpr LinearExpr::Sum(absl::Span<const IntVar> vars) {
208 LinearExpr result;
209 for (const IntVar& var : vars) {
210 result += var;
211 }
212 return result;
213}
214
215LinearExpr LinearExpr::Sum(absl::Span<const BoolVar> vars) {
216 LinearExpr result;
217 for (const BoolVar& var : vars) {
218 result += var;
219 }
220 return result;
221}
222
223LinearExpr LinearExpr::WeightedSum(absl::Span<const IntVar> vars,
224 absl::Span<const int64_t> coeffs) {
225 CHECK_EQ(vars.size(), coeffs.size());
226 LinearExpr result;
227 for (int i = 0; i < vars.size(); ++i) {
228 result += vars[i] * coeffs[i];
229 }
230 return result;
231}
232
233LinearExpr LinearExpr::WeightedSum(absl::Span<const BoolVar> vars,
234 absl::Span<const int64_t> coeffs) {
235 CHECK_EQ(vars.size(), coeffs.size());
236 LinearExpr result;
237 for (int i = 0; i < vars.size(); ++i) {
238 result += vars[i] * coeffs[i];
239 }
240 return result;
241}
242
243LinearExpr LinearExpr::Term(IntVar var, int64_t coefficient) {
244 LinearExpr result;
245 result += var * coefficient;
246 return result;
247}
248
249LinearExpr LinearExpr::Term(BoolVar var, int64_t coefficient) {
250 LinearExpr result;
251 result += var * coefficient;
252 return result;
253}
254
256 constant_ += other.constant_;
257 variables_.insert(variables_.end(), other.variables_.begin(),
258 other.variables_.end());
259 coefficients_.insert(coefficients_.end(), other.coefficients_.begin(),
260 other.coefficients_.end());
261 return *this;
262}
263
265 constant_ -= other.constant_;
266 variables_.insert(variables_.end(), other.variables_.begin(),
267 other.variables_.end());
268 for (const int64_t coeff : other.coefficients_) {
269 coefficients_.push_back(-coeff);
270 }
271 return *this;
272}
273
275 constant_ *= factor;
276 for (int64_t& coeff : coefficients_) coeff *= factor;
277 return *this;
278}
279
280std::string LinearExpr::DebugString(const CpModelProto* proto) const {
281 std::string result;
282 for (int i = 0; i < variables_.size(); ++i) {
283 const int64_t coeff = coefficients_[i];
284 const std::string var_string = proto == nullptr
285 ? absl::StrCat("V", variables_[i])
286 : VarDebugString(*proto, variables_[i]);
287 if (i == 0) {
288 if (coeff == 1) {
289 absl::StrAppend(&result, var_string);
290 } else if (coeff == -1) {
291 absl::StrAppend(&result, "-", var_string);
292 } else if (coeff != 0) {
293 absl::StrAppend(&result, coeff, " * ", var_string);
294 }
295 } else if (coeff == 1) {
296 absl::StrAppend(&result, " + ", var_string);
297 } else if (coeff > 0) {
298 absl::StrAppend(&result, " + ", coeff, " * ", var_string);
299 } else if (coeff == -1) {
300 absl::StrAppend(&result, " - ", var_string);
301 } else if (coeff < 0) {
302 absl::StrAppend(&result, " - ", -coeff, " * ", var_string);
303 }
304 }
305
306 if (constant_ != 0) {
307 if (variables_.empty()) {
308 return absl::StrCat(constant_);
309 } else if (constant_ > 0) {
310 absl::StrAppend(&result, " + ", constant_);
311 } else {
312 absl::StrAppend(&result, " - ", -constant_);
313 }
314 }
315 return result;
316}
317
318std::ostream& operator<<(std::ostream& os, const LinearExpr& e) {
319 os << e.DebugString();
320 return os;
321}
322
323DoubleLinearExpr::DoubleLinearExpr() = default;
324
326
328
330
331DoubleLinearExpr DoubleLinearExpr::Sum(absl::Span<const IntVar> vars) {
332 DoubleLinearExpr result;
333 for (const IntVar& var : vars) {
334 result.AddTerm(var, 1.0);
335 }
336 return result;
337}
338
339DoubleLinearExpr DoubleLinearExpr::Sum(absl::Span<const BoolVar> vars) {
340 DoubleLinearExpr result;
341 for (const BoolVar& var : vars) {
342 result.AddTerm(var, 1.0);
343 }
344 return result;
345}
346
348 absl::Span<const IntVar> vars, absl::Span<const double> coeffs) {
349 CHECK_EQ(vars.size(), coeffs.size());
350 DoubleLinearExpr result;
351 for (int i = 0; i < vars.size(); ++i) {
352 result.AddTerm(vars[i], coeffs[i]);
353 }
354 return result;
355}
356
358 absl::Span<const BoolVar> vars, absl::Span<const double> coeffs) {
359 CHECK_EQ(vars.size(), coeffs.size());
360 DoubleLinearExpr result;
361 for (int i = 0; i < vars.size(); ++i) {
362 result.AddTerm(vars[i], coeffs[i]);
363 }
364 return result;
365}
366
368 constant_ += value;
369 return *this;
370}
371
373 AddTerm(var, 1);
374 return *this;
375}
376
378 AddTerm(var, 1);
379 return *this;
380}
381
383 constant_ += expr.constant_;
384 variables_.insert(variables_.end(), expr.variables_.begin(),
385 expr.variables_.end());
386 coefficients_.insert(coefficients_.end(), expr.coefficients_.begin(),
387 expr.coefficients_.end());
388 return *this;
389}
390
392 variables_.push_back(var.index_);
393 coefficients_.push_back(coeff);
394 return *this;
395}
396
398 const int index = var.index_;
399 if (RefIsPositive(index)) {
400 variables_.push_back(index);
401 coefficients_.push_back(coeff);
402 } else {
403 variables_.push_back(PositiveRef(index));
404 coefficients_.push_back(-coeff);
405 constant_ += coeff;
406 }
407 return *this;
408}
409
411 double coeff) {
412 const std::vector<int>& indices = expr.variables();
413 const std::vector<int64_t> coefficients = expr.coefficients();
414 for (int i = 0; i < indices.size(); ++i) {
415 variables_.push_back(indices[i]);
416 coefficients_.push_back(static_cast<double>(coefficients[i]) * coeff);
417 }
418 constant_ += static_cast<double>(expr.constant()) * coeff;
419
420 return *this;
421}
422
424 constant_ -= value;
425 return *this;
426}
427
429 AddTerm(var, -1.0);
430 return *this;
431}
432
434 constant_ -= expr.constant_;
435 variables_.insert(variables_.end(), expr.variables_.begin(),
436 expr.variables_.end());
437 for (const double coeff : expr.coefficients()) {
438 coefficients_.push_back(-coeff);
439 }
440 return *this;
441}
442
444 constant_ *= coeff;
445 for (double& c : coefficients_) {
446 c *= coeff;
447 }
448 return *this;
449}
450
451std::string DoubleLinearExpr::DebugString(const CpModelProto* proto) const {
452 std::string result;
453 for (int i = 0; i < variables_.size(); ++i) {
454 const double coeff = coefficients_[i];
455 const std::string var_string = proto == nullptr
456 ? absl::StrCat("V", variables_[i])
457 : VarDebugString(*proto, variables_[i]);
458 if (i == 0) {
459 if (coeff == 1.0) {
460 absl::StrAppend(&result, var_string);
461 } else if (coeff == -1.0) {
462 absl::StrAppend(&result, "-", var_string);
463 } else if (coeff != 0.0) {
464 absl::StrAppend(&result, coeff, " * ", var_string);
465 }
466 } else if (coeff == 1.0) {
467 absl::StrAppend(&result, " + ", var_string);
468 } else if (coeff > 0.0) {
469 absl::StrAppend(&result, " + ", coeff, " * ", var_string);
470 } else if (coeff == -1.0) {
471 absl::StrAppend(&result, " - ", var_string);
472 } else if (coeff < 0.0) {
473 absl::StrAppend(&result, " - ", -coeff, " * ", var_string);
474 }
475 }
476
477 if (constant_ != 0.0) {
478 if (variables_.empty()) {
479 return absl::StrCat(constant_);
480 } else if (constant_ > 0.0) {
481 absl::StrAppend(&result, " + ", constant_);
482 } else {
483 absl::StrAppend(&result, " - ", -constant_);
484 }
485 }
486 return result;
487}
488
489std::ostream& operator<<(std::ostream& os, const DoubleLinearExpr& e) {
490 os << e.DebugString();
491 return os;
492}
493
495
496Constraint Constraint::WithName(absl::string_view name) {
497 proto_->set_name(name);
498 return *this;
499}
500
501absl::string_view Constraint::Name() const { return proto_->name(); }
502
503Constraint Constraint::OnlyEnforceIf(absl::Span<const BoolVar> literals) {
504 for (const BoolVar& var : literals) {
505 proto_->add_enforcement_literal(var.index_);
506 }
507 return *this;
508}
509
511 proto_->add_enforcement_literal(literal.index_);
512 return *this;
513}
514
515void CircuitConstraint::AddArc(int tail, int head, BoolVar literal) {
516 proto_->mutable_circuit()->add_tails(tail);
517 proto_->mutable_circuit()->add_heads(head);
518 proto_->mutable_circuit()->add_literals(literal.index_);
519}
520
521void MultipleCircuitConstraint::AddArc(int tail, int head, BoolVar literal) {
522 proto_->mutable_routes()->add_tails(tail);
523 proto_->mutable_routes()->add_heads(head);
524 proto_->mutable_routes()->add_literals(literal.index_);
525}
526
527void TableConstraint::AddTuple(absl::Span<const int64_t> tuple) {
528 CHECK_EQ(tuple.size(), proto_->table().exprs_size());
529 for (const int64_t t : tuple) {
530 proto_->mutable_table()->add_values(t);
531 }
532}
533
534ReservoirConstraint::ReservoirConstraint(ConstraintProto* proto,
535 CpModelBuilder* builder)
536 : Constraint(proto), builder_(builder) {}
537
538void ReservoirConstraint::AddEvent(LinearExpr time, int64_t level_change) {
539 *proto_->mutable_reservoir()->add_time_exprs() =
540 builder_->LinearExprToProto(time);
541 proto_->mutable_reservoir()->add_level_changes()->set_offset(level_change);
542 proto_->mutable_reservoir()->add_active_literals(
543 builder_->IndexFromConstant(1));
544}
545
546void ReservoirConstraint::AddOptionalEvent(LinearExpr time,
547 int64_t level_change,
548 BoolVar is_active) {
550 builder_->LinearExprToProto(time);
552 proto_->mutable_reservoir()->add_active_literals(is_active.index_);
553}
554
556 int64_t transition_label) {
557 proto_->mutable_automaton()->add_transition_tail(tail);
558 proto_->mutable_automaton()->add_transition_head(head);
559 proto_->mutable_automaton()->add_transition_label(transition_label);
560}
561
562void NoOverlap2DConstraint::AddRectangle(IntervalVar x_coordinate,
563 IntervalVar y_coordinate) {
564 proto_->mutable_no_overlap_2d()->add_x_intervals(x_coordinate.index_);
566}
567
568CumulativeConstraint::CumulativeConstraint(ConstraintProto* proto,
569 CpModelBuilder* builder)
570 : Constraint(proto), builder_(builder) {}
571
572void CumulativeConstraint::AddDemand(IntervalVar interval, LinearExpr demand) {
573 proto_->mutable_cumulative()->add_intervals(interval.index_);
575 builder_->LinearExprToProto(demand);
576}
577
578IntervalVar::IntervalVar() : builder_(nullptr), index_() {}
579
580IntervalVar::IntervalVar(int index, CpModelBuilder* builder)
581 : builder_(builder), index_(index) {}
582
583IntervalVar IntervalVar::WithName(absl::string_view name) {
584 DCHECK(builder_ != nullptr);
585 if (builder_ == nullptr) return *this;
586 builder_->MutableProto()->mutable_constraints(index_)->set_name(name);
587 return *this;
588}
589
591 DCHECK(builder_ != nullptr);
592 if (builder_ == nullptr) return LinearExpr();
594 builder_->Proto().constraints(index_).interval().start());
595}
596
598 DCHECK(builder_ != nullptr);
599 if (builder_ == nullptr) return LinearExpr();
601 builder_->Proto().constraints(index_).interval().size());
602}
603
605 DCHECK(builder_ != nullptr);
606 if (builder_ == nullptr) return LinearExpr();
608 builder_->Proto().constraints(index_).interval().end());
609}
610
612 DCHECK(builder_ != nullptr);
613 if (builder_ == nullptr) return BoolVar();
614 if (builder_->Proto().constraints(index_).enforcement_literal_size() == 0) {
615 return builder_->TrueVar();
616 }
617 return BoolVar(builder_->Proto().constraints(index_).enforcement_literal(0),
618 builder_);
619}
620
621std::string IntervalVar::Name() const {
622 if (builder_ == nullptr) return "null";
623 return builder_->Proto().constraints(index_).name();
624}
625
626std::string IntervalVar::DebugString() const {
627 if (builder_ == nullptr) return "null";
628
629 CHECK_GE(index_, 0);
630 const CpModelProto& proto = builder_->Proto();
631 const ConstraintProto& ct_proto = proto.constraints(index_);
632 std::string output;
633 if (ct_proto.name().empty()) {
634 absl::StrAppend(&output, "IntervalVar", index_, "(");
635 } else {
636 absl::StrAppend(&output, ct_proto.name(), "(");
637 }
638 absl::StrAppend(&output, StartExpr().DebugString(&proto), ", ",
639 SizeExpr().DebugString(&proto), ", ",
640 EndExpr().DebugString(&proto), ", ",
642 return output;
643}
644
645std::ostream& operator<<(std::ostream& os, const IntervalVar& var) {
646 os << var.DebugString();
647 return os;
648}
649
650void CpModelBuilder::SetName(absl::string_view name) {
651 cp_model_.set_name(name);
652}
653
654int CpModelBuilder::IndexFromConstant(int64_t value) {
655 if (!constant_to_index_map_.contains(value)) {
656 const int index = cp_model_.variables_size();
657 IntegerVariableProto* const var_proto = cp_model_.add_variables();
658 var_proto->add_domain(value);
659 var_proto->add_domain(value);
660 constant_to_index_map_[value] = index;
661 }
662 return constant_to_index_map_[value];
663}
664
665int CpModelBuilder::GetOrCreateIntegerIndex(int index) {
666 if (index >= 0) {
667 return index;
668 }
669 if (!bool_to_integer_index_map_.contains(index)) {
670 const int var = PositiveRef(index);
671 const IntegerVariableProto& old_var = cp_model_.variables(var);
672 const int new_index = cp_model_.variables_size();
673 IntegerVariableProto* const new_var = cp_model_.add_variables();
674 new_var->add_domain(0);
675 new_var->add_domain(1);
676 if (!old_var.name().empty()) {
677 new_var->set_name(absl::StrCat("Not(", old_var.name(), ")"));
678 }
679 AddEquality(IntVar(new_index, this), BoolVar(index, this));
680 bool_to_integer_index_map_[index] = new_index;
681 return new_index;
682 }
683 return bool_to_integer_index_map_[index];
684}
685
687 const int index = cp_model_.variables_size();
688 IntegerVariableProto* const var_proto = cp_model_.add_variables();
689 for (const auto& interval : domain) {
690 var_proto->add_domain(interval.start);
691 var_proto->add_domain(interval.end);
692 }
693 return IntVar(index, this);
694}
695
697 const int index = cp_model_.variables_size();
698 IntegerVariableProto* const var_proto = cp_model_.add_variables();
699 var_proto->add_domain(0);
700 var_proto->add_domain(1);
701 return BoolVar(index, this);
702}
703
704IntVar CpModelBuilder::NewConstant(int64_t value) {
705 return IntVar(IndexFromConstant(value), this);
706}
707
709 return BoolVar(IndexFromConstant(1), this);
710}
711
713 return BoolVar(IndexFromConstant(0), this);
714}
715
717 const LinearExpr& size,
718 const LinearExpr& end) {
719 const int index = cp_model_.constraints_size();
720 ConstraintProto* const ct = cp_model_.add_constraints();
721 IntervalConstraintProto* const interval = ct->mutable_interval();
722 *interval->mutable_start() = LinearExprToProto(start);
723 *interval->mutable_size() = LinearExprToProto(size);
724 *interval->mutable_end() = LinearExprToProto(end);
725 return IntervalVar(index, this);
726}
727
729 int64_t size) {
730 const int index = cp_model_.constraints_size();
731 ConstraintProto* const ct = cp_model_.add_constraints();
732 IntervalConstraintProto* const interval = ct->mutable_interval();
733 *interval->mutable_start() = LinearExprToProto(start);
734 interval->mutable_size()->set_offset(size);
735 *interval->mutable_end() = LinearExprToProto(start);
736 interval->mutable_end()->set_offset(interval->end().offset() + size);
737 return IntervalVar(index, this);
738}
739
741 const LinearExpr& size,
742 const LinearExpr& end,
743 BoolVar presence) {
744 const int index = cp_model_.constraints_size();
745 ConstraintProto* const ct = cp_model_.add_constraints();
746 ct->add_enforcement_literal(presence.index_);
747 IntervalConstraintProto* const interval = ct->mutable_interval();
748 *interval->mutable_start() = LinearExprToProto(start);
749 *interval->mutable_size() = LinearExprToProto(size);
750 *interval->mutable_end() = LinearExprToProto(end);
751 return IntervalVar(index, this);
752}
753
755 const LinearExpr& start, int64_t size, BoolVar presence) {
756 const int index = cp_model_.constraints_size();
757 ConstraintProto* const ct = cp_model_.add_constraints();
758 ct->add_enforcement_literal(presence.index_);
759 IntervalConstraintProto* const interval = ct->mutable_interval();
760 *interval->mutable_start() = LinearExprToProto(start);
761 interval->mutable_size()->set_offset(size);
762 *interval->mutable_end() = LinearExprToProto(start);
763 interval->mutable_end()->set_offset(interval->end().offset() + size);
764 return IntervalVar(index, this);
765}
766
768 FillDomainInProto(Domain(value), cp_model_.mutable_variables(var.index()));
769}
770
771void CpModelBuilder::FixVariable(BoolVar var, bool value) {
772 const int index = var.index();
773 if (RefIsPositive(index)) {
774 FillDomainInProto(Domain(value), cp_model_.mutable_variables(index));
775 } else {
777 cp_model_.mutable_variables(NegatedRef(index)));
778 }
779}
780
781Constraint CpModelBuilder::AddBoolOr(absl::Span<const BoolVar> literals) {
782 ConstraintProto* const proto = cp_model_.add_constraints();
783 BoolArgumentProto* const bool_or = proto->mutable_bool_or();
784 for (const BoolVar& lit : literals) bool_or->add_literals(lit.index_);
785 return Constraint(proto);
786}
787
788Constraint CpModelBuilder::AddAtLeastOne(absl::Span<const BoolVar> literals) {
789 return AddBoolOr(literals);
790}
791
792Constraint CpModelBuilder::AddAtMostOne(absl::Span<const BoolVar> literals) {
793 ConstraintProto* const proto = cp_model_.add_constraints();
794 for (const BoolVar& lit : literals) {
795 proto->mutable_at_most_one()->add_literals(lit.index_);
796 }
797 return Constraint(proto);
798}
799
800Constraint CpModelBuilder::AddExactlyOne(absl::Span<const BoolVar> literals) {
801 ConstraintProto* const proto = cp_model_.add_constraints();
802 BoolArgumentProto* const exactly_one = proto->mutable_exactly_one();
803 for (const BoolVar& lit : literals) exactly_one->add_literals(lit.index_);
804 return Constraint(proto);
805}
806
807Constraint CpModelBuilder::AddBoolAnd(absl::Span<const BoolVar> literals) {
808 ConstraintProto* const proto = cp_model_.add_constraints();
809 for (const BoolVar& lit : literals) {
810 proto->mutable_bool_and()->add_literals(lit.index_);
811 }
812 return Constraint(proto);
813}
814
815Constraint CpModelBuilder::AddBoolXor(absl::Span<const BoolVar> literals) {
816 ConstraintProto* const proto = cp_model_.add_constraints();
817 for (const BoolVar& lit : literals) {
818 proto->mutable_bool_xor()->add_literals(lit.index_);
819 }
820 return Constraint(proto);
821}
822
823void CpModelBuilder::FillLinearTerms(const LinearExpr& left,
824 const LinearExpr& right,
825 LinearConstraintProto* proto) {
826 for (const int x : left.variables()) {
827 proto->add_vars(x);
828 }
829 for (const int64_t coeff : left.coefficients()) {
830 proto->add_coeffs(coeff);
831 }
832 for (const int x : right.variables()) {
833 proto->add_vars(x);
834 }
835 for (const int64_t coeff : right.coefficients()) {
836 proto->add_coeffs(-coeff);
837 }
838}
839
841 const LinearExpr& right) {
842 ConstraintProto* const proto = cp_model_.add_constraints();
843 FillLinearTerms(left, right, proto->mutable_linear());
844 const int64_t rhs = right.constant() - left.constant();
845 proto->mutable_linear()->add_domain(rhs);
846 proto->mutable_linear()->add_domain(rhs);
847 return Constraint(proto);
848}
849
850Constraint CpModelBuilder::AddGreaterOrEqual(const LinearExpr& left,
851 const LinearExpr& right) {
852 ConstraintProto* const proto = cp_model_.add_constraints();
853 FillLinearTerms(left, right, proto->mutable_linear());
854 const int64_t rhs = right.constant() - left.constant();
855 proto->mutable_linear()->add_domain(rhs);
856 proto->mutable_linear()->add_domain(std::numeric_limits<int64_t>::max());
857 return Constraint(proto);
858}
859
860Constraint CpModelBuilder::AddLessOrEqual(const LinearExpr& left,
861 const LinearExpr& right) {
862 ConstraintProto* const proto = cp_model_.add_constraints();
863 FillLinearTerms(left, right, proto->mutable_linear());
864 const int64_t rhs = right.constant() - left.constant();
865 proto->mutable_linear()->add_domain(std::numeric_limits<int64_t>::min());
866 proto->mutable_linear()->add_domain(rhs);
867 return Constraint(proto);
868}
869
871 const LinearExpr& right) {
872 ConstraintProto* const proto = cp_model_.add_constraints();
873 FillLinearTerms(left, right, proto->mutable_linear());
874 const int64_t rhs = right.constant() - left.constant();
875 proto->mutable_linear()->add_domain(rhs + 1);
876 proto->mutable_linear()->add_domain(std::numeric_limits<int64_t>::max());
877 return Constraint(proto);
878}
879
880Constraint CpModelBuilder::AddLessThan(const LinearExpr& left,
881 const LinearExpr& right) {
882 ConstraintProto* const proto = cp_model_.add_constraints();
883 FillLinearTerms(left, right, proto->mutable_linear());
884 const int64_t rhs = right.constant() - left.constant();
885 proto->mutable_linear()->add_domain(std::numeric_limits<int64_t>::min());
886 proto->mutable_linear()->add_domain(rhs - 1);
887 return Constraint(proto);
888}
889
890Constraint CpModelBuilder::AddLinearConstraint(const LinearExpr& expr,
891 const Domain& domain) {
892 ConstraintProto* const proto = cp_model_.add_constraints();
893 for (const int x : expr.variables()) {
894 proto->mutable_linear()->add_vars(x);
895 }
896 for (const int64_t coeff : expr.coefficients()) {
897 proto->mutable_linear()->add_coeffs(coeff);
898 }
899 const int64_t cst = expr.constant();
900 for (const auto& i : domain) {
901 proto->mutable_linear()->add_domain(i.start - cst);
902 proto->mutable_linear()->add_domain(i.end - cst);
903 }
904 return Constraint(proto);
905}
906
907Constraint CpModelBuilder::AddNotEqual(const LinearExpr& left,
908 const LinearExpr& right) {
909 ConstraintProto* const proto = cp_model_.add_constraints();
910 FillLinearTerms(left, right, proto->mutable_linear());
911 const int64_t rhs = right.constant() - left.constant();
912 proto->mutable_linear()->add_domain(std::numeric_limits<int64_t>::min());
913 proto->mutable_linear()->add_domain(rhs - 1);
914 proto->mutable_linear()->add_domain(rhs + 1);
915 proto->mutable_linear()->add_domain(std::numeric_limits<int64_t>::max());
916 return Constraint(proto);
917}
918
919Constraint CpModelBuilder::AddAllDifferent(absl::Span<const IntVar> vars) {
920 ConstraintProto* const proto = cp_model_.add_constraints();
921 for (const IntVar& var : vars) {
922 auto* expr = proto->mutable_all_diff()->add_exprs();
923 expr->add_vars(var.index_);
924 expr->add_coeffs(1);
925 }
926 return Constraint(proto);
927}
928
929Constraint CpModelBuilder::AddAllDifferent(absl::Span<const LinearExpr> exprs) {
930 ConstraintProto* const proto = cp_model_.add_constraints();
931 for (const LinearExpr& expr : exprs) {
932 *proto->mutable_all_diff()->add_exprs() = LinearExprToProto(expr);
933 }
934 return Constraint(proto);
935}
936
937Constraint CpModelBuilder::AddAllDifferent(
938 std::initializer_list<LinearExpr> exprs) {
939 ConstraintProto* const proto = cp_model_.add_constraints();
940 for (const LinearExpr& expr : exprs) {
941 *proto->mutable_all_diff()->add_exprs() = LinearExprToProto(expr);
942 }
943 return Constraint(proto);
944}
945
946Constraint CpModelBuilder::AddVariableElement(
947 LinearExpr index, absl::Span<const IntVar> variables, LinearExpr target) {
948 ConstraintProto* const proto = cp_model_.add_constraints();
949 *proto->mutable_element()->mutable_linear_index() = LinearExprToProto(index);
950 *proto->mutable_element()->mutable_linear_target() =
951 LinearExprToProto(target);
952 for (const IntVar& var : variables) {
953 *proto->mutable_element()->add_exprs() = LinearExprToProto(var);
954 }
955 return Constraint(proto);
956}
957
958Constraint CpModelBuilder::AddElement(LinearExpr index,
959 absl::Span<const int64_t> values,
960 LinearExpr target) {
961 ConstraintProto* const proto = cp_model_.add_constraints();
962 *proto->mutable_element()->mutable_linear_index() = LinearExprToProto(index);
963 *proto->mutable_element()->mutable_linear_target() =
964 LinearExprToProto(target);
965 for (int64_t value : values) {
966 proto->mutable_element()->add_exprs()->set_offset(value);
967 }
968 return Constraint(proto);
969}
970
971Constraint CpModelBuilder::AddElement(LinearExpr index,
972 absl::Span<const LinearExpr> expressions,
973 LinearExpr target) {
974 ConstraintProto* const proto = cp_model_.add_constraints();
975 *proto->mutable_element()->mutable_linear_index() = LinearExprToProto(index);
976 *proto->mutable_element()->mutable_linear_target() =
977 LinearExprToProto(target);
978 for (const LinearExpr& expr : expressions) {
979 *proto->mutable_element()->add_exprs() = LinearExprToProto(expr);
980 }
981 return Constraint(proto);
982}
983
984Constraint CpModelBuilder::AddElement(
985 LinearExpr index, std::initializer_list<LinearExpr> expressions,
986 LinearExpr target) {
987 ConstraintProto* const proto = cp_model_.add_constraints();
988 *proto->mutable_element()->mutable_linear_index() = LinearExprToProto(index);
989 *proto->mutable_element()->mutable_linear_target() =
990 LinearExprToProto(target);
991 for (const LinearExpr& expr : expressions) {
992 *proto->mutable_element()->add_exprs() = LinearExprToProto(expr);
993 }
994 return Constraint(proto);
995}
996
997CircuitConstraint CpModelBuilder::AddCircuitConstraint() {
998 return CircuitConstraint(cp_model_.add_constraints());
999}
1000
1001MultipleCircuitConstraint CpModelBuilder::AddMultipleCircuitConstraint() {
1002 return MultipleCircuitConstraint(cp_model_.add_constraints());
1003}
1004
1005TableConstraint CpModelBuilder::AddAllowedAssignments(
1006 absl::Span<const LinearExpr> expressions) {
1007 ConstraintProto* const proto = cp_model_.add_constraints();
1008 for (const LinearExpr& expr : expressions) {
1009 *proto->mutable_table()->add_exprs() = LinearExprToProto(expr);
1010 }
1011 return TableConstraint(proto);
1012}
1013
1014TableConstraint CpModelBuilder::AddAllowedAssignments(
1015 absl::Span<const IntVar> variables) {
1016 ConstraintProto* const proto = cp_model_.add_constraints();
1017 for (const IntVar var : variables) {
1018 LinearExpressionProto* expr = proto->mutable_table()->add_exprs();
1019 expr->add_vars(var.index_);
1020 expr->add_coeffs(1);
1021 }
1022 return TableConstraint(proto);
1023}
1024
1025TableConstraint CpModelBuilder::AddAllowedAssignments(
1026 std::initializer_list<LinearExpr> expressions) {
1027 ConstraintProto* const proto = cp_model_.add_constraints();
1028 for (const LinearExpr& expr : expressions) {
1029 *proto->mutable_table()->add_exprs() = LinearExprToProto(expr);
1030 }
1031 return TableConstraint(proto);
1032}
1033
1034TableConstraint CpModelBuilder::AddForbiddenAssignments(
1035 absl::Span<const LinearExpr> expressions) {
1036 TableConstraint ct = AddAllowedAssignments(expressions);
1037 ct.MutableProto()->mutable_table()->set_negated(true);
1038 return ct;
1039}
1040
1041TableConstraint CpModelBuilder::AddForbiddenAssignments(
1042 absl::Span<const IntVar> variables) {
1043 TableConstraint ct = AddAllowedAssignments(variables);
1044 ct.MutableProto()->mutable_table()->set_negated(true);
1045 return ct;
1046}
1047
1048TableConstraint CpModelBuilder::AddForbiddenAssignments(
1049 std::initializer_list<LinearExpr> expressions) {
1050 TableConstraint ct = AddAllowedAssignments(expressions);
1051 ct.MutableProto()->mutable_table()->set_negated(true);
1052 return ct;
1053}
1054
1055Constraint CpModelBuilder::AddInverseConstraint(
1056 absl::Span<const IntVar> variables,
1057 absl::Span<const IntVar> inverse_variables) {
1058 ConstraintProto* const proto = cp_model_.add_constraints();
1059 for (const IntVar& var : variables) {
1060 proto->mutable_inverse()->add_f_direct(var.index_);
1061 }
1062 for (const IntVar& var : inverse_variables) {
1063 proto->mutable_inverse()->add_f_inverse(var.index_);
1064 }
1065 return Constraint(proto);
1066}
1067
1068ReservoirConstraint CpModelBuilder::AddReservoirConstraint(int64_t min_level,
1069 int64_t max_level) {
1070 ConstraintProto* const proto = cp_model_.add_constraints();
1071 proto->mutable_reservoir()->set_min_level(min_level);
1072 proto->mutable_reservoir()->set_max_level(max_level);
1073 return ReservoirConstraint(proto, this);
1074}
1075
1076AutomatonConstraint CpModelBuilder::AddAutomaton(
1077 absl::Span<const LinearExpr> transition_expressions, int starting_state,
1078 absl::Span<const int> final_states) {
1079 ConstraintProto* const proto = cp_model_.add_constraints();
1080 for (const LinearExpr& expr : transition_expressions) {
1081 *proto->mutable_automaton()->add_exprs() = LinearExprToProto(expr);
1082 }
1083 proto->mutable_automaton()->set_starting_state(starting_state);
1084 for (const int final_state : final_states) {
1085 proto->mutable_automaton()->add_final_states(final_state);
1086 }
1087 return AutomatonConstraint(proto);
1088}
1089
1090AutomatonConstraint CpModelBuilder::AddAutomaton(
1091 absl::Span<const IntVar> transition_variables, int starting_state,
1092 absl::Span<const int> final_states) {
1093 ConstraintProto* const proto = cp_model_.add_constraints();
1094 for (const IntVar& var : transition_variables) {
1095 LinearExpressionProto* expr = proto->mutable_automaton()->add_exprs();
1096 expr->add_vars(var.index_);
1097 expr->add_coeffs(1);
1098 }
1099 proto->mutable_automaton()->set_starting_state(starting_state);
1100 for (const int final_state : final_states) {
1101 proto->mutable_automaton()->add_final_states(final_state);
1102 }
1103 return AutomatonConstraint(proto);
1104}
1105
1106AutomatonConstraint CpModelBuilder::AddAutomaton(
1107 std::initializer_list<LinearExpr> transition_expressions,
1108 int starting_state, absl::Span<const int> final_states) {
1109 ConstraintProto* const proto = cp_model_.add_constraints();
1110 for (const LinearExpr& expr : transition_expressions) {
1111 *proto->mutable_automaton()->add_exprs() = LinearExprToProto(expr);
1112 }
1113 proto->mutable_automaton()->set_starting_state(starting_state);
1114 for (const int final_state : final_states) {
1115 proto->mutable_automaton()->add_final_states(final_state);
1116 }
1117 return AutomatonConstraint(proto);
1118}
1119
1120LinearExpressionProto CpModelBuilder::LinearExprToProto(const LinearExpr& expr,
1121 bool negate) {
1122 LinearExpressionProto expr_proto;
1123 for (const int var : expr.variables()) {
1124 expr_proto.add_vars(var);
1125 }
1126 const int64_t mult = negate ? -1 : 1;
1127 for (const int64_t coeff : expr.coefficients()) {
1128 expr_proto.add_coeffs(coeff * mult);
1129 }
1130 expr_proto.set_offset(expr.constant() * mult);
1131 return expr_proto;
1132}
1133
1134Constraint CpModelBuilder::AddMinEquality(const LinearExpr& target,
1135 absl::Span<const IntVar> vars) {
1136 ConstraintProto* ct = cp_model_.add_constraints();
1137 *ct->mutable_lin_max()->mutable_target() =
1138 LinearExprToProto(target, /*negate=*/true);
1139 for (const IntVar& var : vars) {
1140 *ct->mutable_lin_max()->add_exprs() =
1141 LinearExprToProto(var, /*negate=*/true);
1142 }
1143 return Constraint(ct);
1144}
1145
1146Constraint CpModelBuilder::AddMinEquality(const LinearExpr& target,
1147 absl::Span<const LinearExpr> exprs) {
1148 ConstraintProto* ct = cp_model_.add_constraints();
1149 *ct->mutable_lin_max()->mutable_target() =
1150 LinearExprToProto(target, /*negate=*/true);
1151 for (const LinearExpr& expr : exprs) {
1152 *ct->mutable_lin_max()->add_exprs() =
1153 LinearExprToProto(expr, /*negate=*/true);
1154 }
1155 return Constraint(ct);
1156}
1157
1158Constraint CpModelBuilder::AddMinEquality(
1159 const LinearExpr& target, std::initializer_list<LinearExpr> exprs) {
1160 ConstraintProto* ct = cp_model_.add_constraints();
1161 *ct->mutable_lin_max()->mutable_target() =
1162 LinearExprToProto(target, /*negate=*/true);
1163 for (const LinearExpr& expr : exprs) {
1164 *ct->mutable_lin_max()->add_exprs() =
1165 LinearExprToProto(expr, /*negate=*/true);
1166 }
1167 return Constraint(ct);
1168}
1169
1170Constraint CpModelBuilder::AddMaxEquality(const LinearExpr& target,
1171 absl::Span<const IntVar> vars) {
1172 ConstraintProto* ct = cp_model_.add_constraints();
1173 *ct->mutable_lin_max()->mutable_target() = LinearExprToProto(target);
1174 for (const IntVar& var : vars) {
1175 *ct->mutable_lin_max()->add_exprs() = LinearExprToProto(var);
1176 }
1177 return Constraint(ct);
1178}
1179
1180Constraint CpModelBuilder::AddMaxEquality(const LinearExpr& target,
1181 absl::Span<const LinearExpr> exprs) {
1182 ConstraintProto* ct = cp_model_.add_constraints();
1183 *ct->mutable_lin_max()->mutable_target() = LinearExprToProto(target);
1184 for (const LinearExpr& expr : exprs) {
1185 *ct->mutable_lin_max()->add_exprs() = LinearExprToProto(expr);
1186 }
1187 return Constraint(ct);
1188}
1189
1190Constraint CpModelBuilder::AddMaxEquality(
1191 const LinearExpr& target, std::initializer_list<LinearExpr> exprs) {
1192 ConstraintProto* ct = cp_model_.add_constraints();
1193 *ct->mutable_lin_max()->mutable_target() = LinearExprToProto(target);
1194 for (const LinearExpr& expr : exprs) {
1195 *ct->mutable_lin_max()->add_exprs() = LinearExprToProto(expr);
1196 }
1197 return Constraint(ct);
1198}
1199
1200Constraint CpModelBuilder::AddDivisionEquality(const LinearExpr& target,
1201 const LinearExpr& numerator,
1202 const LinearExpr& denominator) {
1203 ConstraintProto* const proto = cp_model_.add_constraints();
1204 *proto->mutable_int_div()->mutable_target() = LinearExprToProto(target);
1205 *proto->mutable_int_div()->add_exprs() = LinearExprToProto(numerator);
1206 *proto->mutable_int_div()->add_exprs() = LinearExprToProto(denominator);
1207 return Constraint(proto);
1208}
1209
1210Constraint CpModelBuilder::AddAbsEquality(const LinearExpr& target,
1211 const LinearExpr& expr) {
1212 ConstraintProto* const proto = cp_model_.add_constraints();
1213 *proto->mutable_lin_max()->mutable_target() = LinearExprToProto(target);
1214 *proto->mutable_lin_max()->add_exprs() = LinearExprToProto(expr);
1215 *proto->mutable_lin_max()->add_exprs() =
1216 LinearExprToProto(expr, /*negate=*/true);
1217 return Constraint(proto);
1218}
1219
1220Constraint CpModelBuilder::AddModuloEquality(const LinearExpr& target,
1221 const LinearExpr& var,
1222 const LinearExpr& mod) {
1223 ConstraintProto* const proto = cp_model_.add_constraints();
1224 *proto->mutable_int_mod()->mutable_target() = LinearExprToProto(target);
1225 *proto->mutable_int_mod()->add_exprs() = LinearExprToProto(var);
1226 *proto->mutable_int_mod()->add_exprs() = LinearExprToProto(mod);
1227 return Constraint(proto);
1228}
1229
1230Constraint CpModelBuilder::AddMultiplicationEquality(
1231 const LinearExpr& target, absl::Span<const IntVar> vars) {
1232 ConstraintProto* const proto = cp_model_.add_constraints();
1233 *proto->mutable_int_prod()->mutable_target() = LinearExprToProto(target);
1234 for (const IntVar& var : vars) {
1235 *proto->mutable_int_prod()->add_exprs() = LinearExprToProto(var);
1236 }
1237 return Constraint(proto);
1238}
1239
1240Constraint CpModelBuilder::AddMultiplicationEquality(
1241 const LinearExpr& target, absl::Span<const LinearExpr> exprs) {
1242 ConstraintProto* const proto = cp_model_.add_constraints();
1243 *proto->mutable_int_prod()->mutable_target() = LinearExprToProto(target);
1244 for (const LinearExpr& expr : exprs) {
1245 *proto->mutable_int_prod()->add_exprs() = LinearExprToProto(expr);
1246 }
1247 return Constraint(proto);
1248}
1249
1250Constraint CpModelBuilder::AddMultiplicationEquality(
1251 const LinearExpr& target, std::initializer_list<LinearExpr> exprs) {
1252 ConstraintProto* const proto = cp_model_.add_constraints();
1253 *proto->mutable_int_prod()->mutable_target() = LinearExprToProto(target);
1254 for (const LinearExpr& expr : exprs) {
1255 *proto->mutable_int_prod()->add_exprs() = LinearExprToProto(expr);
1256 }
1257 return Constraint(proto);
1258}
1259Constraint CpModelBuilder::AddMultiplicationEquality(const LinearExpr& target,
1260 const LinearExpr& left,
1261 const LinearExpr& right) {
1262 ConstraintProto* const proto = cp_model_.add_constraints();
1263 *proto->mutable_int_prod()->mutable_target() = LinearExprToProto(target);
1264 *proto->mutable_int_prod()->add_exprs() = LinearExprToProto(left);
1265 *proto->mutable_int_prod()->add_exprs() = LinearExprToProto(right);
1266
1267 return Constraint(proto);
1268}
1269
1270Constraint CpModelBuilder::AddNoOverlap(absl::Span<const IntervalVar> vars) {
1271 ConstraintProto* const proto = cp_model_.add_constraints();
1272 for (const IntervalVar& var : vars) {
1273 proto->mutable_no_overlap()->add_intervals(var.index_);
1274 }
1275 return Constraint(proto);
1276}
1277
1278NoOverlap2DConstraint CpModelBuilder::AddNoOverlap2D() {
1279 return NoOverlap2DConstraint(cp_model_.add_constraints());
1280}
1281
1282CumulativeConstraint CpModelBuilder::AddCumulative(LinearExpr capacity) {
1283 ConstraintProto* const proto = cp_model_.add_constraints();
1284 *proto->mutable_cumulative()->mutable_capacity() =
1285 LinearExprToProto(capacity);
1286 return CumulativeConstraint(proto, this);
1287}
1288
1289void CpModelBuilder::Minimize(const LinearExpr& expr) {
1290 ClearObjective();
1291 for (const int x : expr.variables()) {
1292 cp_model_.mutable_objective()->add_vars(x);
1293 }
1294 for (const int64_t coeff : expr.coefficients()) {
1295 cp_model_.mutable_objective()->add_coeffs(coeff);
1296 }
1297 cp_model_.mutable_objective()->set_offset(expr.constant());
1298}
1299
1300void CpModelBuilder::Maximize(const LinearExpr& expr) {
1301 ClearObjective();
1302 for (const int x : expr.variables()) {
1303 cp_model_.mutable_objective()->add_vars(x);
1304 }
1305 for (const int64_t coeff : expr.coefficients()) {
1306 cp_model_.mutable_objective()->add_coeffs(-coeff);
1307 }
1308 cp_model_.mutable_objective()->set_offset(-expr.constant());
1309 cp_model_.mutable_objective()->set_scaling_factor(-1.0);
1310}
1311
1312void CpModelBuilder::Minimize(const DoubleLinearExpr& expr) {
1313 ClearObjective();
1314 for (int i = 0; i < expr.variables().size(); ++i) {
1315 cp_model_.mutable_floating_point_objective()->add_vars(expr.variables()[i]);
1316 cp_model_.mutable_floating_point_objective()->add_coeffs(
1317 expr.coefficients()[i]);
1318 }
1319 cp_model_.mutable_floating_point_objective()->set_offset(expr.constant());
1320 cp_model_.mutable_floating_point_objective()->set_maximize(false);
1321}
1322
1323void CpModelBuilder::Maximize(const DoubleLinearExpr& expr) {
1324 ClearObjective();
1325 for (int i = 0; i < expr.variables().size(); ++i) {
1326 cp_model_.mutable_floating_point_objective()->add_vars(expr.variables()[i]);
1327 cp_model_.mutable_floating_point_objective()->add_coeffs(
1328 expr.coefficients()[i]);
1329 }
1330 cp_model_.mutable_floating_point_objective()->set_offset(expr.constant());
1331 cp_model_.mutable_floating_point_objective()->set_maximize(true);
1332}
1333
1334void CpModelBuilder::ClearObjective() {
1335 cp_model_.clear_objective();
1336 cp_model_.clear_floating_point_objective();
1337}
1338
1339bool CpModelBuilder::HasObjective() const {
1340 return cp_model_.has_objective() || cp_model_.has_floating_point_objective();
1341}
1342
1343void CpModelBuilder::AddDecisionStrategy(
1344 absl::Span<const IntVar> variables,
1347 DecisionStrategyProto* const proto = cp_model_.add_search_strategy();
1348 for (const IntVar& var : variables) {
1349 LinearExpressionProto* expr = proto->add_exprs();
1350 if (var.index_ >= 0) {
1351 expr->add_vars(var.index_);
1352 expr->add_coeffs(1);
1353 } else {
1354 expr->add_vars(PositiveRef(var.index_));
1355 expr->add_coeffs(-1);
1356 expr->set_offset(1);
1357 }
1358 }
1359 proto->set_variable_selection_strategy(var_strategy);
1360 proto->set_domain_reduction_strategy(domain_strategy);
1361}
1362
1363void CpModelBuilder::AddDecisionStrategy(
1364 absl::Span<const BoolVar> variables,
1367 DecisionStrategyProto* const proto = cp_model_.add_search_strategy();
1368 for (const BoolVar& var : variables) {
1369 LinearExpressionProto* expr = proto->add_exprs();
1370 if (var.index_ >= 0) {
1371 expr->add_vars(var.index_);
1372 expr->add_coeffs(1);
1373 } else {
1374 expr->add_vars(PositiveRef(var.index_));
1375 expr->add_coeffs(-1);
1376 expr->set_offset(1);
1377 }
1378 }
1379 proto->set_variable_selection_strategy(var_strategy);
1380 proto->set_domain_reduction_strategy(domain_strategy);
1381}
1382
1383void CpModelBuilder::AddDecisionStrategy(
1384 absl::Span<const LinearExpr> expressions,
1387 DecisionStrategyProto* const proto = cp_model_.add_search_strategy();
1388 for (const LinearExpr& expr : expressions) {
1389 *proto->add_exprs() = LinearExprToProto(expr);
1390 }
1391 proto->set_variable_selection_strategy(var_strategy);
1392 proto->set_domain_reduction_strategy(domain_strategy);
1393}
1394
1395void CpModelBuilder::AddDecisionStrategy(
1396 std::initializer_list<LinearExpr> expressions,
1399 DecisionStrategyProto* const proto = cp_model_.add_search_strategy();
1400 for (const LinearExpr& expr : expressions) {
1401 *proto->add_exprs() = LinearExprToProto(expr);
1402 }
1403 proto->set_variable_selection_strategy(var_strategy);
1404 proto->set_domain_reduction_strategy(domain_strategy);
1405}
1406
1407void CpModelBuilder::AddHint(IntVar var, int64_t value) {
1408 cp_model_.mutable_solution_hint()->add_vars(var.index_);
1409 cp_model_.mutable_solution_hint()->add_values(value);
1410}
1411
1412void CpModelBuilder::AddHint(BoolVar var, bool value) {
1413 if (var.index_ >= 0) {
1414 cp_model_.mutable_solution_hint()->add_vars(var.index_);
1415 cp_model_.mutable_solution_hint()->add_values(value);
1416 } else {
1417 cp_model_.mutable_solution_hint()->add_vars(PositiveRef(var.index_));
1418 cp_model_.mutable_solution_hint()->add_values(!value);
1419 }
1420}
1421
1422void CpModelBuilder::ClearHints() {
1423 cp_model_.mutable_solution_hint()->Clear();
1424}
1425
1426void CpModelBuilder::AddAssumption(BoolVar lit) {
1427 cp_model_.mutable_assumptions()->Add(lit.index_);
1428}
1429
1430void CpModelBuilder::AddAssumptions(absl::Span<const BoolVar> literals) {
1431 for (const BoolVar& lit : literals) {
1432 cp_model_.mutable_assumptions()->Add(lit.index_);
1433 }
1434}
1435
1436void CpModelBuilder::ClearAssumptions() {
1437 cp_model_.mutable_assumptions()->Clear();
1438}
1439
1440CpModelBuilder CpModelBuilder::Clone() const {
1441 CpModelBuilder clone;
1442 clone.ResetAndImport(cp_model_);
1443 return clone;
1444}
1445
1446void CpModelBuilder::ResetAndImport(const CpModelProto& model_proto) {
1447 cp_model_ = model_proto;
1448 // Rebuild constant to index map.
1449 constant_to_index_map_.clear();
1450 for (int i = 0; i < cp_model_.variables_size(); ++i) {
1451 const IntegerVariableProto& var = cp_model_.variables(i);
1452 if (var.domain_size() == 2 && var.domain(0) == var.domain(1)) {
1453 constant_to_index_map_[var.domain(0)] = i;
1454 }
1455 }
1456 // This one would be more complicated to rebuild. Let's just clear it.
1457 bool_to_integer_index_map_.clear();
1458}
1459
1460BoolVar CpModelBuilder::GetBoolVarFromProtoIndex(int index) {
1461 CHECK_GE(index, 0);
1462 CHECK_LT(index, cp_model_.variables_size());
1463 const IntegerVariableProto& proto = cp_model_.variables(index);
1464 CHECK_EQ(2, proto.domain_size())
1465 << "CpModelBuilder::GetBoolVarFromProtoIndex: The domain of the variable "
1466 "is not Boolean";
1467 CHECK_GE(0, proto.domain(0))
1468 << "CpModelBuilder::GetBoolVarFromProtoIndex: The domain of the variable "
1469 "is not Boolean";
1470 CHECK_LE(1, proto.domain(1))
1471 << "CpModelBuilder::GetBoolVarFromProtoIndex: The domain of the variable "
1472 "is not Boolean";
1473 return BoolVar(index, this);
1474}
1475
1476IntVar CpModelBuilder::GetIntVarFromProtoIndex(int index) {
1477 CHECK_GE(index, 0);
1478 CHECK_LT(index, cp_model_.variables_size());
1479 return IntVar(index, this);
1480}
1481
1482IntervalVar CpModelBuilder::GetIntervalVarFromProtoIndex(int index) {
1483 CHECK_GE(index, 0);
1484 CHECK_LT(index, cp_model_.constraints_size());
1485 const ConstraintProto& ct = cp_model_.constraints(index);
1486 CHECK_EQ(ct.constraint_case(), ConstraintProto::kInterval)
1487 << "CpModelBuilder::GetIntervalVarFromProtoIndex: the referenced "
1488 "object is not an interval variable";
1489 return IntervalVar(index, this);
1490}
1491
1492bool CpModelBuilder::ExportToFile(absl::string_view filename) const {
1493 return WriteModelProtoToFile(cp_model_, filename);
1494}
1495
1497 const LinearExpr& expr) {
1498 int64_t result = expr.constant();
1499 const std::vector<int>& variables = expr.variables();
1500 const std::vector<int64_t>& coefficients = expr.coefficients();
1501 for (int i = 0; i < variables.size(); ++i) {
1502 result += r.solution(variables[i]) * coefficients[i];
1503 }
1504 return result;
1505}
1506
1508 const int ref = x.index_;
1509 if (RefIsPositive(ref)) {
1510 return r.solution(ref) == 1;
1511 } else {
1512 return r.solution(PositiveRef(ref)) == 0;
1513 }
1514}
1515
1516} // namespace sat
1517} // namespace operations_research
virtual std::string DebugString() const
LinearExpr & operator+=(const LinearExpr &rhs)
LinearExpr & operator-=(const LinearExpr &rhs)
LinearExpr & operator*=(double rhs)
virtual std::string name() const
Object naming.
*Adds a transitions to the automaton void AddTransition(int tail, int head, int64_t transition_label)
Definition cp_model.cc:555
BoolVar WithName(absl::string_view name)
Definition cp_model.cc:39
std::string Name() const
Returns the name of the variable.
Definition cp_model.cc:48
BoolVar Not() const
Returns the logical negation of the current Boolean variable.
Definition cp_model.h:91
std::string DebugString() const
Definition cp_model.cc:59
void AddArc(int tail, int head, BoolVar literal)
Definition cp_model.cc:515
::operations_research::sat::CumulativeConstraintProto *PROTOBUF_NONNULL mutable_cumulative()
::operations_research::sat::NoOverlap2DConstraintProto *PROTOBUF_NONNULL mutable_no_overlap_2d()
const ::std::string & name() const
::operations_research::sat::IntervalConstraintProto *PROTOBUF_NONNULL mutable_interval()
::operations_research::sat::ReservoirConstraintProto *PROTOBUF_NONNULL mutable_reservoir()
::operations_research::sat::BoolArgumentProto *PROTOBUF_NONNULL mutable_bool_or()
::operations_research::sat::LinearConstraintProto *PROTOBUF_NONNULL mutable_linear()
Constraint WithName(absl::string_view name)
Sets the name of the constraint.
Definition cp_model.cc:496
Constraint OnlyEnforceIf(absl::Span< const BoolVar > literals)
Definition cp_model.cc:503
Constraint(ConstraintProto *proto)
Definition cp_model.cc:494
absl::string_view Name() const
Returns the name of the constraint (or the empty string if not set).
Definition cp_model.cc:501
*Creates an integer variable with the given domain IntVar NewIntVar(const Domain &domain)
Definition cp_model.cc:686
*Creates an interval variable from affine expressions IntervalVar NewIntervalVar(const LinearExpr &start, const LinearExpr &size, const LinearExpr &end)
Definition cp_model.cc:716
*It is sometime convenient when building a model to create a bunch of *variables that will later be fixed Instead of doing these functions modify directly the *underlying variable domain *note this ignore completely the original variable domain and just fix *the given variable to the given value
Definition cp_model.h:785
*Creates an optional interval variable from affine expressions and a *Boolean variable IntervalVar NewOptionalIntervalVar(const LinearExpr &start, const LinearExpr &size, const LinearExpr &end, BoolVar presence)
Definition cp_model.cc:740
*Creates an always true Boolean variable *If this is called multiple the same variable will always be *returned BoolVar TrueVar()
Definition cp_model.cc:708
*Same as AddBoolOr(). Sum literals >
*Creates a Boolean variable BoolVar NewBoolVar()
Definition cp_model.cc:696
*Creates an always false Boolean variable *If this is called multiple the same variable will always be *returned BoolVar FalseVar()
Definition cp_model.cc:712
*Adds left right Constraint AddGreaterThan(const LinearExpr &left, const LinearExpr &right)
Definition cp_model.cc:870
*Sets the name of the model void SetName(absl::string_view name)
Definition cp_model.cc:650
*It is sometime convenient when building a model to create a bunch of *variables that will later be fixed Instead of doing these functions modify directly the *underlying variable domain *note this ignore completely the original variable domain and just fix *the given variable to the given even if it was outside the given *variable domain You can still use AddEquality() if this is not what you *want. void FixVariable(IntVar var
*Adds absl::Span< const BoolVar > rhs
Definition cp_model.h:816
*Creates an interval variable with a fixed size IntervalVar NewFixedSizeIntervalVar(const LinearExpr &start, int64_t size)
Definition cp_model.cc:728
*Creates an optional interval variable with a fixed size IntervalVar NewOptionalFixedSizeIntervalVar(const LinearExpr &start, int64_t size, BoolVar presence)
Definition cp_model.cc:754
void FixVariable(BoolVar var, bool value)
Definition cp_model.cc:767
const ::operations_research::sat::IntegerVariableProto & variables(int index) const
const ::operations_research::sat::ConstraintProto & constraints(int index) const
::operations_research::sat::LinearExpressionProto *PROTOBUF_NONNULL add_demands()
DecisionStrategyProto_DomainReductionStrategy DomainReductionStrategy
DecisionStrategyProto_VariableSelectionStrategy VariableSelectionStrategy
const std::vector< double > & coefficients() const
Returns the vector of coefficients.
Definition cp_model.h:411
static DoubleLinearExpr Sum(absl::Span< const IntVar > vars)
Constructs the sum of a list of variables.
Definition cp_model.cc:331
DoubleLinearExpr & operator*=(double coeff)
Multiply the linear expression by a constant.
Definition cp_model.cc:443
DoubleLinearExpr & operator+=(double value)
Adds a constant value to the linear expression.
Definition cp_model.cc:367
DoubleLinearExpr & AddTerm(IntVar var, double coeff)
Adds a term (var * coeff) to the linear expression.
Definition cp_model.cc:391
double constant() const
Returns the constant term.
Definition cp_model.h:417
static DoubleLinearExpr WeightedSum(absl::Span< const IntVar > vars, absl::Span< const double > coeffs)
Constructs the scalar product of variables and coefficients.
Definition cp_model.cc:347
DoubleLinearExpr & operator-=(double value)
Adds a constant value to the linear expression.
Definition cp_model.cc:423
std::string DebugString(const CpModelProto *proto=nullptr) const
Debug string. See the documentation for LinearExpr::DebugString().
Definition cp_model.cc:451
DoubleLinearExpr & AddExpression(const LinearExpr &exprs, double coeff=1.0)
Adds a linear expression to the double linear expression.
Definition cp_model.cc:410
std::string Name() const
Returns the name of the variable (or the empty string if not set).
Definition cp_model.cc:126
std::string DebugString() const
Definition cp_model.cc:136
int index() const
Returns the index of the variable in the model. This will be non-negative.
Definition cp_model.h:192
IntVar WithName(absl::string_view name)
Sets the name of the variable.
Definition cp_model.cc:119
BoolVar ToBoolVar() const
Cast IntVar -> BoolVar.
Definition cp_model.cc:109
::operations_research::Domain Domain() const
Definition cp_model.cc:131
::operations_research::sat::LinearExpressionProto *PROTOBUF_NONNULL mutable_start()
::operations_research::sat::LinearExpressionProto *PROTOBUF_NONNULL mutable_size()
::operations_research::sat::LinearExpressionProto *PROTOBUF_NONNULL mutable_end()
const ::operations_research::sat::LinearExpressionProto & end() const
IntervalVar WithName(absl::string_view name)
Sets the name of the variable.
Definition cp_model.cc:583
std::string Name() const
Returns the name of the interval (or the empty string if not set).
Definition cp_model.cc:621
std::string DebugString() const
Returns a debug string.
Definition cp_model.cc:626
static LinearExpr Sum(absl::Span< const IntVar > vars)
Constructs the sum of a list of variables.
Definition cp_model.cc:207
std::string DebugString(const CpModelProto *proto=nullptr) const
Definition cp_model.cc:280
static LinearExpr WeightedSum(absl::Span< const IntVar > vars, absl::Span< const int64_t > coeffs)
Constructs the scalar product of variables and coefficients.
Definition cp_model.cc:223
static LinearExpr Term(IntVar var, int64_t coefficient)
Constructs var * coefficient.
Definition cp_model.cc:243
int64_t constant() const
Returns the constant term.
Definition cp_model.h:303
LinearExpr()=default
Creates an empty linear expression with value zero.
static LinearExpr FromProto(const LinearExpressionProto &proto)
Constructs a linear expr from its proto representation.
Definition cp_model.cc:198
const std::vector< int > & variables() const
Returns the vector of variable indices.
Definition cp_model.h:294
const std::vector< int64_t > & coefficients() const
Returns the vector of coefficients.
Definition cp_model.h:297
void AddArc(int tail, int head, BoolVar literal)
Definition cp_model.cc:521
::operations_research::sat::LinearExpressionProto *PROTOBUF_NONNULL add_level_changes()
::operations_research::sat::LinearExpressionProto *PROTOBUF_NONNULL add_time_exprs()
void AddEvent(LinearExpr time, int64_t level_change)
Definition cp_model.cc:538
void AddTuple(absl::Span< const int64_t > tuple)
Adds a tuple of possible values to the constraint.
Definition cp_model.cc:527
std::ostream & operator<<(std::ostream &out, FileFormat f)
std::string VarDebugString(const CpModelProto &proto, int index)
Definition cp_model.cc:143
int64_t SolutionIntegerValue(const CpSolverResponse &r, const LinearExpr &expr)
Definition cp_model.cc:1496
bool WriteModelProtoToFile(const M &proto, absl::string_view filename)
BoolVar Not(BoolVar x)
Definition cp_model.cc:87
std::ostream & operator<<(std::ostream &os, const BoolVar &var)
Definition cp_model.cc:89
void FillDomainInProto(const Domain &domain, ProtoWithDomain *proto)
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
bool SolutionBooleanValue(const CpSolverResponse &r, BoolVar x)
Definition cp_model.cc:1507
OR-Tools root namespace.
ClosedInterval::Iterator end(ClosedInterval interval)
std::ostream & operator<<(std::ostream &out, const Assignment &assignment)