22 #include "absl/container/flat_hash_map.h"
25 #include "ortools/sat/cp_model.pb.h"
33 template <
typename IntList>
34 void AddIndices(
const IntList& indices, std::vector<int>* output) {
35 output->insert(output->end(), indices.begin(), indices.end());
41 LinearExpressionProto* output_negated_expr) {
42 output_negated_expr->Clear();
43 for (
int i = 0; i < input_expr.vars_size(); ++i) {
44 output_negated_expr->add_vars(
NegatedRef(input_expr.vars(i)));
45 output_negated_expr->add_coeffs(input_expr.coeffs(i));
47 output_negated_expr->set_offset(-input_expr.offset());
52 switch (
ct.constraint_case()) {
53 case ConstraintProto::ConstraintCase::kBoolOr:
54 AddIndices(
ct.bool_or().literals(), &output.
literals);
56 case ConstraintProto::ConstraintCase::kBoolAnd:
57 AddIndices(
ct.bool_and().literals(), &output.
literals);
59 case ConstraintProto::ConstraintCase::kAtMostOne:
60 AddIndices(
ct.at_most_one().literals(), &output.
literals);
62 case ConstraintProto::ConstraintCase::kExactlyOne:
63 AddIndices(
ct.exactly_one().literals(), &output.
literals);
65 case ConstraintProto::ConstraintCase::kBoolXor:
66 AddIndices(
ct.bool_xor().literals(), &output.
literals);
68 case ConstraintProto::ConstraintCase::kIntDiv:
69 AddIndices(
ct.int_div().target().vars(), &output.
variables);
70 for (
const LinearExpressionProto& expr :
ct.int_div().exprs()) {
71 AddIndices(expr.vars(), &output.
variables);
74 case ConstraintProto::ConstraintCase::kIntMod:
75 AddIndices(
ct.int_mod().target().vars(), &output.
variables);
76 for (
const LinearExpressionProto& expr :
ct.int_mod().exprs()) {
77 AddIndices(expr.vars(), &output.
variables);
80 case ConstraintProto::ConstraintCase::kLinMax: {
81 AddIndices(
ct.lin_max().target().vars(), &output.
variables);
82 for (
const LinearExpressionProto& expr :
ct.lin_max().exprs()) {
83 AddIndices(expr.vars(), &output.
variables);
87 case ConstraintProto::ConstraintCase::kIntProd:
88 AddIndices(
ct.int_prod().target().vars(), &output.
variables);
89 for (
const LinearExpressionProto& expr :
ct.int_prod().exprs()) {
90 AddIndices(expr.vars(), &output.
variables);
93 case ConstraintProto::ConstraintCase::kLinear:
96 case ConstraintProto::ConstraintCase::kAllDiff:
97 for (
const LinearExpressionProto& expr :
ct.all_diff().exprs()) {
98 AddIndices(expr.vars(), &output.
variables);
101 case ConstraintProto::ConstraintCase::kDummyConstraint:
102 AddIndices(
ct.dummy_constraint().vars(), &output.
variables);
104 case ConstraintProto::ConstraintCase::kElement:
107 AddIndices(
ct.element().vars(), &output.
variables);
109 case ConstraintProto::ConstraintCase::kCircuit:
110 AddIndices(
ct.circuit().literals(), &output.
literals);
112 case ConstraintProto::ConstraintCase::kRoutes:
113 AddIndices(
ct.routes().literals(), &output.
literals);
115 case ConstraintProto::ConstraintCase::kInverse:
116 AddIndices(
ct.inverse().f_direct(), &output.
variables);
117 AddIndices(
ct.inverse().f_inverse(), &output.
variables);
119 case ConstraintProto::ConstraintCase::kReservoir:
120 for (
const LinearExpressionProto&
time :
ct.reservoir().time_exprs()) {
123 for (
const LinearExpressionProto& level :
124 ct.reservoir().level_changes()) {
125 AddIndices(level.vars(), &output.
variables);
127 AddIndices(
ct.reservoir().active_literals(), &output.
literals);
129 case ConstraintProto::ConstraintCase::kTable:
132 case ConstraintProto::ConstraintCase::kAutomaton:
133 AddIndices(
ct.automaton().vars(), &output.
variables);
135 case ConstraintProto::ConstraintCase::kInterval:
136 AddIndices(
ct.interval().start().vars(), &output.
variables);
137 AddIndices(
ct.interval().size().vars(), &output.
variables);
138 AddIndices(
ct.interval().end().vars(), &output.
variables);
140 case ConstraintProto::ConstraintCase::kNoOverlap:
142 case ConstraintProto::ConstraintCase::kNoOverlap2D:
144 case ConstraintProto::ConstraintCase::kCumulative:
145 AddIndices(
ct.cumulative().capacity().vars(), &output.
variables);
146 for (
const LinearExpressionProto&
demand :
ct.cumulative().demands()) {
150 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
156 #define APPLY_TO_SINGULAR_FIELD(ct_name, field_name) \
158 int temp = ct->mutable_##ct_name()->field_name(); \
160 ct->mutable_##ct_name()->set_##field_name(temp); \
163 #define APPLY_TO_REPEATED_FIELD(ct_name, field_name) \
165 for (int& r : *ct->mutable_##ct_name()->mutable_##field_name()) f(&r); \
169 ConstraintProto*
ct) {
170 for (
int& r : *
ct->mutable_enforcement_literal()) f(&r);
171 switch (
ct->constraint_case()) {
172 case ConstraintProto::ConstraintCase::kBoolOr:
175 case ConstraintProto::ConstraintCase::kBoolAnd:
178 case ConstraintProto::ConstraintCase::kAtMostOne:
181 case ConstraintProto::ConstraintCase::kExactlyOne:
184 case ConstraintProto::ConstraintCase::kBoolXor:
187 case ConstraintProto::ConstraintCase::kIntDiv:
189 case ConstraintProto::ConstraintCase::kIntMod:
191 case ConstraintProto::ConstraintCase::kLinMax:
193 case ConstraintProto::ConstraintCase::kIntProd:
195 case ConstraintProto::ConstraintCase::kLinear:
197 case ConstraintProto::ConstraintCase::kAllDiff:
199 case ConstraintProto::ConstraintCase::kDummyConstraint:
201 case ConstraintProto::ConstraintCase::kElement:
203 case ConstraintProto::ConstraintCase::kCircuit:
206 case ConstraintProto::ConstraintCase::kRoutes:
209 case ConstraintProto::ConstraintCase::kInverse:
211 case ConstraintProto::ConstraintCase::kReservoir:
214 case ConstraintProto::ConstraintCase::kTable:
216 case ConstraintProto::ConstraintCase::kAutomaton:
218 case ConstraintProto::ConstraintCase::kInterval:
220 case ConstraintProto::ConstraintCase::kNoOverlap:
222 case ConstraintProto::ConstraintCase::kNoOverlap2D:
224 case ConstraintProto::ConstraintCase::kCumulative:
226 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
232 ConstraintProto*
ct) {
233 switch (
ct->constraint_case()) {
234 case ConstraintProto::ConstraintCase::kBoolOr:
236 case ConstraintProto::ConstraintCase::kBoolAnd:
238 case ConstraintProto::ConstraintCase::kAtMostOne:
240 case ConstraintProto::ConstraintCase::kExactlyOne:
242 case ConstraintProto::ConstraintCase::kBoolXor:
244 case ConstraintProto::ConstraintCase::kIntDiv:
246 for (
int i = 0; i <
ct->int_div().exprs_size(); ++i) {
250 case ConstraintProto::ConstraintCase::kIntMod:
252 for (
int i = 0; i <
ct->int_mod().exprs_size(); ++i) {
256 case ConstraintProto::ConstraintCase::kLinMax:
258 for (
int i = 0; i <
ct->lin_max().exprs_size(); ++i) {
262 case ConstraintProto::ConstraintCase::kIntProd:
264 for (
int i = 0; i <
ct->int_prod().exprs_size(); ++i) {
268 case ConstraintProto::ConstraintCase::kLinear:
271 case ConstraintProto::ConstraintCase::kAllDiff:
272 for (
int i = 0; i <
ct->all_diff().exprs_size(); ++i) {
276 case ConstraintProto::ConstraintCase::kDummyConstraint:
279 case ConstraintProto::ConstraintCase::kElement:
284 case ConstraintProto::ConstraintCase::kCircuit:
286 case ConstraintProto::ConstraintCase::kRoutes:
288 case ConstraintProto::ConstraintCase::kInverse:
292 case ConstraintProto::ConstraintCase::kReservoir:
293 for (
int i = 0; i <
ct->reservoir().time_exprs_size(); ++i) {
296 for (
int i = 0; i <
ct->reservoir().level_changes_size(); ++i) {
300 case ConstraintProto::ConstraintCase::kTable:
303 case ConstraintProto::ConstraintCase::kAutomaton:
306 case ConstraintProto::ConstraintCase::kInterval:
311 case ConstraintProto::ConstraintCase::kNoOverlap:
313 case ConstraintProto::ConstraintCase::kNoOverlap2D:
315 case ConstraintProto::ConstraintCase::kCumulative:
317 for (
int i = 0; i <
ct->cumulative().demands_size(); ++i) {
319 *
ct->mutable_cumulative()->mutable_demands(i)->mutable_vars()) {
324 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
330 ConstraintProto*
ct) {
331 switch (
ct->constraint_case()) {
332 case ConstraintProto::ConstraintCase::kBoolOr:
334 case ConstraintProto::ConstraintCase::kBoolAnd:
336 case ConstraintProto::ConstraintCase::kAtMostOne:
338 case ConstraintProto::ConstraintCase::kExactlyOne:
340 case ConstraintProto::ConstraintCase::kBoolXor:
342 case ConstraintProto::ConstraintCase::kIntDiv:
344 case ConstraintProto::ConstraintCase::kIntMod:
346 case ConstraintProto::ConstraintCase::kLinMax:
348 case ConstraintProto::ConstraintCase::kIntProd:
350 case ConstraintProto::ConstraintCase::kLinear:
352 case ConstraintProto::ConstraintCase::kAllDiff:
354 case ConstraintProto::ConstraintCase::kDummyConstraint:
356 case ConstraintProto::ConstraintCase::kElement:
358 case ConstraintProto::ConstraintCase::kCircuit:
360 case ConstraintProto::ConstraintCase::kRoutes:
362 case ConstraintProto::ConstraintCase::kInverse:
364 case ConstraintProto::ConstraintCase::kReservoir:
366 case ConstraintProto::ConstraintCase::kTable:
368 case ConstraintProto::ConstraintCase::kAutomaton:
370 case ConstraintProto::ConstraintCase::kInterval:
372 case ConstraintProto::ConstraintCase::kNoOverlap:
375 case ConstraintProto::ConstraintCase::kNoOverlap2D:
379 case ConstraintProto::ConstraintCase::kCumulative:
382 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
387 #undef APPLY_TO_SINGULAR_FIELD
388 #undef APPLY_TO_REPEATED_FIELD
391 ConstraintProto::ConstraintCase constraint_case) {
392 switch (constraint_case) {
393 case ConstraintProto::ConstraintCase::kBoolOr:
395 case ConstraintProto::ConstraintCase::kBoolAnd:
397 case ConstraintProto::ConstraintCase::kAtMostOne:
399 case ConstraintProto::ConstraintCase::kExactlyOne:
400 return "kExactlyOne";
401 case ConstraintProto::ConstraintCase::kBoolXor:
403 case ConstraintProto::ConstraintCase::kIntDiv:
405 case ConstraintProto::ConstraintCase::kIntMod:
407 case ConstraintProto::ConstraintCase::kLinMax:
409 case ConstraintProto::ConstraintCase::kIntProd:
411 case ConstraintProto::ConstraintCase::kLinear:
413 case ConstraintProto::ConstraintCase::kAllDiff:
415 case ConstraintProto::ConstraintCase::kDummyConstraint:
416 return "kDummyConstraint";
417 case ConstraintProto::ConstraintCase::kElement:
419 case ConstraintProto::ConstraintCase::kCircuit:
421 case ConstraintProto::ConstraintCase::kRoutes:
423 case ConstraintProto::ConstraintCase::kInverse:
425 case ConstraintProto::ConstraintCase::kReservoir:
427 case ConstraintProto::ConstraintCase::kTable:
429 case ConstraintProto::ConstraintCase::kAutomaton:
431 case ConstraintProto::ConstraintCase::kInterval:
433 case ConstraintProto::ConstraintCase::kNoOverlap:
435 case ConstraintProto::ConstraintCase::kNoOverlap2D:
436 return "kNoOverlap2D";
437 case ConstraintProto::ConstraintCase::kCumulative:
438 return "kCumulative";
439 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
449 for (
const int lit : references.
literals) {
452 for (
const int lit :
ct.enforcement_literal()) {
460 std::vector<int> used_intervals;
461 switch (
ct.constraint_case()) {
462 case ConstraintProto::ConstraintCase::kBoolOr:
464 case ConstraintProto::ConstraintCase::kBoolAnd:
466 case ConstraintProto::ConstraintCase::kAtMostOne:
468 case ConstraintProto::ConstraintCase::kExactlyOne:
470 case ConstraintProto::ConstraintCase::kBoolXor:
472 case ConstraintProto::ConstraintCase::kIntDiv:
474 case ConstraintProto::ConstraintCase::kIntMod:
476 case ConstraintProto::ConstraintCase::kLinMax:
478 case ConstraintProto::ConstraintCase::kIntProd:
480 case ConstraintProto::ConstraintCase::kLinear:
482 case ConstraintProto::ConstraintCase::kAllDiff:
484 case ConstraintProto::ConstraintCase::kDummyConstraint:
486 case ConstraintProto::ConstraintCase::kElement:
488 case ConstraintProto::ConstraintCase::kCircuit:
490 case ConstraintProto::ConstraintCase::kRoutes:
492 case ConstraintProto::ConstraintCase::kInverse:
494 case ConstraintProto::ConstraintCase::kReservoir:
496 case ConstraintProto::ConstraintCase::kTable:
498 case ConstraintProto::ConstraintCase::kAutomaton:
500 case ConstraintProto::ConstraintCase::kInterval:
502 case ConstraintProto::ConstraintCase::kNoOverlap:
503 AddIndices(
ct.no_overlap().intervals(), &used_intervals);
505 case ConstraintProto::ConstraintCase::kNoOverlap2D:
506 AddIndices(
ct.no_overlap_2d().x_intervals(), &used_intervals);
507 AddIndices(
ct.no_overlap_2d().y_intervals(), &used_intervals);
509 case ConstraintProto::ConstraintCase::kCumulative:
510 AddIndices(
ct.cumulative().intervals(), &used_intervals);
512 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
516 return used_intervals;
520 absl::Span<const int64_t> solution) {
522 for (
int i = 0; i < objective.vars_size(); ++i) {
523 int64_t coeff = objective.coeffs(i);
524 const int ref = objective.vars(i);
533 return expr.offset() == 0 && expr.vars_size() == 1 &&
534 std::abs(expr.coeffs(0)) == 1;
538 return expr.vars_size() <= 1;
545 return expr.coeffs(0) == 1 ? expr.vars(0) :
NegatedRef(expr.vars(0));
550 LinearConstraintProto* linear) {
551 for (
int i = 0; i < expr.vars_size(); ++i) {
552 linear->add_vars(expr.vars(i));
555 DCHECK(!linear->domain().empty());
564 const LinearExpressionProto&
b,
566 if (
a.vars_size() !=
b.vars_size())
return false;
567 if (
a.offset() !=
b.offset() * b_scaling)
return false;
568 absl::flat_hash_map<int, int64_t> coeffs;
569 for (
int i = 0; i <
a.vars_size(); ++i) {
570 coeffs[
a.vars(i)] +=
a.coeffs(i);
571 coeffs[
b.vars(i)] += -
b.coeffs(i) * b_scaling;
574 for (
const auto [
var, coeff] : coeffs) {
575 if (coeff != 0)
return false;
583 if (!lin.vars().empty()) {
593 for (
const IntegerVariableProto& var_proto :
model.variables()) {
596 for (
const ConstraintProto&
ct :
model.constraints()) {
597 if (!
ct.enforcement_literal().empty()) {
600 switch (
ct.constraint_case()) {
601 case ConstraintProto::ConstraintCase::kBoolOr:
604 case ConstraintProto::ConstraintCase::kBoolAnd:
607 case ConstraintProto::ConstraintCase::kAtMostOne:
610 case ConstraintProto::ConstraintCase::kExactlyOne:
613 case ConstraintProto::ConstraintCase::kBoolXor:
616 case ConstraintProto::ConstraintCase::kIntDiv:
618 for (
const LinearExpressionProto& expr :
ct.int_div().exprs()) {
622 case ConstraintProto::ConstraintCase::kIntMod:
624 for (
const LinearExpressionProto& expr :
ct.int_mod().exprs()) {
628 case ConstraintProto::ConstraintCase::kLinMax: {
630 for (
const LinearExpressionProto& expr :
ct.lin_max().exprs()) {
635 case ConstraintProto::ConstraintCase::kIntProd:
637 for (
const LinearExpressionProto& expr :
ct.int_prod().exprs()) {
641 case ConstraintProto::ConstraintCase::kLinear:
646 case ConstraintProto::ConstraintCase::kAllDiff:
647 for (
const LinearExpressionProto& expr :
ct.all_diff().exprs()) {
651 case ConstraintProto::ConstraintCase::kDummyConstraint:
653 case ConstraintProto::ConstraintCase::kElement:
658 case ConstraintProto::ConstraintCase::kCircuit:
663 case ConstraintProto::ConstraintCase::kRoutes:
668 case ConstraintProto::ConstraintCase::kInverse:
672 case ConstraintProto::ConstraintCase::kReservoir:
675 for (
const LinearExpressionProto& expr :
ct.reservoir().time_exprs()) {
678 for (
const LinearExpressionProto& expr :
679 ct.reservoir().level_changes()) {
683 case ConstraintProto::ConstraintCase::kTable:
688 case ConstraintProto::ConstraintCase::kAutomaton:
696 case ConstraintProto::ConstraintCase::kInterval:
701 case ConstraintProto::ConstraintCase::kNoOverlap:
704 case ConstraintProto::ConstraintCase::kNoOverlap2D:
708 case ConstraintProto::ConstraintCase::kCumulative:
711 for (
const LinearExpressionProto&
demand :
ct.cumulative().demands()) {
715 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
721 if (
model.has_objective()) {
727 }
else if (
model.has_floating_point_objective()) {
736 if (
model.has_solution_hint()) {
746 #if !defined(__PORTABLE_PLATFORM__)
757 class InlineFieldPrinter
758 :
public google::protobuf::TextFormat::FastFieldValuePrinter {
759 void PrintMessageStart(
const google::protobuf::Message& ,
762 google::protobuf::TextFormat::BaseTextGenerator*
763 generator)
const override {
764 generator->PrintLiteral(
" { ");
768 class InlineMessagePrinter
769 :
public google::protobuf::TextFormat::MessagePrinter {
771 InlineMessagePrinter() {
772 printer_.SetSingleLineMode(
true);
773 printer_.SetUseShortRepeatedPrimitives(
true);
776 void Print(
const google::protobuf::Message&
message,
778 google::protobuf::TextFormat::BaseTextGenerator* generator)
781 printer_.PrintToString(
message, &buffer_);
782 generator->Print(buffer_.data(), buffer_.size());
786 google::protobuf::TextFormat::Printer printer_;
787 mutable std::string buffer_;
792 void RegisterFieldPrinters(
793 const google::protobuf::Descriptor* descriptor,
794 absl::flat_hash_set<const google::protobuf::Descriptor*>* descriptors,
795 google::protobuf::TextFormat::Printer* printer) {
797 if (!descriptors->insert(descriptor).second)
return;
799 for (
int i = 0; i < descriptor->field_count(); ++i) {
800 const google::protobuf::FieldDescriptor* field = descriptor->field(i);
801 if (field->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE) {
802 if (field->message_type() == IntegerVariableProto::descriptor() ||
803 field->message_type() == LinearExpressionProto::descriptor()) {
804 printer->RegisterFieldValuePrinter(field,
new InlineFieldPrinter());
806 RegisterFieldPrinters(field->message_type(), descriptors, printer);
815 printer->SetUseShortRepeatedPrimitives(
true);
816 absl::flat_hash_set<const google::protobuf::Descriptor*> descriptors;
817 RegisterFieldPrinters(CpModelProto::descriptor(), &descriptors, printer);
818 printer->RegisterMessagePrinter(IntegerVariableProto::descriptor(),
819 new InlineMessagePrinter());
820 printer->RegisterMessagePrinter(LinearExpressionProto::descriptor(),
821 new InlineMessagePrinter());
We call domain any subset of Int64 = [kint64min, kint64max].
Domain AdditionWith(const Domain &domain) const
Returns {x ∈ Int64, ∃ a ∈ D, ∃ b ∈ domain, x = a + b}.
#define APPLY_TO_SINGULAR_FIELD(ct_name, field_name)
#define APPLY_TO_REPEATED_FIELD(ct_name, field_name)
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
uint64_t FingerprintRepeatedField(const google::protobuf::RepeatedField< T > &sequence, uint64_t seed)
std::vector< int > UsedVariables(const ConstraintProto &ct)
bool RefIsPositive(int ref)
std::vector< int > UsedIntervals(const ConstraintProto &ct)
void SetToNegatedLinearExpression(const LinearExpressionProto &input_expr, LinearExpressionProto *output_negated_expr)
uint64_t FingerprintSingleField(const T &field, uint64_t seed)
void ApplyToAllLiteralIndices(const std::function< void(int *)> &f, ConstraintProto *ct)
bool LinearExpressionProtosAreEqual(const LinearExpressionProto &a, const LinearExpressionProto &b, int64_t b_scaling)
void ApplyToAllIntervalIndices(const std::function< void(int *)> &f, ConstraintProto *ct)
void FillDomainInProto(const Domain &domain, ProtoWithDomain *proto)
uint64_t FingerprintExpression(const LinearExpressionProto &lin, uint64_t seed)
bool ExpressionIsAffine(const LinearExpressionProto &expr)
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
void ApplyToAllVariableIndices(const std::function< void(int *)> &f, ConstraintProto *ct)
int64_t ComputeInnerObjective(const CpObjectiveProto &objective, absl::Span< const int64_t > solution)
void SetupTextFormatPrinter(google::protobuf::TextFormat::Printer *printer)
IndexReferences GetReferencesUsedByConstraint(const ConstraintProto &ct)
void AddLinearExpressionToLinearConstraint(const LinearExpressionProto &expr, int64_t coefficient, LinearConstraintProto *linear)
std::string ConstraintCaseName(ConstraintProto::ConstraintCase constraint_case)
int GetSingleRefFromExpression(const LinearExpressionProto &expr)
bool ExpressionContainsSingleRef(const LinearExpressionProto &expr)
uint64_t FingerprintModel(const CpModelProto &model, uint64_t seed)
Collection of objects used to extend the Constraint Solver library.
std::optional< int64_t > end
std::vector< int > variables
std::vector< int > literals