Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
file_format_flags.cc
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <optional>
17#include <ostream>
18#include <string>
19#include <utility>
20#include <vector>
21
22#include "absl/algorithm/container.h"
23#include "absl/container/flat_hash_map.h"
24#include "absl/status/status.h"
25#include "absl/status/statusor.h"
26#include "absl/strings/match.h"
27#include "absl/strings/str_cat.h"
28#include "absl/strings/str_join.h"
29#include "absl/strings/string_view.h"
30#include "absl/types/span.h"
35#include "ortools/linear_solver/linear_solver.pb.h"
40#include "ortools/math_opt/model.pb.h"
41#include "ortools/math_opt/model_parameters.pb.h"
42
44
45absl::Span<const FileFormat> AllFileFormats() {
46 static constexpr FileFormat kValues[] = {
47 FileFormat::kMathOptBinary,
48 FileFormat::kMathOptText,
49 FileFormat::kLinearSolverBinary,
50 FileFormat::kLinearSolverText,
51 FileFormat::kMPS,
52 FileFormat::kLP,
53 };
54 return absl::MakeConstSpan(kValues);
55}
56
57std::string AbslUnparseFlag(const FileFormat f) {
58 switch (f) {
59 case FileFormat::kMathOptBinary:
60 return "mathopt";
61 case FileFormat::kMathOptText:
62 return "mathopt_txt";
63 case FileFormat::kLinearSolverBinary:
64 return "linear_solver";
65 case FileFormat::kLinearSolverText:
66 return "linear_solver_txt";
67 case FileFormat::kMPS:
68 return "mps";
69 case FileFormat::kLP:
70 return "lp";
71 }
72}
73
74std::ostream& operator<<(std::ostream& out, const FileFormat f) {
75 out << AbslUnparseFlag(f);
76 return out;
77}
78
79bool AbslParseFlag(const absl::string_view text, FileFormat* const f,
80 std::string* const error) {
81 for (const FileFormat candidate : AllFileFormats()) {
82 if (text == AbslUnparseFlag(candidate)) {
83 *f = candidate;
84 return true;
85 }
86 }
87
88 absl::StrAppend(error, "not a known value");
89 return false;
90}
91
92absl::flat_hash_map<absl::string_view, FileFormat> ExtensionToFileFormat() {
93 return {
94 {".pb", FileFormat::kMathOptBinary},
95 {".proto", FileFormat::kMathOptBinary},
96 {".pb.txt", FileFormat::kMathOptText},
97 {".pbtxt", FileFormat::kMathOptText},
98 {".textproto", FileFormat::kMathOptText},
99 {".mps", FileFormat::kMPS},
100 {".mps.gz", FileFormat::kMPS},
101 {".lp", FileFormat::kLP},
102 };
103}
104
105std::optional<FileFormat> FormatFromFilePath(absl::string_view file_path) {
106 const absl::flat_hash_map<absl::string_view, FileFormat> extensions =
108
109 // Sort extensions in reverse lexicographic order. The point here would be to
110 // consider ".pb.txt" before we text for ".txt".
111 using ExtensionPair = std::pair<absl::string_view, FileFormat>;
112 std::vector<ExtensionPair> sorted_extensions(extensions.begin(),
113 extensions.end());
114 absl::c_sort(sorted_extensions,
115 [](const ExtensionPair& lhs, const ExtensionPair& rhs) {
116 return lhs > rhs;
117 });
118
119 for (const auto& [extension, format] : sorted_extensions) {
120 if (absl::EndsWith(file_path, extension)) {
121 return format;
122 }
123 }
124 return std::nullopt;
125}
126
127std::optional<FileFormat> FormatFromFlagOrFilePath(
128 const std::optional<FileFormat> format_flag_value,
129 const absl::string_view file_path) {
130 if (format_flag_value.has_value()) {
131 return *format_flag_value;
132 }
133 return FormatFromFilePath(file_path);
134}
135
136namespace {
137
138constexpr absl::string_view kListLinePrefix = "* ";
139constexpr absl::string_view kSubListLinePrefix = " - ";
140
141} // namespace
142
144 // Get the lines for each format and the introduction doc.
145 std::string list = FormatFlagPossibleValuesList();
146
147 // Add the doc of what happen when format is not specified.
148 absl::StrAppend(&list, "\n", kListLinePrefix, "<unset>",
149 ": to guess the format from the file extension:");
150
151 // Builds a map from formats to their extensions.
152 absl::flat_hash_map<FileFormat, std::vector<absl::string_view>>
153 format_extensions;
154 for (const auto& [extension, format] : ExtensionToFileFormat()) {
155 format_extensions[format].push_back(extension);
156 }
157 for (auto& [format, extensions] : format_extensions) {
158 absl::c_sort(extensions);
159 }
160
161 // Here we iterate on all formats so that we list them in the same order as in
162 // the enum.
163 for (const FileFormat format : AllFileFormats()) {
164 // Here we use operator[] as it is not an issue to create new empty entries
165 // in the map.
166 const std::vector<absl::string_view>& extensions =
167 format_extensions[format];
168 if (extensions.empty()) {
169 continue;
170 }
171
172 absl::StrAppend(&list, "\n", kSubListLinePrefix,
173 absl::StrJoin(extensions, ", "), ": ",
174 AbslUnparseFlag(format));
175 }
176 return list;
177}
178
180 const absl::flat_hash_map<FileFormat, absl::string_view> format_help = {
181 {FileFormat::kMathOptBinary, "for a MathOpt ModelProto in binary"},
182 {FileFormat::kMathOptText, "when the proto is in text"},
183 {FileFormat::kLinearSolverBinary,
184 "for a LinearSolver MPModelProto in binary"},
185 {FileFormat::kLinearSolverText, "when the proto is in text"},
186 {FileFormat::kMPS, "for MPS file (which can be GZiped)"},
187 {FileFormat::kLP, " for LP file"},
188 };
189 std::string list;
190 for (const FileFormat format : AllFileFormats()) {
191 absl::StrAppend(&list, "\n", kListLinePrefix, AbslUnparseFlag(format), ": ",
192 format_help.at(format));
193 }
194 return list;
195}
196
197absl::StatusOr<std::pair<ModelProto, std::optional<SolutionHintProto>>>
198ReadModel(const absl::string_view file_path, const FileFormat format) {
199 switch (format) {
200 case FileFormat::kMathOptBinary: {
202 file_path, file::Defaults()));
203 return std::make_pair(std::move(model), std::nullopt);
204 }
205 case FileFormat::kMathOptText: {
207 file_path, file::Defaults()));
208 return std::make_pair(std::move(model), std::nullopt);
209 }
210 case FileFormat::kLinearSolverBinary:
211 case FileFormat::kLinearSolverText: {
213 const MPModelProto linear_solver_model,
214 format == FileFormat::kLinearSolverBinary
217 ASSIGN_OR_RETURN(ModelProto model,
218 MPModelProtoToMathOptModel(linear_solver_model));
220 std::optional<SolutionHintProto> hint,
221 MPModelProtoSolutionHintToMathOptHint(linear_solver_model));
222 return std::make_pair(std::move(model), std::move(hint));
223 }
224 case FileFormat::kMPS: {
225 ASSIGN_OR_RETURN(ModelProto model, ReadMpsFile(file_path));
226 return std::make_pair(std::move(model), std::nullopt);
227 }
228 case FileFormat::kLP: {
229 ASSIGN_OR_RETURN(const std::string lp_data,
230 file::GetContents(file_path, file::Defaults()));
231 ASSIGN_OR_RETURN(ModelProto model, ModelProtoFromLp(lp_data));
232 return std::make_pair(std::move(model), std::nullopt);
233 }
234 }
235}
236
237absl::Status WriteModel(const absl::string_view file_path,
238 const ModelProto& model_proto,
239 const std::optional<SolutionHintProto>& hint_proto,
240 const FileFormat format) {
241 switch (format) {
242 case FileFormat::kMathOptBinary:
243 return file::SetBinaryProto(file_path, model_proto, file::Defaults());
244 case FileFormat::kMathOptText:
245 return file::SetTextProto(file_path, model_proto, file::Defaults());
246 case FileFormat::kLinearSolverBinary:
247 case FileFormat::kLinearSolverText: {
248 ASSIGN_OR_RETURN(const MPModelProto linear_solver_model,
249 MathOptModelToMPModelProto(model_proto));
250 if (hint_proto.has_value()) {
251 LOG(WARNING) << "support for converting a MathOpt hint to MPModelProto "
252 "is not yet supported thus the hint has been lost";
253 }
254 return format == FileFormat::kLinearSolverBinary
255 ? file::SetBinaryProto(file_path, linear_solver_model,
257 : file::SetTextProto(file_path, linear_solver_model,
259 }
260 case FileFormat::kMPS: {
261 ASSIGN_OR_RETURN(const std::string mps_data,
262 ModelProtoToMps(model_proto));
263 return file::SetContents(file_path, mps_data, file::Defaults());
264 }
265 case FileFormat::kLP: {
266 ASSIGN_OR_RETURN(const std::string lp_data, ModelProtoToLp(model_proto));
267 return file::SetContents(file_path, lp_data, file::Defaults());
268 }
269 }
270}
271
272} // namespace operations_research::math_opt
#define ASSIGN_OR_RETURN(lhs, rexpr)
* FileFormat
GRBmodel * model
std::optional< ModelSolveParameters::SolutionHint > hint
absl::Status SetTextProto(absl::string_view filename, const google::protobuf::Message &proto, Options options)
Definition file.cc:337
absl::StatusOr< std::string > GetContents(absl::string_view path, Options options)
Definition file.cc:191
absl::Status SetBinaryProto(absl::string_view filename, const google::protobuf::Message &proto, Options options)
Definition file.cc:360
absl::Status SetContents(absl::string_view filename, absl::string_view contents, Options options)
Definition file.cc:242
Options Defaults()
Definition file.h:109
absl::Status GetTextProto(absl::string_view filename, google::protobuf::Message *proto, Options options)
Definition file.cc:327
absl::Status GetBinaryProto(const absl::string_view filename, google::protobuf::Message *proto, Options options)
Definition file.cc:348
An object oriented wrapper for quadratic constraints in ModelStorage.
Definition gurobi_isv.cc:28
std::optional< FileFormat > FormatFromFlagOrFilePath(const std::optional< FileFormat > format_flag_value, const absl::string_view file_path)
absl::StatusOr< std::string > ModelProtoToLp(const ModelProto &model)
bool AbslParseFlag(const absl::string_view text, SolverType *const value, std::string *const error)
absl::StatusOr< std::optional< SolutionHintProto > > MPModelProtoSolutionHintToMathOptHint(const MPModelProto &model)
absl::flat_hash_map< absl::string_view, FileFormat > ExtensionToFileFormat()
std::ostream & operator<<(std::ostream &ostr, const IndicatorConstraint &constraint)
absl::StatusOr<::operations_research::MPModelProto > MathOptModelToMPModelProto(const ::operations_research::math_opt::ModelProto &model)
std::string OptionalFormatFlagPossibleValuesList()
absl::Status WriteModel(const absl::string_view file_path, const ModelProto &model_proto, const std::optional< SolutionHintProto > &hint_proto, const FileFormat format)
absl::StatusOr< ModelProto > ReadMpsFile(const absl::string_view filename)
absl::StatusOr< std::string > ModelProtoToMps(const ModelProto &model)
absl::StatusOr< std::pair< ModelProto, std::optional< SolutionHintProto > > > ReadModel(const absl::string_view file_path, const FileFormat format)
absl::StatusOr<::operations_research::math_opt::ModelProto > MPModelProtoToMathOptModel(const ::operations_research::MPModelProto &model)
absl::StatusOr< ModelProto > ModelProtoFromLp(const absl::string_view lp_data)
Definition lp_parser.cc:52
std::optional< FileFormat > FormatFromFilePath(absl::string_view file_path)
std::string AbslUnparseFlag(const SolverType value)
absl::Span< const FileFormat > AllFileFormats()