00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "cpp/parse_dimacs_assignment.h"
00015
00016 #include <algorithm>
00017 #include <cstdio>
00018 #include <cstring>
00019 #include <string>
00020
00021 #include "base/callback.h"
00022 #include "base/commandlineflags.h"
00023 #include "base/logging.h"
00024 #include "base/scoped_ptr.h"
00025 #include "graph/ebert_graph.h"
00026 #include "graph/linear_assignment.h"
00027
00028 DEFINE_bool(assignment_maximize_cost, false,
00029 "Negate costs so a max-cost assignment is found.");
00030 DEFINE_bool(assignment_optimize_layout, true,
00031 "Optimize graph layout for speed.");
00032
00033 namespace operations_research {
00034
00035 struct ParserState {
00036 ParserState()
00037 : bad(false),
00038 expect_last_line(false),
00039 nodes_described(false),
00040 reason(NULL),
00041 num_left_nodes(0) { }
00042 bool bad;
00043 bool expect_last_line;
00044 bool nodes_described;
00045 const char* reason;
00046 NodeIndex num_left_nodes;
00047 scoped_ptr<string> bad_line;
00048 };
00049
00050 static void ParseProblemLine(const char* line,
00051 ParserState* state,
00052 ForwardStarGraph** graph) {
00053 static const char* kIncorrectProblemLine =
00054 "Incorrect assignment problem line.";
00055 static const char* kAssignmentProblemType = "asn";
00056 char problem_type[4];
00057 NodeIndex num_nodes;
00058 ArcIndex num_arcs;
00059
00060 if ((sscanf(line, "%*c%3s%d%d",
00061 problem_type,
00062 &num_nodes,
00063 &num_arcs) != 3) ||
00064 (strncmp(kAssignmentProblemType,
00065 problem_type,
00066 strlen(kAssignmentProblemType)) != 0)) {
00067 state->bad = true;
00068 state->reason = kIncorrectProblemLine;
00069 state->bad_line.reset(new string(line));
00070 return;
00071 }
00072
00073 *graph = new ForwardStarGraph(num_nodes, num_arcs);
00074 }
00075
00076 static void ParseNodeLine(const char* line,
00077 ParserState* state) {
00078 NodeIndex node_id;
00079 if (sscanf(line, "%*c%d", &node_id) != 1) {
00080 state->bad = true;
00081 state->reason = "Syntax error in node desciption.";
00082 state->bad_line.reset(new string(line));
00083 return;
00084 }
00085 if (state->nodes_described) {
00086 state->bad = true;
00087 state->reason = "All node description must precede first arc description.";
00088 state->bad_line.reset(new string(line));
00089 return;
00090 }
00091 state->num_left_nodes = ::std::max(state->num_left_nodes, node_id);
00092 }
00093
00094 static void ParseArcLine(
00095 const char* line,
00096 ParserState* state,
00097 ForwardStarGraph* graph,
00098 LinearSumAssignment<ForwardStarGraph>** assignment) {
00099 if (graph == NULL) {
00100 state->bad = true;
00101 state->reason =
00102 "Problem specification line must precede any arc specification.";
00103 state->bad_line.reset(new string(line));
00104 return;
00105 }
00106 if (!state->nodes_described) {
00107 state->nodes_described = true;
00108 DCHECK(*assignment == NULL);
00109 *assignment = new LinearSumAssignment<ForwardStarGraph>(
00110 *graph, state->num_left_nodes);
00111 }
00112 NodeIndex tail;
00113 NodeIndex head;
00114 CostValue cost;
00115 if (sscanf(line, "%*c%d%d%lld", &tail, &head, &cost) != 3) {
00116 state->bad = true;
00117 state->reason = "Syntax error in arc descriptor.";
00118 state->bad_line.reset(new string(line));
00119 }
00120 ArcIndex arc = graph->AddArc(tail - 1, head - 1);
00121 (*assignment)->SetArcCost(arc, FLAGS_assignment_maximize_cost ? -cost : cost);
00122 }
00123
00124
00125
00126 static void ParseOneLine(
00127 ParserState* state,
00128 ForwardStarGraph** graph,
00129 LinearSumAssignment<ForwardStarGraph>** assignment,
00130 char* line) {
00131 if (state->bad) {
00132 return;
00133 }
00134
00135 if (state->expect_last_line) {
00136 state->bad = true;
00137 state->reason = "Input line is too long.";
00138
00139
00140 return;
00141 }
00142
00143 size_t length = strlen(line);
00144
00145
00146
00147 if (line[length - 1] != '\n') {
00148 state->expect_last_line = true;
00149
00150
00151
00152 state->bad_line.reset(new string(line));
00153 }
00154
00155
00156 switch (line[0]) {
00157 case 'p': {
00158
00159 ParseProblemLine(line, state, graph);
00160 break;
00161 }
00162 case 'c': {
00163
00164 return;
00165 }
00166 case 'n': {
00167
00168 ParseNodeLine(line, state);
00169 break;
00170 }
00171 case 'a': {
00172 ParseArcLine(line, state, *graph, assignment);
00173 break;
00174 }
00175 case '0':
00176 case '\n':
00177 break;
00178 default: {
00179 state->bad = true;
00180 state->reason = "Unknown line type in the input.";
00181 state->bad_line.reset(new string(line));
00182 break;
00183 }
00184 }
00185 }
00186
00187 void ParseFileByLines(const string& filename,
00188 Callback1<char*>* line_parser) {
00189 FILE* fp = fopen(filename.c_str(), "r");
00190 const int kMaximumLineSize = 1024;
00191 char line[kMaximumLineSize];
00192 if (fp != NULL) {
00193 char* result;
00194 do {
00195 result = fgets(line, kMaximumLineSize, fp);
00196 if (result != NULL) {
00197 line_parser->Run(result);
00198 }
00199 } while (result != NULL);
00200 }
00201 delete line_parser;
00202 }
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 LinearSumAssignment<ForwardStarGraph>* ParseDimacsAssignment(
00219 const string& filename,
00220 string* error_message,
00221 ForwardStarGraph** graph_handle) {
00222 CHECK_NOTNULL(error_message);
00223 CHECK_NOTNULL(graph_handle);
00224 ForwardStarGraph* graph = NULL;
00225 LinearSumAssignment<ForwardStarGraph>* assignment = NULL;
00226 ParserState state;
00227 Callback1<char*>* cb =
00228 NewPermanentCallback(ParseOneLine, &state, &graph, &assignment);
00229
00230 ParseFileByLines(filename, cb);
00231
00232 if (state.bad) {
00233 *error_message = state.reason;
00234 *error_message = *error_message + ": \"" + *state.bad_line + "\"";
00235 return NULL;
00236 }
00237 if (graph == NULL) {
00238 *error_message = "empty graph description";
00239 return NULL;
00240 }
00241 if (FLAGS_assignment_optimize_layout) {
00242 assignment->OptimizeGraphLayout(graph);
00243 }
00244 *error_message = "";
00245
00246
00247
00248 *graph_handle = graph;
00249 return assignment;
00250 }
00251
00252 }