24#include "absl/container/flat_hash_map.h"
25#include "absl/container/flat_hash_set.h"
26#include "absl/log/check.h"
27#include "absl/strings/str_cat.h"
28#include "absl/strings/string_view.h"
29#include "absl/types/span.h"
30#include "google/protobuf/descriptor.h"
31#include "google/protobuf/message.h"
32#include "google/protobuf/text_format.h"
34#include "ortools/sat/cp_model.pb.h"
44template <
typename IntList>
45void AddIndices(
const IntList& indices, std::vector<int>* output) {
46 output->insert(output->end(), indices.begin(), indices.end());
52 gcd = std::gcd(gcd, std::abs(expr.offset()));
53 for (
const int64_t coeff : expr.coeffs()) {
54 gcd = std::gcd(gcd, std::abs(coeff));
61 if (divisor == 1)
return;
63 DCHECK_EQ(expr->offset() % divisor, 0);
64 expr->set_offset(expr->offset() / divisor);
65 for (
int i = 0;
i < expr->vars_size(); ++
i) {
66 DCHECK_EQ(expr->coeffs(
i) % divisor, 0);
67 expr->set_coeffs(
i, expr->coeffs(
i) / divisor);
72 LinearExpressionProto* output_negated_expr) {
73 output_negated_expr->Clear();
74 for (
int i = 0;
i < input_expr.vars_size(); ++
i) {
75 output_negated_expr->add_vars(
NegatedRef(input_expr.vars(
i)));
76 output_negated_expr->add_coeffs(input_expr.coeffs(
i));
78 output_negated_expr->set_offset(-input_expr.offset());
88 std::vector<int>* variables,
89 std::vector<int>* literals) {
92 switch (
ct.constraint_case()) {
93 case ConstraintProto::ConstraintCase::kBoolOr:
94 AddIndices(
ct.bool_or().literals(), literals);
96 case ConstraintProto::ConstraintCase::kBoolAnd:
97 AddIndices(
ct.bool_and().literals(), literals);
99 case ConstraintProto::ConstraintCase::kAtMostOne:
100 AddIndices(
ct.at_most_one().literals(), literals);
102 case ConstraintProto::ConstraintCase::kExactlyOne:
103 AddIndices(
ct.exactly_one().literals(), literals);
105 case ConstraintProto::ConstraintCase::kBoolXor:
106 AddIndices(
ct.bool_xor().literals(), literals);
108 case ConstraintProto::ConstraintCase::kIntDiv:
109 AddIndices(
ct.int_div().target().vars(), variables);
110 for (
const LinearExpressionProto& expr :
ct.int_div().exprs()) {
111 AddIndices(expr.vars(), variables);
114 case ConstraintProto::ConstraintCase::kIntMod:
115 AddIndices(
ct.int_mod().target().vars(), variables);
116 for (
const LinearExpressionProto& expr :
ct.int_mod().exprs()) {
117 AddIndices(expr.vars(), variables);
120 case ConstraintProto::ConstraintCase::kLinMax: {
121 AddIndices(
ct.lin_max().target().vars(), variables);
122 for (
const LinearExpressionProto& expr :
ct.lin_max().exprs()) {
123 AddIndices(expr.vars(), variables);
127 case ConstraintProto::ConstraintCase::kIntProd:
128 AddIndices(
ct.int_prod().target().vars(), variables);
129 for (
const LinearExpressionProto& expr :
ct.int_prod().exprs()) {
130 AddIndices(expr.vars(), variables);
133 case ConstraintProto::ConstraintCase::kLinear:
134 AddIndices(
ct.linear().vars(), variables);
136 case ConstraintProto::ConstraintCase::kAllDiff:
137 for (
const LinearExpressionProto& expr :
ct.all_diff().exprs()) {
138 AddIndices(expr.vars(), variables);
141 case ConstraintProto::ConstraintCase::kDummyConstraint:
142 AddIndices(
ct.dummy_constraint().vars(), variables);
144 case ConstraintProto::ConstraintCase::kElement:
145 variables->push_back(
ct.element().index());
146 variables->push_back(
ct.element().target());
147 AddIndices(
ct.element().vars(), variables);
149 case ConstraintProto::ConstraintCase::kCircuit:
150 AddIndices(
ct.circuit().literals(), literals);
152 case ConstraintProto::ConstraintCase::kRoutes:
153 AddIndices(
ct.routes().literals(), literals);
155 case ConstraintProto::ConstraintCase::kInverse:
156 AddIndices(
ct.inverse().f_direct(), variables);
157 AddIndices(
ct.inverse().f_inverse(), variables);
159 case ConstraintProto::ConstraintCase::kReservoir:
160 for (
const LinearExpressionProto&
time :
ct.reservoir().time_exprs()) {
161 AddIndices(
time.vars(), variables);
163 for (
const LinearExpressionProto& level :
164 ct.reservoir().level_changes()) {
165 AddIndices(level.vars(), variables);
167 AddIndices(
ct.reservoir().active_literals(), literals);
169 case ConstraintProto::ConstraintCase::kTable:
170 AddIndices(
ct.table().vars(), variables);
172 case ConstraintProto::ConstraintCase::kAutomaton:
173 AddIndices(
ct.automaton().vars(), variables);
175 case ConstraintProto::ConstraintCase::kInterval:
176 AddIndices(
ct.interval().start().vars(), variables);
177 AddIndices(
ct.interval().size().vars(), variables);
178 AddIndices(
ct.interval().end().vars(), variables);
180 case ConstraintProto::ConstraintCase::kNoOverlap:
182 case ConstraintProto::ConstraintCase::kNoOverlap2D:
184 case ConstraintProto::ConstraintCase::kCumulative:
185 AddIndices(
ct.cumulative().capacity().vars(), variables);
186 for (
const LinearExpressionProto&
demand :
ct.cumulative().demands()) {
187 AddIndices(
demand.vars(), variables);
190 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
195#define APPLY_TO_SINGULAR_FIELD(ct_name, field_name) \
197 int temp = ct->mutable_##ct_name()->field_name(); \
199 ct->mutable_##ct_name()->set_##field_name(temp); \
202#define APPLY_TO_REPEATED_FIELD(ct_name, field_name) \
204 for (int& r : *ct->mutable_##ct_name()->mutable_##field_name()) f(&r); \
208 ConstraintProto*
ct) {
209 for (
int& r : *
ct->mutable_enforcement_literal()) f(&r);
210 switch (
ct->constraint_case()) {
211 case ConstraintProto::ConstraintCase::kBoolOr:
214 case ConstraintProto::ConstraintCase::kBoolAnd:
217 case ConstraintProto::ConstraintCase::kAtMostOne:
220 case ConstraintProto::ConstraintCase::kExactlyOne:
223 case ConstraintProto::ConstraintCase::kBoolXor:
226 case ConstraintProto::ConstraintCase::kIntDiv:
228 case ConstraintProto::ConstraintCase::kIntMod:
230 case ConstraintProto::ConstraintCase::kLinMax:
232 case ConstraintProto::ConstraintCase::kIntProd:
234 case ConstraintProto::ConstraintCase::kLinear:
236 case ConstraintProto::ConstraintCase::kAllDiff:
238 case ConstraintProto::ConstraintCase::kDummyConstraint:
240 case ConstraintProto::ConstraintCase::kElement:
242 case ConstraintProto::ConstraintCase::kCircuit:
245 case ConstraintProto::ConstraintCase::kRoutes:
248 case ConstraintProto::ConstraintCase::kInverse:
250 case ConstraintProto::ConstraintCase::kReservoir:
253 case ConstraintProto::ConstraintCase::kTable:
255 case ConstraintProto::ConstraintCase::kAutomaton:
257 case ConstraintProto::ConstraintCase::kInterval:
259 case ConstraintProto::ConstraintCase::kNoOverlap:
261 case ConstraintProto::ConstraintCase::kNoOverlap2D:
263 case ConstraintProto::ConstraintCase::kCumulative:
265 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
271 ConstraintProto*
ct) {
272 switch (
ct->constraint_case()) {
273 case ConstraintProto::ConstraintCase::kBoolOr:
275 case ConstraintProto::ConstraintCase::kBoolAnd:
277 case ConstraintProto::ConstraintCase::kAtMostOne:
279 case ConstraintProto::ConstraintCase::kExactlyOne:
281 case ConstraintProto::ConstraintCase::kBoolXor:
283 case ConstraintProto::ConstraintCase::kIntDiv:
285 for (
int i = 0;
i <
ct->int_div().exprs_size(); ++
i) {
289 case ConstraintProto::ConstraintCase::kIntMod:
291 for (
int i = 0;
i <
ct->int_mod().exprs_size(); ++
i) {
295 case ConstraintProto::ConstraintCase::kLinMax:
297 for (
int i = 0;
i <
ct->lin_max().exprs_size(); ++
i) {
301 case ConstraintProto::ConstraintCase::kIntProd:
303 for (
int i = 0;
i <
ct->int_prod().exprs_size(); ++
i) {
307 case ConstraintProto::ConstraintCase::kLinear:
310 case ConstraintProto::ConstraintCase::kAllDiff:
311 for (
int i = 0;
i <
ct->all_diff().exprs_size(); ++
i) {
315 case ConstraintProto::ConstraintCase::kDummyConstraint:
318 case ConstraintProto::ConstraintCase::kElement:
323 case ConstraintProto::ConstraintCase::kCircuit:
325 case ConstraintProto::ConstraintCase::kRoutes:
327 case ConstraintProto::ConstraintCase::kInverse:
331 case ConstraintProto::ConstraintCase::kReservoir:
332 for (
int i = 0;
i <
ct->reservoir().time_exprs_size(); ++
i) {
335 for (
int i = 0;
i <
ct->reservoir().level_changes_size(); ++
i) {
339 case ConstraintProto::ConstraintCase::kTable:
342 case ConstraintProto::ConstraintCase::kAutomaton:
345 case ConstraintProto::ConstraintCase::kInterval:
350 case ConstraintProto::ConstraintCase::kNoOverlap:
352 case ConstraintProto::ConstraintCase::kNoOverlap2D:
354 case ConstraintProto::ConstraintCase::kCumulative:
356 for (
int i = 0;
i <
ct->cumulative().demands_size(); ++
i) {
358 *
ct->mutable_cumulative()->mutable_demands(
i)->mutable_vars()) {
363 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
369 ConstraintProto*
ct) {
370 switch (
ct->constraint_case()) {
371 case ConstraintProto::ConstraintCase::kBoolOr:
373 case ConstraintProto::ConstraintCase::kBoolAnd:
375 case ConstraintProto::ConstraintCase::kAtMostOne:
377 case ConstraintProto::ConstraintCase::kExactlyOne:
379 case ConstraintProto::ConstraintCase::kBoolXor:
381 case ConstraintProto::ConstraintCase::kIntDiv:
383 case ConstraintProto::ConstraintCase::kIntMod:
385 case ConstraintProto::ConstraintCase::kLinMax:
387 case ConstraintProto::ConstraintCase::kIntProd:
389 case ConstraintProto::ConstraintCase::kLinear:
391 case ConstraintProto::ConstraintCase::kAllDiff:
393 case ConstraintProto::ConstraintCase::kDummyConstraint:
395 case ConstraintProto::ConstraintCase::kElement:
397 case ConstraintProto::ConstraintCase::kCircuit:
399 case ConstraintProto::ConstraintCase::kRoutes:
401 case ConstraintProto::ConstraintCase::kInverse:
403 case ConstraintProto::ConstraintCase::kReservoir:
405 case ConstraintProto::ConstraintCase::kTable:
407 case ConstraintProto::ConstraintCase::kAutomaton:
409 case ConstraintProto::ConstraintCase::kInterval:
411 case ConstraintProto::ConstraintCase::kNoOverlap:
414 case ConstraintProto::ConstraintCase::kNoOverlap2D:
418 case ConstraintProto::ConstraintCase::kCumulative:
421 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
426#undef APPLY_TO_SINGULAR_FIELD
427#undef APPLY_TO_REPEATED_FIELD
430 ConstraintProto::ConstraintCase constraint_case) {
431 switch (constraint_case) {
432 case ConstraintProto::ConstraintCase::kBoolOr:
434 case ConstraintProto::ConstraintCase::kBoolAnd:
436 case ConstraintProto::ConstraintCase::kAtMostOne:
438 case ConstraintProto::ConstraintCase::kExactlyOne:
439 return "kExactlyOne";
440 case ConstraintProto::ConstraintCase::kBoolXor:
442 case ConstraintProto::ConstraintCase::kIntDiv:
444 case ConstraintProto::ConstraintCase::kIntMod:
446 case ConstraintProto::ConstraintCase::kLinMax:
448 case ConstraintProto::ConstraintCase::kIntProd:
450 case ConstraintProto::ConstraintCase::kLinear:
452 case ConstraintProto::ConstraintCase::kAllDiff:
454 case ConstraintProto::ConstraintCase::kDummyConstraint:
455 return "kDummyConstraint";
456 case ConstraintProto::ConstraintCase::kElement:
458 case ConstraintProto::ConstraintCase::kCircuit:
460 case ConstraintProto::ConstraintCase::kRoutes:
462 case ConstraintProto::ConstraintCase::kInverse:
464 case ConstraintProto::ConstraintCase::kReservoir:
466 case ConstraintProto::ConstraintCase::kTable:
468 case ConstraintProto::ConstraintCase::kAutomaton:
470 case ConstraintProto::ConstraintCase::kInterval:
472 case ConstraintProto::ConstraintCase::kNoOverlap:
474 case ConstraintProto::ConstraintCase::kNoOverlap2D:
475 return "kNoOverlap2D";
476 case ConstraintProto::ConstraintCase::kCumulative:
477 return "kCumulative";
478 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
484 std::vector<int> result;
486 for (
int& ref : result) {
489 for (
const int lit :
ct.enforcement_literal()) {
497 std::vector<int> used_intervals;
498 switch (
ct.constraint_case()) {
499 case ConstraintProto::ConstraintCase::kBoolOr:
501 case ConstraintProto::ConstraintCase::kBoolAnd:
503 case ConstraintProto::ConstraintCase::kAtMostOne:
505 case ConstraintProto::ConstraintCase::kExactlyOne:
507 case ConstraintProto::ConstraintCase::kBoolXor:
509 case ConstraintProto::ConstraintCase::kIntDiv:
511 case ConstraintProto::ConstraintCase::kIntMod:
513 case ConstraintProto::ConstraintCase::kLinMax:
515 case ConstraintProto::ConstraintCase::kIntProd:
517 case ConstraintProto::ConstraintCase::kLinear:
519 case ConstraintProto::ConstraintCase::kAllDiff:
521 case ConstraintProto::ConstraintCase::kDummyConstraint:
523 case ConstraintProto::ConstraintCase::kElement:
525 case ConstraintProto::ConstraintCase::kCircuit:
527 case ConstraintProto::ConstraintCase::kRoutes:
529 case ConstraintProto::ConstraintCase::kInverse:
531 case ConstraintProto::ConstraintCase::kReservoir:
533 case ConstraintProto::ConstraintCase::kTable:
535 case ConstraintProto::ConstraintCase::kAutomaton:
537 case ConstraintProto::ConstraintCase::kInterval:
539 case ConstraintProto::ConstraintCase::kNoOverlap:
540 AddIndices(
ct.no_overlap().intervals(), &used_intervals);
542 case ConstraintProto::ConstraintCase::kNoOverlap2D:
543 AddIndices(
ct.no_overlap_2d().x_intervals(), &used_intervals);
544 AddIndices(
ct.no_overlap_2d().y_intervals(), &used_intervals);
546 case ConstraintProto::ConstraintCase::kCumulative:
547 AddIndices(
ct.cumulative().intervals(), &used_intervals);
549 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
553 return used_intervals;
557 absl::Span<const int64_t>
solution) {
559 for (
int i = 0;
i < objective.vars_size(); ++
i) {
560 int64_t coeff = objective.coeffs(
i);
561 const int ref = objective.vars(
i);
570 return expr.offset() == 0 && expr.vars_size() == 1 &&
571 std::abs(expr.coeffs(0)) == 1;
575 return expr.vars_size() <= 1;
582 return expr.coeffs(0) == 1 ? expr.vars(0) :
NegatedRef(expr.vars(0));
587 LinearConstraintProto* linear) {
588 for (
int i = 0;
i < expr.vars_size(); ++
i) {
589 linear->add_vars(expr.vars(
i));
592 DCHECK(!linear->domain().empty());
601 const LinearExpressionProto& expr, int64_t
coefficient,
602 LinearConstraintProto* linear) {
603 for (
int i = 0;
i < expr.vars_size(); ++
i) {
604 linear->add_vars(expr.vars(
i));
607 linear->add_coeffs(prod);
609 DCHECK(!linear->domain().empty());
620 const LinearExpressionProto&
b,
622 if (
a.vars_size() !=
b.vars_size())
return false;
623 if (
a.offset() !=
b.offset() * b_scaling)
return false;
624 absl::flat_hash_map<int, int64_t> coeffs;
625 for (
int i = 0;
i <
a.vars_size(); ++
i) {
626 coeffs[
a.vars(
i)] +=
a.coeffs(
i);
627 coeffs[
b.vars(
i)] += -
b.coeffs(
i) * b_scaling;
630 for (
const auto [
var, coeff] : coeffs) {
631 if (coeff != 0)
return false;
639 if (!lin.vars().empty()) {
649 for (
const IntegerVariableProto& var_proto :
model.variables()) {
652 for (
const ConstraintProto&
ct :
model.constraints()) {
653 if (!
ct.enforcement_literal().empty()) {
656 switch (
ct.constraint_case()) {
657 case ConstraintProto::ConstraintCase::kBoolOr:
660 case ConstraintProto::ConstraintCase::kBoolAnd:
663 case ConstraintProto::ConstraintCase::kAtMostOne:
666 case ConstraintProto::ConstraintCase::kExactlyOne:
669 case ConstraintProto::ConstraintCase::kBoolXor:
672 case ConstraintProto::ConstraintCase::kIntDiv:
674 for (
const LinearExpressionProto& expr :
ct.int_div().exprs()) {
678 case ConstraintProto::ConstraintCase::kIntMod:
680 for (
const LinearExpressionProto& expr :
ct.int_mod().exprs()) {
684 case ConstraintProto::ConstraintCase::kLinMax: {
686 for (
const LinearExpressionProto& expr :
ct.lin_max().exprs()) {
691 case ConstraintProto::ConstraintCase::kIntProd:
693 for (
const LinearExpressionProto& expr :
ct.int_prod().exprs()) {
697 case ConstraintProto::ConstraintCase::kLinear:
702 case ConstraintProto::ConstraintCase::kAllDiff:
703 for (
const LinearExpressionProto& expr :
ct.all_diff().exprs()) {
707 case ConstraintProto::ConstraintCase::kDummyConstraint:
709 case ConstraintProto::ConstraintCase::kElement:
714 case ConstraintProto::ConstraintCase::kCircuit:
719 case ConstraintProto::ConstraintCase::kRoutes:
724 case ConstraintProto::ConstraintCase::kInverse:
728 case ConstraintProto::ConstraintCase::kReservoir:
731 for (
const LinearExpressionProto& expr :
ct.reservoir().time_exprs()) {
734 for (
const LinearExpressionProto& expr :
735 ct.reservoir().level_changes()) {
739 case ConstraintProto::ConstraintCase::kTable:
744 case ConstraintProto::ConstraintCase::kAutomaton:
752 case ConstraintProto::ConstraintCase::kInterval:
757 case ConstraintProto::ConstraintCase::kNoOverlap:
760 case ConstraintProto::ConstraintCase::kNoOverlap2D:
764 case ConstraintProto::ConstraintCase::kCumulative:
767 for (
const LinearExpressionProto&
demand :
ct.cumulative().demands()) {
771 case ConstraintProto::ConstraintCase::CONSTRAINT_NOT_SET:
777 if (
model.has_objective()) {
783 }
else if (
model.has_floating_point_objective()) {
792 if (
model.has_solution_hint()) {
802#if !defined(__PORTABLE_PLATFORM__)
813class InlineFieldPrinter
814 :
public google::protobuf::TextFormat::FastFieldValuePrinter {
815 void PrintMessageStart(
const google::protobuf::Message& ,
818 google::protobuf::TextFormat::BaseTextGenerator*
819 generator)
const override {
820 generator->PrintLiteral(
" { ");
824class InlineMessagePrinter
825 :
public google::protobuf::TextFormat::MessagePrinter {
827 InlineMessagePrinter() {
828 printer_.SetSingleLineMode(
true);
829 printer_.SetUseShortRepeatedPrimitives(
true);
832 void Print(
const google::protobuf::Message&
message,
834 google::protobuf::TextFormat::BaseTextGenerator* generator)
837 printer_.PrintToString(
message, &buffer_);
838 generator->Print(buffer_.data(), buffer_.size());
842 google::protobuf::TextFormat::Printer printer_;
843 mutable std::string buffer_;
848void RegisterFieldPrinters(
849 const google::protobuf::Descriptor* descriptor,
850 absl::flat_hash_set<const google::protobuf::Descriptor*>* descriptors,
851 google::protobuf::TextFormat::Printer* printer) {
853 if (!descriptors->insert(descriptor).second)
return;
855 for (
int i = 0;
i < descriptor->field_count(); ++
i) {
856 const google::protobuf::FieldDescriptor* field = descriptor->field(
i);
857 if (field->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE) {
858 if (field->message_type() == IntegerVariableProto::descriptor() ||
859 field->message_type() == LinearExpressionProto::descriptor()) {
860 printer->RegisterFieldValuePrinter(field,
new InlineFieldPrinter());
862 RegisterFieldPrinters(field->message_type(), descriptors, printer);
871 printer->SetUseShortRepeatedPrimitives(
true);
872 absl::flat_hash_set<const google::protobuf::Descriptor*> descriptors;
873 RegisterFieldPrinters(CpModelProto::descriptor(), &descriptors, printer);
874 printer->RegisterMessagePrinter(IntegerVariableProto::descriptor(),
875 new InlineMessagePrinter());
876 printer->RegisterMessagePrinter(LinearExpressionProto::descriptor(),
877 new InlineMessagePrinter());
886 if (cp_model.has_objective())
return false;
887 const int num_vars = cp_model.variables().size();
888 for (
int v = 0; v < num_vars; ++v) {
889 if (cp_model.variables(v).domain().size() != 2)
return false;
890 if (cp_model.variables(v).domain(0) != 0)
return false;
891 if (cp_model.variables(v).domain(1) != 1)
return false;
894 for (
const ConstraintProto&
ct : cp_model.constraints()) {
895 if (
ct.constraint_case() == ConstraintProto::kBoolOr) {
897 }
else if (
ct.constraint_case() == ConstraintProto::kBoolAnd) {
898 num_clauses +=
ct.bool_and().literals().size();
906 absl::StrAppend(out,
"p cnf ", num_vars,
" ", num_clauses,
"\n");
907 for (
const ConstraintProto&
ct : cp_model.constraints()) {
908 if (
ct.constraint_case() == ConstraintProto::kBoolOr) {
909 CHECK(
ct.enforcement_literal().empty());
910 for (
const int lit :
ct.bool_or().literals()) {
914 absl::StrAppend(out,
value,
" ");
916 absl::StrAppend(out,
"0\n");
917 }
else if (
ct.constraint_case() == ConstraintProto::kBoolAnd) {
918 CHECK(!
ct.enforcement_literal().empty());
920 for (
const int lit :
ct.enforcement_literal()) {
926 for (
const int lit :
ct.bool_and().literals()) {
Domain AdditionWith(const Domain &domain) const
#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)
void SetToNegatedLinearExpression(const LinearExpressionProto &input_expr, LinearExpressionProto *output_negated_expr)
Fills the target as negated ref.
constexpr uint64_t kDefaultFingerprintSeed
Default seed for fingerprints.
uint64_t FingerprintRepeatedField(const google::protobuf::RepeatedField< T > &sequence, uint64_t seed)
bool RefIsPositive(int ref)
int64_t ComputeInnerObjective(const CpObjectiveProto &objective, absl::Span< const int64_t > solution)
int CombineSeed(int base_seed, int64_t delta)
We assume delta >= 0 and we only use the low bit of delta.
void ApplyToAllIntervalIndices(const std::function< void(int *)> &f, ConstraintProto *ct)
bool SafeAddLinearExpressionToLinearConstraint(const LinearExpressionProto &expr, int64_t coefficient, LinearConstraintProto *linear)
Same method, but returns if the addition was possible without overflowing.
uint64_t FingerprintSingleField(const T &field, uint64_t seed)
bool ConvertCpModelProtoToCnf(const CpModelProto &cp_model, std::string *out)
uint64_t FingerprintExpression(const LinearExpressionProto &lin, uint64_t seed)
Returns a stable fingerprint of a linear expression.
uint64_t FingerprintModel(const CpModelProto &model, uint64_t seed)
Returns a stable fingerprint of a model.
bool ExpressionIsAffine(const LinearExpressionProto &expr)
Checks if the expression is affine or constant.
std::vector< int > UsedVariables(const ConstraintProto &ct)
std::vector< int > UsedIntervals(const ConstraintProto &ct)
Returns the sorted list of interval used by a constraint.
void FillDomainInProto(const Domain &domain, ProtoWithDomain *proto)
Serializes a Domain into the domain field of a proto.
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
Reads a Domain from the domain field of a proto.
void SetupTextFormatPrinter(google::protobuf::TextFormat::Printer *printer)
absl::string_view ConstraintCaseName(ConstraintProto::ConstraintCase constraint_case)
bool ExpressionContainsSingleRef(const LinearExpressionProto &expr)
Returns true if a linear expression can be reduced to a single ref.
int64_t LinearExpressionGcd(const LinearExpressionProto &expr, int64_t gcd)
void ApplyToAllLiteralIndices(const std::function< void(int *)> &f, ConstraintProto *ct)
void DivideLinearExpression(int64_t divisor, LinearExpressionProto *expr)
void AddLinearExpressionToLinearConstraint(const LinearExpressionProto &expr, int64_t coefficient, LinearConstraintProto *linear)
int GetSingleRefFromExpression(const LinearExpressionProto &expr)
int NegatedRef(int ref)
Small utility functions to deal with negative variable/literal references.
bool LinearExpressionProtosAreEqual(const LinearExpressionProto &a, const LinearExpressionProto &b, int64_t b_scaling)
Returns true iff a == b * b_scaling.
IndexReferences GetReferencesUsedByConstraint(const ConstraintProto &ct)
void ApplyToAllVariableIndices(const std::function< void(int *)> &f, ConstraintProto *ct)
In SWIG mode, we don't want anything besides these top-level includes.
bool AtMinOrMaxInt64(int64_t x)
Checks if x is equal to the min or the max value of an int64_t.
int64_t CapProd(int64_t x, int64_t y)
std::optional< int64_t > end
std::vector< int > variables
std::vector< int > literals
double objective_value
The value objective_vector^T * (solution - center_point).