17#include "absl/flags/flag.h"
18#include "absl/flags/parse.h"
19#include "absl/flags/usage.h"
20#include "absl/log/check.h"
21#include "absl/log/flags.h"
22#include "absl/log/initialize.h"
23#include "absl/strings/match.h"
24#include "absl/strings/str_format.h"
25#include "absl/strings/string_view.h"
26#include "google/protobuf/arena.h"
27#include "google/protobuf/text_format.h"
33#include "ortools/sat/boolean_problem.pb.h"
34#include "ortools/sat/cp_model.pb.h"
40#include "ortools/sat/sat_parameters.pb.h"
45 std::string,
input,
"",
46 "Required: input file of the problem to solve. Many format are supported:"
47 ".cnf (sat, max-sat, weighted max-sat), .opb (pseudo-boolean sat/optim) "
48 "and by default the CpModelProto proto (binary or text).");
51 std::string, hint_file,
"",
52 "Protobuf file containing a CpModelResponse. The solution will be used as a"
53 " hint to bootstrap the search.");
56 "Protobuf file containing a CpModelResponse. If present, the "
57 "tightened models will be used to reduce the domain of variables.");
60 "If non-empty, write the response there. By default it uses the "
61 "binary format except if the file extension is '.txt'.");
64 "Parameters for the sat solver in a text format of the "
65 "SatParameters proto, example: --params=use_conflicts:true.");
68 "If true, when we add a slack variable to reify a soft clause, we "
69 "enforce the fact that when it is true, the clause must be false.");
70ABSL_FLAG(
bool, fingerprint_intermediate_solutions,
false,
71 "Attach the fingerprint of intermediate solutions to the output.");
77void TryToRemoveSuffix(absl::string_view suffix, std::string* str) {
81std::string ExtractName(absl::string_view full_filename) {
84 TryToRemoveSuffix(
"gz", &filename);
85 TryToRemoveSuffix(
"txt", &filename);
86 TryToRemoveSuffix(
"pb", &filename);
87 TryToRemoveSuffix(
"pbtxt", &filename);
88 TryToRemoveSuffix(
"proto", &filename);
89 TryToRemoveSuffix(
"prototxt", &filename);
90 TryToRemoveSuffix(
"textproto", &filename);
91 TryToRemoveSuffix(
"bin", &filename);
95bool LoadProblem(
const std::string& filename, absl::string_view hint_file,
96 absl::string_view domain_file, CpModelProto* cp_model) {
97 if (absl::EndsWith(filename,
".opb") ||
98 absl::EndsWith(filename,
".opb.bz2")) {
100 LinearBooleanProblem problem;
101 if (!reader.Load(filename, &problem)) {
102 LOG(FATAL) <<
"Cannot load file '" << filename <<
"'.";
105 }
else if (absl::EndsWith(filename,
".cnf") ||
106 absl::EndsWith(filename,
".cnf.xz") ||
107 absl::EndsWith(filename,
".cnf.gz") ||
108 absl::EndsWith(filename,
".wcnf") ||
109 absl::EndsWith(filename,
".wcnf.xz") ||
110 absl::EndsWith(filename,
".wcnf.gz")) {
111 SatCnfReader reader(absl::GetFlag(FLAGS_wcnf_use_strong_slack));
112 if (!reader.Load(filename, cp_model)) {
113 LOG(FATAL) <<
"Cannot load file '" << filename <<
"'.";
120 if (!hint_file.empty()) {
121 CpSolverResponse response;
123 if (!response.solution().empty()) {
124 CHECK_EQ(response.solution_size(), cp_model->variables_size())
125 <<
"The hint from the response proto is not compatible with the "
128 cp_model->clear_solution_hint();
129 for (
int i = 0;
i < cp_model->variables_size(); ++
i) {
130 cp_model->mutable_solution_hint()->add_vars(
i);
131 cp_model->mutable_solution_hint()->add_values(response.solution(
i));
134 LOG(INFO) <<
"The response proto has no solutions, ignoring.";
139 if (!domain_file.empty()) {
140 CpSolverResponse response;
142 if (!response.tightened_variables().empty()) {
143 CHECK_EQ(response.tightened_variables_size(), cp_model->variables_size())
144 <<
"The tighened variables from the response proto is not "
145 "compatible with the model proto";
147 for (
int i = 0;
i < cp_model->variables_size(); ++
i) {
148 IntegerVariableProto* var_proto = cp_model->mutable_variables(
i);
149 const Domain tightened_domain =
151 const Domain new_domain =
156 LOG(INFO) <<
"The response proto has no tightened variable domains, "
162 if (cp_model->name().empty()) {
163 cp_model->set_name(ExtractName(filename));
171 if (absl::GetFlag(FLAGS_input).empty()) {
172 LOG(FATAL) <<
"Please supply a data file with --input=";
177 if (!absl::GetFlag(FLAGS_params).empty()) {
178 CHECK(google::protobuf::TextFormat::MergeFromString(
180 << absl::GetFlag(FLAGS_params);
184 google::protobuf::Arena arena;
185 CpModelProto* cp_model =
186 google::protobuf::Arena::Create<CpModelProto>(&arena);
187 if (!LoadProblem(absl::GetFlag(FLAGS_input), absl::GetFlag(FLAGS_hint_file),
188 absl::GetFlag(FLAGS_domain_file), cp_model)) {
189 CpSolverResponse response;
190 response.set_status(CpSolverStatus::MODEL_INVALID);
196 if (absl::GetFlag(FLAGS_fingerprint_intermediate_solutions)) {
200 return absl::StrFormat(
207 if (!absl::GetFlag(FLAGS_output).empty()) {
208 if (absl::EndsWith(absl::GetFlag(FLAGS_output),
"txt")) {
219 if (response.status() == CpSolverStatus::OPTIMAL)
return 10;
220 if (response.status() == CpSolverStatus::FEASIBLE)
return 10;
221 if (response.status() == CpSolverStatus::INFEASIBLE)
return 20;
230 "Usage: see flags.\n"
231 "This program solves a given problem with the CP-SAT solver.";
233int main(
int argc,
char** argv) {
234 absl::InitializeLog();
235 absl::SetProgramUsageMessage(
kUsage);
236 absl::ParseCommandLine(argc, argv);
237 return operations_research::sat::Run();
Domain IntersectionWith(const Domain &domain) const
absl::Status SetTextProto(absl::string_view filename, const google::protobuf::Message &proto, Options options)
absl::string_view Extension(absl::string_view path)
absl::Status SetBinaryProto(absl::string_view filename, const google::protobuf::Message &proto, Options options)
absl::string_view Stem(absl::string_view path)
absl::string_view Basename(absl::string_view path)
std::function< SatParameters(Model *)> NewSatParameters(const std::string ¶ms)
constexpr uint64_t kDefaultFingerprintSeed
Default seed for fingerprints.
uint64_t FingerprintRepeatedField(const google::protobuf::RepeatedField< T > &sequence, uint64_t seed)
CpModelProto BooleanProblemToCpModelproto(const LinearBooleanProblem &problem)
void FillDomainInProto(const Domain &domain, ProtoWithDomain *proto)
Serializes a Domain into the domain field of a proto.
CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model)
std::function< void(Model *)> NewFeasibleSolutionLogCallback(const std::function< std::string(const CpSolverResponse &response)> &callback)
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
Reads a Domain from the domain field of a proto.
In SWIG mode, we don't want anything besides these top-level includes.
absl::Status ReadFileToProto(absl::string_view filename, google::protobuf::Message *proto, bool allow_partial)
static int input(yyscan_t yyscanner)
int main(int argc, char **argv)
ABSL_FLAG(std::string, input, "", "Required: input file of the problem to solve. Many format are supported:" ".cnf (sat, max-sat, weighted max-sat), .opb (pseudo-boolean sat/optim) " "and by default the CpModelProto proto (binary or text).")
static const char kUsage[]