35 #include "absl/flags/flag.h"
36 #include "absl/status/status.h"
37 #include "absl/status/statusor.h"
38 #include "absl/strings/match.h"
39 #include "absl/strings/str_cat.h"
40 #include "absl/strings/str_join.h"
41 #include "absl/strings/string_view.h"
42 #include "absl/time/time.h"
43 #include "google/protobuf/text_format.h"
55 #include "ortools/math_opt/parameters.pb.h"
66 inline constexpr absl::string_view
kPbExt =
".pb";
67 inline constexpr absl::string_view
kProtoExt =
".proto";
68 inline constexpr absl::string_view
kPbTxtExt =
".pb.txt";
70 inline constexpr absl::string_view
kMPSExt =
".mps";
75 struct SolverTypeProtoFormatter {
77 std::string*
const out,
78 const operations_research::math_opt::SolverTypeProto solver_type) {
86 "the file containing the model to solve; use --format to specify the "
89 std::string, format,
"auto",
91 "the format of the --input_file; possible values:\n",
98 ": for a LinearSolver MPModelProto in binary\n",
102 "* ",
kMPSFormat,
": for MPS file (which can be GZiped)\n",
104 "* ",
kAutoFormat,
": to guess the format from the file extension:\n",
113 std::vector<std::string>, update_files, {},
115 "the file containing ModelUpdateProto to apply to the --input_file; "
116 "when this flag is used, the --format must be either ",
122 "the solver to use, possible values: ",
125 ->RegisteredSolvers(),
126 ", ", SolverTypeProtoFormatter())));
128 "SolveParameters in text-proto format. Note that the time limit is "
129 "overridden by the --time_limit flag.");
131 "use a message callback to print the solver convergence logs");
133 "the time limit to use for the solve");
136 "use the names in the input models; ignoring names is useful when "
137 "the input contains duplicates");
139 "prints statistics about the ranges of the model values");
140 ABSL_FLAG(
bool, print_model,
false,
"prints the model to stdout");
148 std::optional<absl::string_view> FormatFromFilePath(
149 const absl::string_view file_path) {
150 const std::vector<std::pair<absl::string_view, absl::string_view>>
151 extension_to_format = {
157 for (
const auto& [ext, format] : extension_to_format) {
158 if (absl::EndsWith(file_path, ext)) {
169 absl::StatusOr<ModelProto> ReadModel(
const absl::string_view file_path,
170 const absl::string_view format) {
172 return file::GetBinaryProto<ModelProto>(file_path,
file::Defaults());
175 return file::GetTextProto<ModelProto>(file_path,
file::Defaults());
180 MPModelProto linear_solver_model,
189 LOG(QFATAL) <<
"Unsupported value of --format: " << format;
195 absl::StatusOr<ModelUpdateProto> ReadModelUpdate(
196 const absl::string_view file_path,
const absl::string_view format) {
198 return file::GetBinaryProto<ModelUpdateProto>(file_path,
file::Defaults());
201 return file::GetTextProto<ModelUpdateProto>(file_path,
file::Defaults());
203 return absl::InternalError(
204 absl::StrCat(
"invalid format in ReadModelUpdate(): ", format));
208 absl::Status PrintSummary(
const SolveResult& result) {
209 std::cout <<
"Solve finished:\n"
210 <<
" termination: " << result.termination <<
"\n"
211 <<
" solve time: " << result.solve_stats.solve_time
212 <<
"\n best primal bound: " << result.solve_stats.best_primal_bound
213 <<
"\n best dual bound: " << result.solve_stats.best_dual_bound
215 if (result.solutions.empty()) {
216 std::cout <<
" no solution" << std::endl;
218 for (
int i = 0; i < result.solutions.size(); ++i) {
219 const Solution& solution = result.solutions[i];
220 std::cout <<
" solution #" << (i + 1) <<
" objective: ";
221 if (solution.primal_solution.has_value()) {
222 std::cout << solution.primal_solution->objective_value;
226 std::cout << std::endl;
229 return absl::OkStatus();
232 absl::Status RunSolver() {
233 const std::string input_file_path = absl::GetFlag(FLAGS_input_file);
234 if (input_file_path.empty()) {
235 LOG(QFATAL) <<
"The flag --input_file is mandatory.";
239 std::string format = absl::GetFlag(FLAGS_format);
241 const std::optional<absl::string_view> guessed_format =
242 FormatFromFilePath(input_file_path);
243 if (!guessed_format) {
244 LOG(QFATAL) <<
"Can't guess the format from the file extension, please "
245 "use --format to specify the file format explicitly.";
247 format = *guessed_format;
252 const std::vector<std::string> update_file_paths =
253 absl::GetFlag(FLAGS_update_files);
256 LOG(QFATAL) <<
"Can't use --update_files with a input of format " << format
261 ReadModel(input_file_path, format),
262 _ <<
"failed to read " << input_file_path);
264 std::vector<ModelUpdateProto> model_updates;
265 for (
const std::string& update_file_path : update_file_paths) {
267 ReadModelUpdate(update_file_path, format));
268 model_updates.emplace_back(std::move(update));
271 if (!absl::GetFlag(FLAGS_names)) {
273 for (ModelUpdateProto& update : model_updates) {
281 for (
int u = 0; u < model_updates.size(); ++u) {
282 const ModelUpdateProto& update = model_updates[u];
284 <<
"failed to apply the update file: " << update_file_paths[u];
287 if (absl::GetFlag(FLAGS_ranges)) {
288 std::cout <<
"Ranges of finite non-zero values in the model:\n"
293 if (absl::GetFlag(FLAGS_print_model)) {
299 SolveParameters solve_parameters = absl::GetFlag(FLAGS_solve_parameters);
300 solve_parameters.time_limit = absl::GetFlag(FLAGS_time_limit);
301 SolveArguments solve_args = {.parameters = solve_parameters};
302 if (absl::GetFlag(FLAGS_solver_logs)) {
306 const SolveResult result,
307 Solve(*
model, absl::GetFlag(FLAGS_solver_type), solve_args),
308 _ <<
"the solver failed");
312 return absl::OkStatus();
319 int main(
int argc,
char* argv[]) {
322 const absl::Status
status = operations_research::math_opt::RunSolver();
#define ASSIGN_OR_RETURN(lhs, rexpr)
#define RETURN_IF_ERROR(expr)
static AllSolversRegistry * Instance()
static absl::StatusOr< std::unique_ptr< Model > > FromModelProto(const ModelProto &model_proto)
CpModelProto const * model_proto
ModelSharedTimeLimit * time_limit
void InitGoogle(const char *usage, int *argc, char ***argv, bool deprecated)
constexpr absl::string_view kMathOptTextFormat
int main(int argc, char *argv[])
constexpr absl::string_view kPbExt
constexpr absl::string_view kMathOptBinaryFormat
constexpr absl::string_view kMPSGzipExt
constexpr absl::string_view kMPSExt
constexpr absl::string_view kAutoFormat
constexpr absl::string_view kMPSFormat
constexpr absl::string_view kLinearSolverTextFormat
constexpr absl::string_view kTextProtoExt
ABSL_FLAG(std::string, input_file, "", "the file containing the model to solve; use --format to specify the " "file format")
constexpr absl::string_view kProtoExt
constexpr absl::string_view kLinearSolverBinaryFormat
constexpr absl::string_view kPbTxtExt
absl::string_view EnumToString(const E value)
void RemoveNames(ModelProto &model)
absl::StatusOr< SolveResult > Solve(const Model &model, const SolverType solver_type, const SolveArguments &solve_args, const SolverInitArguments &init_args)
MessageCallback PrinterMessageCallback(std::ostream &output_stream, const absl::string_view prefix)
absl::StatusOr<::operations_research::math_opt::ModelProto > MPModelProtoToMathOptModel(const ::operations_research::MPModelProto &model)
absl::StatusOr< ModelProto > ReadMpsFile(const absl::string_view filename)
ModelRanges ComputeModelRanges(const Model &model)
std::optional< typename EnumProto< P >::Cpp > EnumFromProto(const P proto_value)
Collection of objects used to extend the Constraint Solver library.
#define OR_ASSIGN_OR_RETURN3(lhs, rexpr, error_expression)