22#include "absl/container/flat_hash_map.h"
25#include "ortools/sat/cp_model.pb.h"
33template <
typename IntList>
34void 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 AddIndices(
ct.reservoir().active_literals(), &output.
literals);
125 case ConstraintProto::ConstraintCase::kTable:
128 case ConstraintProto::ConstraintCase::kAutomaton:
129 AddIndices(
ct.automaton().vars(), &output.
variables);
131 case ConstraintProto::ConstraintCase::kInterval:
132 AddIndices(
ct.interval().start().vars(), &output.
variables);
133 AddIndices(
ct.interval().size().vars(), &output.
variables);
134 AddIndices(
ct.interval().end().vars(), &output.
variables);
136 case ConstraintProto::ConstraintCase::kNoOverlap:
138 case ConstraintProto::ConstraintCase::kNoOverlap2D:
140 case ConstraintProto::ConstraintCase::kCumulative:
141 AddIndices(
ct.cumulative().capacity().vars(), &output.
variables);
142 for (
const LinearExpressionProto&
demand :
ct.cumulative().demands()) {
146 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
152#define APPLY_TO_SINGULAR_FIELD(ct_name, field_name) \
154 int temp = ct->mutable_##ct_name()->field_name(); \
156 ct->mutable_##ct_name()->set_##field_name(temp); \
159#define APPLY_TO_REPEATED_FIELD(ct_name, field_name) \
161 for (int& r : *ct->mutable_##ct_name()->mutable_##field_name()) f(&r); \
165 ConstraintProto*
ct) {
166 for (
int& r : *
ct->mutable_enforcement_literal()) f(&r);
167 switch (
ct->constraint_case()) {
168 case ConstraintProto::ConstraintCase::kBoolOr:
171 case ConstraintProto::ConstraintCase::kBoolAnd:
174 case ConstraintProto::ConstraintCase::kAtMostOne:
177 case ConstraintProto::ConstraintCase::kExactlyOne:
180 case ConstraintProto::ConstraintCase::kBoolXor:
183 case ConstraintProto::ConstraintCase::kIntDiv:
185 case ConstraintProto::ConstraintCase::kIntMod:
187 case ConstraintProto::ConstraintCase::kLinMax:
189 case ConstraintProto::ConstraintCase::kIntProd:
191 case ConstraintProto::ConstraintCase::kLinear:
193 case ConstraintProto::ConstraintCase::kAllDiff:
195 case ConstraintProto::ConstraintCase::kDummyConstraint:
197 case ConstraintProto::ConstraintCase::kElement:
199 case ConstraintProto::ConstraintCase::kCircuit:
202 case ConstraintProto::ConstraintCase::kRoutes:
205 case ConstraintProto::ConstraintCase::kInverse:
207 case ConstraintProto::ConstraintCase::kReservoir:
210 case ConstraintProto::ConstraintCase::kTable:
212 case ConstraintProto::ConstraintCase::kAutomaton:
214 case ConstraintProto::ConstraintCase::kInterval:
216 case ConstraintProto::ConstraintCase::kNoOverlap:
218 case ConstraintProto::ConstraintCase::kNoOverlap2D:
220 case ConstraintProto::ConstraintCase::kCumulative:
222 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
228 ConstraintProto*
ct) {
229 switch (
ct->constraint_case()) {
230 case ConstraintProto::ConstraintCase::kBoolOr:
232 case ConstraintProto::ConstraintCase::kBoolAnd:
234 case ConstraintProto::ConstraintCase::kAtMostOne:
236 case ConstraintProto::ConstraintCase::kExactlyOne:
238 case ConstraintProto::ConstraintCase::kBoolXor:
240 case ConstraintProto::ConstraintCase::kIntDiv:
242 for (
int i = 0; i <
ct->int_div().exprs_size(); ++i) {
246 case ConstraintProto::ConstraintCase::kIntMod:
248 for (
int i = 0; i <
ct->int_mod().exprs_size(); ++i) {
252 case ConstraintProto::ConstraintCase::kLinMax:
254 for (
int i = 0; i <
ct->lin_max().exprs_size(); ++i) {
258 case ConstraintProto::ConstraintCase::kIntProd:
260 for (
int i = 0; i <
ct->int_prod().exprs_size(); ++i) {
264 case ConstraintProto::ConstraintCase::kLinear:
267 case ConstraintProto::ConstraintCase::kAllDiff:
268 for (
int i = 0; i <
ct->all_diff().exprs_size(); ++i) {
272 case ConstraintProto::ConstraintCase::kDummyConstraint:
275 case ConstraintProto::ConstraintCase::kElement:
280 case ConstraintProto::ConstraintCase::kCircuit:
282 case ConstraintProto::ConstraintCase::kRoutes:
284 case ConstraintProto::ConstraintCase::kInverse:
288 case ConstraintProto::ConstraintCase::kReservoir:
289 for (
int i = 0; i <
ct->reservoir().time_exprs_size(); ++i) {
293 case ConstraintProto::ConstraintCase::kTable:
296 case ConstraintProto::ConstraintCase::kAutomaton:
299 case ConstraintProto::ConstraintCase::kInterval:
304 case ConstraintProto::ConstraintCase::kNoOverlap:
306 case ConstraintProto::ConstraintCase::kNoOverlap2D:
308 case ConstraintProto::ConstraintCase::kCumulative:
310 for (
int i = 0; i <
ct->cumulative().demands_size(); ++i) {
312 *
ct->mutable_cumulative()->mutable_demands(i)->mutable_vars()) {
317 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
323 ConstraintProto*
ct) {
324 switch (
ct->constraint_case()) {
325 case ConstraintProto::ConstraintCase::kBoolOr:
327 case ConstraintProto::ConstraintCase::kBoolAnd:
329 case ConstraintProto::ConstraintCase::kAtMostOne:
331 case ConstraintProto::ConstraintCase::kExactlyOne:
333 case ConstraintProto::ConstraintCase::kBoolXor:
335 case ConstraintProto::ConstraintCase::kIntDiv:
337 case ConstraintProto::ConstraintCase::kIntMod:
339 case ConstraintProto::ConstraintCase::kLinMax:
341 case ConstraintProto::ConstraintCase::kIntProd:
343 case ConstraintProto::ConstraintCase::kLinear:
345 case ConstraintProto::ConstraintCase::kAllDiff:
347 case ConstraintProto::ConstraintCase::kDummyConstraint:
349 case ConstraintProto::ConstraintCase::kElement:
351 case ConstraintProto::ConstraintCase::kCircuit:
353 case ConstraintProto::ConstraintCase::kRoutes:
355 case ConstraintProto::ConstraintCase::kInverse:
357 case ConstraintProto::ConstraintCase::kReservoir:
359 case ConstraintProto::ConstraintCase::kTable:
361 case ConstraintProto::ConstraintCase::kAutomaton:
363 case ConstraintProto::ConstraintCase::kInterval:
365 case ConstraintProto::ConstraintCase::kNoOverlap:
368 case ConstraintProto::ConstraintCase::kNoOverlap2D:
372 case ConstraintProto::ConstraintCase::kCumulative:
375 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
380#undef APPLY_TO_SINGULAR_FIELD
381#undef APPLY_TO_REPEATED_FIELD
384 ConstraintProto::ConstraintCase constraint_case) {
385 switch (constraint_case) {
386 case ConstraintProto::ConstraintCase::kBoolOr:
388 case ConstraintProto::ConstraintCase::kBoolAnd:
390 case ConstraintProto::ConstraintCase::kAtMostOne:
392 case ConstraintProto::ConstraintCase::kExactlyOne:
393 return "kExactlyOne";
394 case ConstraintProto::ConstraintCase::kBoolXor:
396 case ConstraintProto::ConstraintCase::kIntDiv:
398 case ConstraintProto::ConstraintCase::kIntMod:
400 case ConstraintProto::ConstraintCase::kLinMax:
402 case ConstraintProto::ConstraintCase::kIntProd:
404 case ConstraintProto::ConstraintCase::kLinear:
406 case ConstraintProto::ConstraintCase::kAllDiff:
408 case ConstraintProto::ConstraintCase::kDummyConstraint:
409 return "kDummyConstraint";
410 case ConstraintProto::ConstraintCase::kElement:
412 case ConstraintProto::ConstraintCase::kCircuit:
414 case ConstraintProto::ConstraintCase::kRoutes:
416 case ConstraintProto::ConstraintCase::kInverse:
418 case ConstraintProto::ConstraintCase::kReservoir:
420 case ConstraintProto::ConstraintCase::kTable:
422 case ConstraintProto::ConstraintCase::kAutomaton:
424 case ConstraintProto::ConstraintCase::kInterval:
426 case ConstraintProto::ConstraintCase::kNoOverlap:
428 case ConstraintProto::ConstraintCase::kNoOverlap2D:
429 return "kNoOverlap2D";
430 case ConstraintProto::ConstraintCase::kCumulative:
431 return "kCumulative";
432 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
442 for (
const int lit : references.
literals) {
445 for (
const int lit :
ct.enforcement_literal()) {
453 std::vector<int> used_intervals;
454 switch (
ct.constraint_case()) {
455 case ConstraintProto::ConstraintCase::kBoolOr:
457 case ConstraintProto::ConstraintCase::kBoolAnd:
459 case ConstraintProto::ConstraintCase::kAtMostOne:
461 case ConstraintProto::ConstraintCase::kExactlyOne:
463 case ConstraintProto::ConstraintCase::kBoolXor:
465 case ConstraintProto::ConstraintCase::kIntDiv:
467 case ConstraintProto::ConstraintCase::kIntMod:
469 case ConstraintProto::ConstraintCase::kLinMax:
471 case ConstraintProto::ConstraintCase::kIntProd:
473 case ConstraintProto::ConstraintCase::kLinear:
475 case ConstraintProto::ConstraintCase::kAllDiff:
477 case ConstraintProto::ConstraintCase::kDummyConstraint:
479 case ConstraintProto::ConstraintCase::kElement:
481 case ConstraintProto::ConstraintCase::kCircuit:
483 case ConstraintProto::ConstraintCase::kRoutes:
485 case ConstraintProto::ConstraintCase::kInverse:
487 case ConstraintProto::ConstraintCase::kReservoir:
489 case ConstraintProto::ConstraintCase::kTable:
491 case ConstraintProto::ConstraintCase::kAutomaton:
493 case ConstraintProto::ConstraintCase::kInterval:
495 case ConstraintProto::ConstraintCase::kNoOverlap:
496 AddIndices(
ct.no_overlap().intervals(), &used_intervals);
498 case ConstraintProto::ConstraintCase::kNoOverlap2D:
499 AddIndices(
ct.no_overlap_2d().x_intervals(), &used_intervals);
500 AddIndices(
ct.no_overlap_2d().y_intervals(), &used_intervals);
502 case ConstraintProto::ConstraintCase::kCumulative:
503 AddIndices(
ct.cumulative().intervals(), &used_intervals);
505 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
509 return used_intervals;
515 for (
int i = 0; i < objective.vars_size(); ++i) {
516 int64_t
coeff = objective.coeffs(i);
517 const int ref = objective.vars(i);
526 return expr.offset() == 0 && expr.vars_size() == 1 &&
527 std::abs(expr.coeffs(0)) == 1;
531 return expr.vars_size() <= 1;
538 return expr.coeffs(0) == 1 ? expr.vars(0) :
NegatedRef(expr.vars(0));
543 LinearConstraintProto* linear) {
544 for (
int i = 0; i < expr.vars_size(); ++i) {
545 linear->add_vars(expr.vars(i));
548 DCHECK(!linear->domain().empty());
557 const LinearExpressionProto&
b,
559 if (
a.vars_size() !=
b.vars_size())
return false;
560 if (
a.offset() !=
b.offset() * b_scaling)
return false;
561 absl::flat_hash_map<int, int64_t> coeffs;
562 for (
int i = 0; i <
a.vars_size(); ++i) {
563 coeffs[
a.vars(i)] +=
a.coeffs(i);
564 coeffs[
b.vars(i)] += -
b.coeffs(i) * b_scaling;
567 for (
const auto [
var,
coeff] : coeffs) {
568 if (
coeff != 0)
return false;
#define DCHECK(condition)
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}.
SharedResponseManager * response
#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)
int64_t ComputeInnerObjective(const CpObjectiveProto &objective, const CpSolverResponse &response)
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)
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)
bool ExpressionIsAffine(const LinearExpressionProto &expr)
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
void ApplyToAllVariableIndices(const std::function< void(int *)> &f, ConstraintProto *ct)
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)
Collection of objects used to extend the Constraint Solver library.
std::optional< int64_t > end
std::vector< int > variables
std::vector< int > literals