25#include "absl/base/optimization.h"
26#include "absl/container/flat_hash_map.h"
27#include "absl/container/flat_hash_set.h"
28#include "absl/flags/flag.h"
29#include "absl/functional/function_ref.h"
30#include "absl/log/check.h"
31#include "absl/strings/str_cat.h"
32#include "absl/strings/string_view.h"
33#include "absl/types/span.h"
34#include "google/protobuf/descriptor.h"
35#include "google/protobuf/message.h"
36#include "google/protobuf/text_format.h"
44 "DEBUG ONLY. When set to true, SolveCpModel() will dump its model "
45 "protos (original model, presolved model, mapping model) in text "
46 "format to 'FLAGS_cp_model_dump_prefix'{model|presolved_model|"
47 "mapping_model}.pb.txt.");
50ABSL_FLAG(std::string, cp_model_dump_prefix,
".\\",
51 "Prefix filename for all dumped files");
53ABSL_FLAG(std::string, cp_model_dump_prefix,
"/tmp/",
54 "Prefix filename for all dumped files");
58 "DEBUG ONLY. When set to true, solve will dump all "
59 "lns or objective_shaving submodels proto in text format to "
60 "'FLAGS_cp_model_dump_prefix'xxx.pb.txt.");
67template <
typename IntList>
68void AddIndices(
const IntList& indices, std::vector<int>* output) {
69 output->insert(output->end(), indices.begin(), indices.end());
75 gcd = std::gcd(gcd, std::abs(expr.
offset()));
76 for (
const int64_t coeff : expr.
coeffs()) {
77 gcd = std::gcd(gcd, std::abs(coeff));
84 if (divisor == 1)
return;
86 DCHECK_EQ(expr->
offset() % divisor, 0);
89 DCHECK_EQ(expr->
coeffs(
i) % divisor, 0);
96 output_negated_expr->
Clear();
111 std::vector<int>* variables,
112 std::vector<int>* literals) {
134 AddIndices(expr.vars(), variables);
140 AddIndices(expr.vars(), variables);
146 AddIndices(expr.vars(), variables);
153 AddIndices(expr.vars(), variables);
161 AddIndices(expr.vars(), variables);
179 AddIndices(expr.vars(), variables);
196 AddIndices(time.vars(), variables);
200 AddIndices(level.vars(), variables);
206 AddIndices(ct.
table().
vars(), variables);
209 AddIndices(expr.vars(), variables);
218 AddIndices(expr.vars(), variables);
234 AddIndices(demand.vars(), variables);
242#define APPLY_TO_SINGULAR_FIELD(ct_name, field_name) \
244 int temp = ct->mutable_##ct_name()->field_name(); \
246 ct->mutable_##ct_name()->set_##field_name(temp); \
249#define APPLY_TO_REPEATED_FIELD(ct_name, field_name) \
251 for (int& r : *ct->mutable_##ct_name()->mutable_##field_name()) f(&r); \
332 for (
int i = 0;
i < ct->
int_div().exprs_size(); ++
i) {
338 for (
int i = 0;
i < ct->
int_mod().exprs_size(); ++
i) {
344 for (
int i = 0;
i < ct->
lin_max().exprs_size(); ++
i) {
350 for (
int i = 0;
i < ct->
int_prod().exprs_size(); ++
i) {
358 for (
int i = 0;
i < ct->
all_diff().exprs_size(); ++
i) {
376 for (
int i = 0;
i < ct->
element().exprs_size(); ++
i) {
390 for (
int i = 0;
i < ct->
reservoir().time_exprs_size(); ++
i) {
393 for (
int i = 0;
i < ct->
reservoir().level_changes_size(); ++
i) {
401 for (
int i = 0;
i < ct->
table().exprs_size(); ++
i) {
410 for (
int i = 0;
i < ct->
automaton().exprs_size(); ++
i) {
496#undef APPLY_TO_SINGULAR_FIELD
497#undef APPLY_TO_REPEATED_FIELD
501 switch (constraint_case) {
509 return "kExactlyOne";
525 return "kDummyConstraint";
545 return "kNoOverlap2D";
547 return "kCumulative";
555 std::vector<int> result;
557 for (
int& ref : result) {
568 std::vector<int> used_intervals;
624 return used_intervals;
628 absl::Span<const int64_t>
solution) {
629 int64_t objective_value = 0;
631 int64_t coeff = objective.
coeffs(
i);
632 const int ref = objective.
vars(
i);
635 objective_value += coeff *
solution[var];
637 return objective_value;
642 std::abs(expr.
coeffs(0)) == 1;
663 DCHECK(!linear->
domain().empty());
664 const int64_t shift = coefficient * expr.
offset();
674 if (coeff == 0)
return;
688 for (
const int lit : literals) {
712 DCHECK(!linear->
domain().empty());
725 if (a.
vars_size() !=
b.vars_size())
return false;
726 if (a.
offset() !=
b.offset() * b_scaling)
return false;
727 absl::flat_hash_map<int, int64_t> coeffs;
730 coeffs[
b.vars(
i)] += -
b.coeffs(
i) * b_scaling;
733 for (
const auto [var, coeff] : coeffs) {
734 if (coeff != 0)
return false;
742 if (!lin.
vars().empty()) {
756 if (!ct.enforcement_literal().empty()) {
759 switch (ct.constraint_case()) {
843 ct.reservoir().level_changes()) {
848 if (!ct.table().vars().empty()) {
864 if (!ct.automaton().vars().empty()) {
922#if !defined(__PORTABLE_PLATFORM__)
933class InlineFieldPrinter
934 :
public google::protobuf::TextFormat::FastFieldValuePrinter {
935 void PrintMessageStart(
const google::protobuf::Message& ,
938 google::protobuf::TextFormat::BaseTextGenerator*
939 generator)
const override {
940 generator->PrintLiteral(
" { ");
944class InlineMessagePrinter
945 :
public google::protobuf::TextFormat::MessagePrinter {
947 InlineMessagePrinter() {
948 printer_.SetSingleLineMode(
true);
949 printer_.SetUseShortRepeatedPrimitives(
true);
952 void Print(
const google::protobuf::Message& message,
954 google::protobuf::TextFormat::BaseTextGenerator* generator)
957 printer_.PrintToString(message, &buffer_);
958 generator->Print(buffer_.data(), buffer_.size());
962 google::protobuf::TextFormat::Printer printer_;
963 mutable std::string buffer_;
968void RegisterFieldPrinters(
969 const google::protobuf::Descriptor* descriptor,
970 absl::flat_hash_set<const google::protobuf::Descriptor*>* descriptors,
971 google::protobuf::TextFormat::Printer* printer) {
973 if (!descriptors->insert(descriptor).second)
return;
975 for (
int i = 0;
i < descriptor->field_count(); ++
i) {
976 const google::protobuf::FieldDescriptor* field = descriptor->field(
i);
977 if (field->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE) {
980 printer->RegisterFieldValuePrinter(field,
new InlineFieldPrinter());
982 RegisterFieldPrinters(field->message_type(), descriptors, printer);
991 printer->SetUseShortRepeatedPrimitives(
true);
992 absl::flat_hash_set<const google::protobuf::Descriptor*> descriptors;
995 new InlineMessagePrinter());
997 new InlineMessagePrinter());
1002bool ModelHasOnlyClausesAndBooleanVariables(
const CpModelProto& cp_model,
1004 const int num_vars = cp_model.variables().size();
1006 for (
int v = 0; v < num_vars; ++v) {
1007 const auto& domain = cp_model.variables(v).domain();
1008 if (domain.size() != 2)
return false;
1009 const int64_t lb = domain.Get(0);
1010 const int64_t ub = domain.Get(1);
1012 if (lb != 0 && lb != 1)
return false;
1014 }
else if (lb != 0 || ub != 1) {
1022 *num_clauses += ct.bool_and().literals().size();
1032 int num_clauses = 0;
1033 if (!cp_model.has_objective())
return false;
1035 const double scaling = obj.
scaling_factor() == 0 ? 1.0 : obj.scaling_factor();
1036 if (std::round(scaling) != scaling)
return false;
1037 if (std::round(obj.offset()) != obj.offset())
return false;
1038 return ModelHasOnlyClausesAndBooleanVariables(cp_model, &num_clauses);
1041bool ModelIsPureSat(
const CpModelProto& cp_model,
int* num_clauses) {
1044 return ModelHasOnlyClausesAndBooleanVariables(cp_model, num_clauses);
1047void ConvertSatCpModelProtoToClauses(
1049 std::function<
void(
const std::vector<Literal>&)> add_clause) {
1050 const int num_vars = cp_model.variables().size();
1051 for (
int v = 0; v < num_vars; ++v) {
1052 const auto& domain = cp_model.variables(v).domain();
1053 const int64_t lb = domain.Get(0);
1054 const int64_t ub = domain.Get(1);
1056 add_clause({
Literal(BooleanVariable(v), lb == 1)});
1059 auto literal = [](
int lit) {
1062 std::vector<Literal> clause;
1066 for (
const int lit : ct.enforcement_literal()) {
1067 clause.push_back(literal(lit).Negated());
1069 for (
const int lit : ct.bool_or().literals()) {
1070 clause.push_back(literal(lit));
1074 for (
const int lit : ct.bool_and().literals()) {
1076 for (
const int lit : ct.enforcement_literal()) {
1077 clause.push_back(literal(lit).Negated());
1079 clause.push_back(literal(lit));
1090 const int num_vars = cp_model.
variables().size();
1091 int num_clauses = 0;
1092 if (!ModelIsPureSat(cp_model, &num_clauses))
return false;
1094 absl::StrAppend(out,
"p cnf ", num_vars,
" ", num_clauses,
"\n");
1095 ConvertSatCpModelProtoToClauses(
1096 cp_model, [&out](absl::Span<const Literal> clause) {
1097 for (
const Literal lit : clause) {
1098 absl::StrAppend(out, lit.SignedValue(),
" ");
1100 absl::StrAppend(out,
"0\n");
1108 if (!ModelIsMaxSat(cp_model))
return false;
1110 ConvertSatCpModelProtoToClauses(
1111 cp_model, [&out](
const std::vector<Literal>& clause) {
1112 absl::StrAppend(out,
"h ");
1113 for (
const Literal lit : clause) {
1114 absl::StrAppend(out, lit.SignedValue(),
" ");
1116 absl::StrAppend(out,
"0\n");
1135 for (
int i = 0;
i < obj.vars().size(); ++
i) {
1136 const int64_t opp_coeff = -obj.coeffs(
i);
1139 if (opp_coeff > 0) {
1140 absl::StrAppend(out, opp_coeff,
" ", lit.
SignedValue(),
" 0\n");
1141 }
else if (opp_coeff < 0) {
1176 return left_coeff == -right_coeff;
Domain AdditionWith(const Domain &domain) const
const ::operations_research::sat::LinearExpressionProto & exprs(int index) const
::int32_t vars(int index) const
const ::operations_research::sat::LinearExpressionProto & exprs(int index) const
::int32_t literals(int index) const
::int32_t literals(int index) const
const ::operations_research::sat::TableConstraintProto & table() const
const ::operations_research::sat::BoolArgumentProto & bool_xor() const
ConstraintCase constraint_case() const
const ::operations_research::sat::InverseConstraintProto & inverse() const
::operations_research::sat::CumulativeConstraintProto *PROTOBUF_NONNULL mutable_cumulative()
::int32_t enforcement_literal(int index) const
const ::operations_research::sat::BoolArgumentProto & exactly_one() const
const ::operations_research::sat::NoOverlapConstraintProto & no_overlap() const
const ::operations_research::sat::ListOfVariablesProto & dummy_constraint() const
const ::operations_research::sat::AllDifferentConstraintProto & all_diff() const
const ::operations_research::sat::LinearConstraintProto & linear() const
const ::operations_research::sat::BoolArgumentProto & at_most_one() const
const ::operations_research::sat::IntervalConstraintProto & interval() const
const ::operations_research::sat::RoutesConstraintProto & routes() const
const ::operations_research::sat::LinearArgumentProto & lin_max() const
const ::operations_research::sat::ElementConstraintProto & element() const
const ::operations_research::sat::BoolArgumentProto & bool_and() const
const ::operations_research::sat::BoolArgumentProto & bool_or() const
const ::operations_research::sat::LinearArgumentProto & int_mod() const
::google::protobuf::RepeatedField<::int32_t > *PROTOBUF_NONNULL mutable_enforcement_literal()
const ::operations_research::sat::LinearArgumentProto & int_prod() const
const ::operations_research::sat::LinearArgumentProto & int_div() const
const ::operations_research::sat::AutomatonConstraintProto & automaton() const
const ::operations_research::sat::CircuitConstraintProto & circuit() const
const ::operations_research::sat::CumulativeConstraintProto & cumulative() const
const ::operations_research::sat::ReservoirConstraintProto & reservoir() const
const ::operations_research::sat::NoOverlap2DConstraintProto & no_overlap_2d() const
bool has_solution_hint() const
bool has_floating_point_objective() const
static const ::google::protobuf::Descriptor *PROTOBUF_NONNULL descriptor()
const ::operations_research::sat::IntegerVariableProto & variables(int index) const
const ::operations_research::sat::FloatObjectiveProto & floating_point_objective() const
const ::operations_research::sat::ConstraintProto & constraints(int index) const
bool has_objective() const
const ::operations_research::sat::PartialVariableAssignment & solution_hint() const
const ::operations_research::sat::CpObjectiveProto & objective() const
::int64_t domain(int index) const
double scaling_factor() const
::int32_t vars(int index) const
::int64_t coeffs(int index) const
const ::operations_research::sat::LinearExpressionProto & demands(int index) const
::operations_research::sat::LinearExpressionProto *PROTOBUF_NONNULL mutable_demands(int index)
::int32_t intervals(int index) const
const ::operations_research::sat::LinearExpressionProto & capacity() const
const ::operations_research::sat::LinearExpressionProto & exprs(int index) const
const ::operations_research::sat::LinearExpressionProto & linear_target() const
bool has_linear_index() const
bool has_linear_target() const
::int32_t vars(int index) const
const ::operations_research::sat::LinearExpressionProto & linear_index() const
::int32_t vars(int index) const
double coeffs(int index) const
static const ::google::protobuf::Descriptor *PROTOBUF_NONNULL descriptor()
const ::operations_research::sat::LinearExpressionProto & size() const
const ::operations_research::sat::LinearExpressionProto & end() const
const ::operations_research::sat::LinearExpressionProto & start() const
::int32_t f_inverse(int index) const
::int32_t f_direct(int index) const
const ::operations_research::sat::LinearExpressionProto & exprs(int index) const
const ::operations_research::sat::LinearExpressionProto & target() const
::int32_t vars(int index) const
void add_vars(::int32_t value)
ABSL_ATTRIBUTE_REINITIALIZES void Clear() PROTOBUF_FINAL
void add_domain(::int64_t value)
void add_coeffs(::int64_t value)
::int64_t domain(int index) const
::int64_t coeffs(int index) const
ABSL_ATTRIBUTE_REINITIALIZES void Clear() PROTOBUF_FINAL
::google::protobuf::RepeatedField<::int32_t > *PROTOBUF_NONNULL mutable_vars()
::int32_t vars(int index) const
void set_offset(::int64_t value)
void add_coeffs(::int64_t value)
void set_coeffs(int index, ::int64_t value)
static const ::google::protobuf::Descriptor *PROTOBUF_NONNULL descriptor()
void add_vars(::int32_t value)
::int32_t vars(int index) const
::int32_t y_intervals(int index) const
::int32_t x_intervals(int index) const
::int32_t intervals(int index) const
::int64_t values(int index) const
::int32_t vars(int index) const
::int32_t active_literals(int index) const
const ::operations_research::sat::LinearExpressionProto & time_exprs(int index) const
const ::operations_research::sat::LinearExpressionProto & level_changes(int index) const
::int32_t literals(int index) const
::int32_t vars(int index) const
const ::operations_research::sat::LinearExpressionProto & exprs(int index) const
#define APPLY_TO_SINGULAR_FIELD(ct_name, field_name)
ABSL_FLAG(bool, cp_model_dump_models, false, "DEBUG ONLY. When set to true, SolveCpModel() will dump its model " "protos (original model, presolved model, mapping model) in text " "format to 'FLAGS_cp_model_dump_prefix'{model|presolved_model|" "mapping_model}.pb.txt.")
#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)
constexpr uint64_t kDefaultFingerprintSeed
uint64_t FingerprintRepeatedField(const google::protobuf::RepeatedField< T > &sequence, uint64_t seed)
void ApplyToAllVariableIndices(absl::FunctionRef< void(int *)> f, ConstraintProto *ct)
bool RefIsPositive(int ref)
bool LinearExpressionProtosAreEqual(const LinearExpressionProto &a, const LinearExpressionProto &b, int64_t b_scaling)
int64_t ComputeInnerObjective(const CpObjectiveProto &objective, absl::Span< const int64_t > solution)
bool ConvertCpModelProtoToWCnf(const CpModelProto &cp_model, std::string *out)
void ApplyToAllLiteralIndices(absl::FunctionRef< void(int *)> f, ConstraintProto *ct)
int CombineSeed(int base_seed, int64_t delta)
bool SafeAddLinearExpressionToLinearConstraint(const LinearExpressionProto &expr, int64_t coefficient, LinearConstraintProto *linear)
uint64_t FingerprintModel(const CpModelProto &model, uint64_t seed)
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)
bool ExpressionIsAffine(const LinearExpressionProto &expr)
std::vector< int > UsedVariables(const ConstraintProto &ct)
std::vector< int > UsedIntervals(const ConstraintProto &ct)
void LiteralsToLinear(absl::Span< const int > literals, int64_t lb, int64_t ub, LinearConstraintProto *linear)
void FillDomainInProto(const Domain &domain, ProtoWithDomain *proto)
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
void SetupTextFormatPrinter(google::protobuf::TextFormat::Printer *printer)
absl::string_view ConstraintCaseName(ConstraintProto::ConstraintCase constraint_case)
bool ExpressionContainsSingleRef(const LinearExpressionProto &expr)
int64_t LinearExpressionGcd(const LinearExpressionProto &expr, int64_t gcd)
void DivideLinearExpression(int64_t divisor, LinearExpressionProto *expr)
void AddLinearExpressionToLinearConstraint(const LinearExpressionProto &expr, int64_t coefficient, LinearConstraintProto *linear)
int GetSingleRefFromExpression(const LinearExpressionProto &expr)
bool IsAffineIntAbs(const ConstraintProto &ct)
void ApplyToAllIntervalIndices(absl::FunctionRef< void(int *)> f, ConstraintProto *ct)
IndexReferences GetReferencesUsedByConstraint(const ConstraintProto &ct)
void AddWeightedLiteralToLinearConstraint(int lit, int64_t coeff, LinearConstraintProto *linear, int64_t *offset)
bool AtMinOrMaxInt64(int64_t x)
Select next search node to expand Select next item_i to add this new search node to the search Generate a new search node where item_i is not in the knapsack Check validity of this new partial solution(using propagators) - If valid
ClosedInterval::Iterator end(ClosedInterval interval)
int64_t CapProd(int64_t x, int64_t y)
std::vector< int > variables
std::vector< int > literals