30#include "absl/base/log_severity.h"
31#include "absl/flags/flag.h"
32#include "absl/log/check.h"
33#include "absl/log/globals.h"
34#include "absl/log/log.h"
35#include "absl/strings/match.h"
36#include "absl/strings/str_format.h"
37#include "absl/strings/string_view.h"
54ABSL_FLAG(std::string, output_dimacs,
"",
"Output problem as a dimacs file.");
55ABSL_FLAG(std::string, output_proto,
"",
"Output problem as a flow proto.");
56ABSL_FLAG(
bool, use_flow_graph,
true,
"Use special kind of graph.");
57ABSL_FLAG(
bool, sort_heads,
false,
"Sort outgoing arcs by head.");
58ABSL_FLAG(
bool, detect_reverse_arcs,
true,
"Detect reverse arcs.");
67 std::string* dimacs) {
70 dimacs->append(
"c Min-Cost flow problem generated from a FlowModelProto.\n");
73 int64_t num_nodes = 0;
74 for (int64_t i = 0; i < flow_model.
arcs_size(); ++i) {
75 num_nodes = std::max(num_nodes, flow_model.
arcs(i).
tail() + 1);
76 num_nodes = std::max(num_nodes, flow_model.
arcs(i).
head() + 1);
80 const int64_t num_arcs = flow_model.
arcs_size();
81 dimacs->append(
"c\nc Problem line (problem_type, num nodes, num arcs).\n");
82 dimacs->append(absl::StrFormat(
"p min %d %d\n", num_nodes, num_arcs));
85 dimacs->append(
"c\nc Node descriptor lines (id, supply/demand).\n");
86 for (int64_t i = 0; i < flow_model.
nodes_size(); ++i) {
87 const int64_t
id = flow_model.
nodes(i).
id() + 1;
88 const int64_t supply = flow_model.
nodes(i).
supply();
90 dimacs->append(absl::StrFormat(
"n %d %d\n",
id, supply));
96 "c\nc Arc descriptor Lines (tail, head, minflow, maxflow, cost).\n");
97 for (int64_t i = 0; i < flow_model.
arcs_size(); ++i) {
98 const int64_t tail = flow_model.
arcs(i).
tail() + 1;
99 const int64_t head = flow_model.
arcs(i).
head() + 1;
102 dimacs->append(absl::StrFormat(
"a %d %d %d %d %d\n", tail, head, int64_t{0},
103 capacity, unit_cost));
105 dimacs->append(
"c\n");
116 if (line.empty())
continue;
117 if (line[0] ==
'p') {
118 if (absl::StartsWith(line,
"p min")) {
120 }
else if (absl::StartsWith(line,
"p max")) {
123 LOG(ERROR) <<
"Unknown dimacs problem format.";
128 if (line[0] ==
'n') {
131 std::stringstream ss(line.substr(1));
132 switch (problem_type) {
139 supply = (type ==
"s" ? 1 : -1);
143 LOG(ERROR) <<
"Node line before the problem type definition.";
150 if (line[0] ==
'a') {
153 int64_t min_capacity = 0;
154 int64_t max_capacity = 0;
155 int64_t unit_cost = 0;
156 std::stringstream ss(line.substr(1));
157 switch (problem_type) {
159 ss >> tail >> head >> min_capacity >> max_capacity >> unit_cost;
162 ss >> tail >> head >> max_capacity;
165 LOG(ERROR) <<
"Arc line before the problem type definition.";
173 if (min_capacity != 0) {
174 LOG(ERROR) <<
"We do not support minimum capacity.";
187 double* solving_time) {
192 int64_t num_nodes = 0;
193 for (
int i = 0; i < flow_model.
arcs_size(); ++i) {
194 num_nodes = std::max(num_nodes, flow_model.
arcs(i).
tail() + 1);
195 num_nodes = std::max(num_nodes, flow_model.
arcs(i).
head() + 1);
200 for (
int i = 0; i < flow_model.
arcs_size(); ++i) {
203 std::vector<Graph::ArcIndex> permutation;
204 graph.
Build(&permutation);
206 absl::PrintF(
"%d,", graph.
num_arcs());
209 for (
int i = 0; i < flow_model.
arcs_size(); ++i) {
210 const Graph::ArcIndex image = i < permutation.size() ? permutation[i] : i;
214 for (
int i = 0; i < flow_model.
nodes_size(); ++i) {
219 *loading_time = timer.
Get();
220 absl::PrintF(
"%f,", *loading_time);
224 CHECK(min_cost_flow.
Solve());
226 *solving_time = timer.
Get();
227 absl::PrintF(
"%f,", *solving_time);
233template <
typename GraphType>
236 double* solving_time,
237 std::function<
void(GraphType* graph)> configure_graph_options =
nullptr) {
243 for (
int i = 0; i < flow_model.
arcs_size(); ++i) {
246 std::vector<typename GraphType::ArcIndex> permutation;
248 if (configure_graph_options !=
nullptr) {
249 configure_graph_options(&graph);
251 graph.Build(&permutation);
253 absl::PrintF(
"%d,", graph.num_nodes());
254 absl::PrintF(
"%d,", graph.num_arcs());
257 typename GraphType::NodeIndex source = -1;
258 typename GraphType::NodeIndex sink = -1;
260 for (
int i = 0; i < flow_model.
nodes_size(); ++i) {
262 source = flow_model.
nodes(i).
id();
265 sink = flow_model.
nodes(i).
id();
268 CHECK_NE(source, -1);
273 for (
int i = 0; i < flow_model.
arcs_size(); ++i) {
274 const typename GraphType::ArcIndex image =
275 i < permutation.size() ? permutation[i] : i;
279 *loading_time = timer.
Get();
280 absl::PrintF(
"%f,", *loading_time);
284 CHECK(max_flow.
Solve());
286 *solving_time = timer.
Get();
287 absl::PrintF(
"%f,", *solving_time);
299int main(
int argc,
char** argv) {
301 "Runs the OR-tools min-cost flow on a pattern of files given by --input. "
302 "The files must be in Dimacs text format or in binary FlowModelProto "
305 absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
306 if (absl::GetFlag(FLAGS_input).empty()) {
307 LOG(FATAL) <<
"Please specify input pattern via --input=...";
309 std::vector<std::string> file_list;
318 "file_name, parsing_time, num_nodes, num_arcs,loading_time, "
319 "solving_time, optimal_cost\n");
320 for (
int i = 0; i < file_list.size(); ++i) {
321 const std::string file_name = file_list[i];
326 double parsing_time = 0;
328 if (absl::EndsWith(file_name,
".bin") ||
329 absl::EndsWith(file_name,
".bin.gz")) {
331 if (absl::EndsWith(file_name,
"gz")) {
332 std::string raw_data;
334 CHECK_OK(StringToProto(raw_data, &proto));
340 if (!ConvertDimacsToFlowModel(file_name, &proto))
continue;
342 absl::PrintF(
"%f,", parsing_time);
345 if (!absl::GetFlag(FLAGS_output_proto).empty()) {
346 LOG(INFO) <<
"Dumping binary proto to '"
347 << absl::GetFlag(FLAGS_output_proto) <<
"'.";
353 if (!absl::GetFlag(FLAGS_output_dimacs).empty()) {
354 LOG(INFO) <<
"Converting first input file to dimacs format.";
359 ConvertFlowModelToDimacs(proto, &dimacs);
363 LOG(INFO) <<
"Done: " << time <<
"s.";
367 double loading_time = 0;
368 double solving_time = 0;
374 if (absl::GetFlag(FLAGS_use_flow_graph)) {
376 proto, &loading_time, &solving_time,
378 graph->SetDetectReverse(
379 absl::GetFlag(FLAGS_detect_reverse_arcs));
380 graph->SetSortByHead(absl::GetFlag(FLAGS_sort_heads));
388 LOG(ERROR) <<
"Problem type not supported: " << proto.
problem_type();
396 absl::PrintF(
"%s", parsing_time_distribution.
StatString());
397 absl::PrintF(
"%s", loading_time_distribution.
StatString());
398 absl::PrintF(
"%s", solving_time_distribution.
StatString());
static constexpr ProblemType MIN_COST_FLOW
static constexpr ProblemType MAX_FLOW
void Start()
When Start() is called multiple times, only the most recent is used.
::int64_t unit_cost() const
void set_capacity(::int64_t value)
void set_unit_cost(::int64_t value)
void set_head(::int64_t value)
void set_tail(::int64_t value)
::int64_t capacity() const
::operations_research::FlowNodeProto *PROTOBUF_NONNULL add_nodes()
::operations_research::FlowModelProto_ProblemType problem_type() const
const ::operations_research::FlowNodeProto & nodes(int index) const
void set_problem_type(::operations_research::FlowModelProto_ProblemType value)
int arcs_size() const
repeated .operations_research.FlowArcProto arcs = 2;
ABSL_ATTRIBUTE_REINITIALIZES void Clear() PROTOBUF_FINAL
::operations_research::FlowArcProto *PROTOBUF_NONNULL add_arcs()
const ::operations_research::FlowArcProto & arcs(int index) const
static constexpr ProblemType MIN_COST_FLOW
static constexpr ProblemType MAX_FLOW
FlowModelProto_ProblemType ProblemType
nested types -------------------------------------------------—
int nodes_size() const
repeated .operations_research.FlowNodeProto nodes = 1;
void set_supply(::int64_t value)
void set_id(::int64_t value)
bool Solve()
Returns true if a maximum flow was solved.
FlowSumType GetOptimalFlow() const
Returns the total flow found by the algorithm.
void SetArcCapacity(ArcIndex arc, ArcFlowType new_capacity)
void SetArcUnitCost(ArcIndex arc, ArcScaledCostType unit_cost)
Sets the unit cost for the given arc.
bool Solve()
Solves the problem, returning true if a min-cost flow could be found.
void SetArcCapacity(ArcIndex arc, ArcFlowType new_capacity)
Sets the capacity for the given arc.
void SetNodeSupply(NodeIndex node, FlowQuantity supply)
CostValue GetOptimalCost()
std::string StatString() const
void AddTimeInSec(double seconds)
Adds a time in seconds to this distribution.
NodeIndexType num_nodes() const
ArcIndexType num_arcs() const
Returns the number of valid arcs in the graph.
ArcIndexType AddArc(NodeIndexType tail, NodeIndexType head)
void InitGoogle(absl::string_view usage, int *argc, char ***argv, bool deprecated)
absl::StatusOr< std::string > GetContents(absl::string_view path, Options options)
-— Content API -—
absl::Status SetBinaryProto(absl::string_view file_name, const google::protobuf::Message &proto, Options options)
absl::Status Match(std::string_view pattern, std::vector< std::string > *result, const file::Options &options)
absl::Status GetBinaryProto(const absl::string_view file_name, google::protobuf::Message *proto, Options options)
absl::string_view Basename(absl::string_view path)
absl::Status SetContents(absl::string_view file_name, absl::string_view contents, Options options)
In SWIG mode, we don't want anything besides these top-level includes.
void ConvertFlowModelToDimacs(const FlowModelProto &flow_model, std::string *dimacs)
bool ConvertDimacsToFlowModel(absl::string_view file, FlowModelProto *flow_model)
void SolveMinCostFlow(const FlowModelProto &flow_model, double *loading_time, double *solving_time)
Loads a FlowModelProto proto into the MinCostFlow class and solves it.
util::ReverseArcStaticGraph Graph
Type of graph to use.
void SolveMaxFlow(const FlowModelProto &flow_model, double *loading_time, double *solving_time, std::function< void(GraphType *graph)> configure_graph_options=nullptr)
Loads a FlowModelProto proto into the MaxFlow class and solves it.
static int input(yyscan_t yyscanner)
int main(int argc, char **argv)
void SolveMinCostFlow(const FlowModelProto &flow_model, double *loading_time, double *solving_time)
Loads a FlowModelProto proto into the MinCostFlow class and solves it.
ABSL_FLAG(std::string, input, "", "Input file of the problem.")
void SolveMaxFlow(const FlowModelProto &flow_model, double *loading_time, double *solving_time, std::function< void(GraphType *graph)> configure_graph_options=nullptr)
Loads a FlowModelProto proto into the MaxFlow class and solves it.