00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "base/commandlineflags.h"
00015 #include "base/commandlineflags.h"
00016 #include "base/integral_types.h"
00017 #include "base/logging.h"
00018 #include "base/macros.h"
00019 #include "base/file.h"
00020 #include "base/recordio.h"
00021 #include "constraint_solver/constraint_solver.h"
00022 #include "constraint_solver/model.pb.h"
00023 #include "util/graph_export.h"
00024 #include "util/string_array.h"
00025
00026 DEFINE_string(input, "", "Input file of the problem.");
00027 DEFINE_string(output, "", "Output file when doing modifications.");
00028 DEFINE_string(dot_file, "", "Exports model to dot file.");
00029 DEFINE_string(gml_file, "", "Exports model to gml file.");
00030
00031 DEFINE_bool(print_proto, false, "Prints the raw model protobuf.");
00032 DEFINE_bool(test_proto, false, "Performs various tests on the model protobuf.");
00033 DEFINE_bool(model_stats, false, "Prints model statistics.");
00034 DEFINE_bool(print_model, false, "Pretty print loaded model.");
00035
00036 DEFINE_string(rename_model, "", "Renames to the model.");
00037 DEFINE_bool(strip_limit, false, "Strips limits from the model.");
00038 DEFINE_bool(strip_groups, false, "Strips variable groups from the model.");
00039 DEFINE_bool(upgrade_proto, false, "Upgrade the model to the latest version.");
00040 DEFINE_string(insert_license, "",
00041 "Insert content of the given file into the license file.");
00042 DEFINE_bool(collect_variables, false,
00043 "Shows effect of the variable collector.");
00044
00045 namespace operations_research {
00046
00047
00048
00049 static const int kProblem = -1;
00050 static const int kOk = 0;
00051
00052
00053 static const char kGreen1[] = "#A2CD5A";
00054 static const char kGreen2[] = "#76EEC6";
00055 static const char kGreen3[] = "#00CD00";
00056 static const char kWhite[] = "#FAFAFA";
00057 static const char kBlue[] = "#87CEFA";
00058 static const char kYellow[] = "#FFF68F";
00059 static const char kRed[] = "#A52A2A";
00060
00061
00062 string ExprLabel(int index) {
00063 return StringPrintf("expr_%i", index);
00064 }
00065
00066 string IntervalLabel(int index) {
00067 return StringPrintf("interval_%i", index);
00068 }
00069
00070 string SequenceLabel(int index) {
00071 return StringPrintf("sequence_%i", index);
00072 }
00073
00074 string ConstraintLabel(int index) {
00075 return StringPrintf("ct_%i", index);
00076 }
00077
00078
00079 template <class T> void ExportLinks(const CPModelProto& model,
00080 const string& source,
00081 const T& proto,
00082 GraphExporter* const exporter) {
00083 const string& arg_name = model.tags(proto.argument_index());
00084 if (proto.has_integer_expression_index()) {
00085 exporter->WriteLink(source,
00086 ExprLabel(proto.integer_expression_index()),
00087 arg_name);
00088 }
00089 for (int i = 0; i < proto.integer_expression_array_size(); ++i) {
00090 exporter->WriteLink(source,
00091 ExprLabel(proto.integer_expression_array(i)),
00092 arg_name);
00093 }
00094 if (proto.has_interval_index()) {
00095 exporter->WriteLink(source,
00096 IntervalLabel(proto.interval_index()),
00097 arg_name);
00098 }
00099 for (int i = 0; i < proto.interval_array_size(); ++i) {
00100 exporter->WriteLink(source,
00101 IntervalLabel(proto.interval_array(i)),
00102 arg_name);
00103 }
00104 if (proto.has_sequence_index()) {
00105 exporter->WriteLink(source,
00106 SequenceLabel(proto.sequence_index()),
00107 arg_name);
00108 }
00109 for (int i = 0; i < proto.sequence_array_size(); ++i) {
00110 exporter->WriteLink(source,
00111 SequenceLabel(proto.sequence_array(i)),
00112 arg_name);
00113 }
00114 }
00115
00116
00117
00118 bool GetValueIfConstant(const CPModelProto& model,
00119 const CPIntegerExpressionProto& proto,
00120 int64* const value) {
00121 CHECK_NOTNULL(value);
00122 const int expr_type = proto.type_index();
00123 if (model.tags(expr_type) != ModelVisitor::kIntegerVariable) {
00124 return false;
00125 }
00126 if (proto.arguments_size() != 2) {
00127 return false;
00128 }
00129 const CPArgumentProto& arg1_proto = proto.arguments(0);
00130 if (model.tags(arg1_proto.argument_index()) != ModelVisitor::kMinArgument) {
00131 return false;
00132 }
00133 const int64 value1 = arg1_proto.integer_value();
00134 const CPArgumentProto& arg2_proto = proto.arguments(1);
00135 if (model.tags(arg2_proto.argument_index()) != ModelVisitor::kMaxArgument) {
00136 return false;
00137 }
00138 const int64 value2 = arg2_proto.integer_value();
00139 if (value1 == value2) {
00140 *value = value1;
00141 return true;
00142 } else {
00143 return false;
00144 }
00145 }
00146
00147
00148 void DeclareExpression(int index,
00149 const CPModelProto& proto,
00150 GraphExporter* const exporter) {
00151 const CPIntegerExpressionProto& expr = proto.expressions(index);
00152 const string label = ExprLabel(index);
00153 int64 value = 0;
00154 if (expr.has_name()) {
00155 exporter->WriteNode(label, expr.name(), "oval", kGreen1);
00156 } else if (GetValueIfConstant(proto, expr, &value)) {
00157 exporter->WriteNode(label,
00158 StringPrintf("%lld", value),
00159 "oval",
00160 kYellow);
00161 } else {
00162 const string& type = proto.tags(expr.type_index());
00163 exporter->WriteNode(label, type, "oval", kWhite);
00164 }
00165 }
00166
00167 void DeclareInterval(int index,
00168 const CPModelProto& proto,
00169 GraphExporter* const exporter) {
00170 const CPIntervalVariableProto& interval = proto.intervals(index);
00171 const string label = IntervalLabel(index);
00172 if (interval.has_name()) {
00173 exporter->WriteNode(label, interval.name(), "circle", kGreen2);
00174 } else {
00175 const string& type = proto.tags(interval.type_index());
00176 exporter->WriteNode(label, type, "circle", kWhite);
00177 }
00178 }
00179
00180 void DeclareSequence(int index,
00181 const CPModelProto& proto,
00182 GraphExporter* const exporter) {
00183 const CPSequenceVariableProto& sequence = proto.sequences(index);
00184 const string label = SequenceLabel(index);
00185 if (sequence.has_name()) {
00186 exporter->WriteNode(label, sequence.name(), "circle", kGreen3);
00187 } else {
00188 const string& type = proto.tags(sequence.type_index());
00189 exporter->WriteNode(label, type, "circle", kWhite);
00190 }
00191 }
00192
00193 void DeclareConstraint(int index,
00194 const CPModelProto& proto,
00195 GraphExporter* const exporter) {
00196 const CPConstraintProto& ct = proto.constraints(index);
00197 const string& type = proto.tags(ct.type_index());
00198 const string label = ConstraintLabel(index);
00199 exporter->WriteNode(label, type, "rectangle", kBlue);
00200 }
00201
00202
00203 void ExportToGraphFile(const CPModelProto& proto,
00204 File* const file,
00205 GraphExporter::GraphFormat format) {
00206 scoped_ptr<GraphExporter> exporter(
00207 GraphExporter::MakeFileExporter(file, format));
00208 exporter->WriteHeader(proto.model());
00209 for (int i = 0; i < proto.expressions_size(); ++i) {
00210 DeclareExpression(i, proto, exporter.get());
00211 }
00212
00213 for (int i = 0; i < proto.intervals_size(); ++i) {
00214 DeclareInterval(i, proto, exporter.get());
00215 }
00216
00217 for (int i = 0; i < proto.sequences_size(); ++i) {
00218 DeclareSequence(i, proto, exporter.get());
00219 }
00220
00221 for (int i = 0; i < proto.constraints_size(); ++i) {
00222 DeclareConstraint(i, proto, exporter.get());
00223 }
00224
00225 const char kObjLabel[] = "obj";
00226 if (proto.has_objective()) {
00227 const string name = proto.objective().maximize() ? "Maximize" : "Minimize";
00228 exporter->WriteNode(kObjLabel, name, "diamond", kRed);
00229 }
00230
00231 for (int i = 0; i < proto.expressions_size(); ++i) {
00232 const CPIntegerExpressionProto& expr = proto.expressions(i);
00233 const string label = ExprLabel(i);
00234 for (int j = 0; j < expr.arguments_size(); ++j) {
00235 ExportLinks(proto, label, expr.arguments(j), exporter.get());
00236 }
00237 }
00238
00239 for (int i = 0; i < proto.intervals_size(); ++i) {
00240 const CPIntervalVariableProto& interval = proto.intervals(i);
00241 const string label = IntervalLabel(i);
00242 for (int j = 0; j < interval.arguments_size(); ++j) {
00243 ExportLinks(proto, label, interval.arguments(j), exporter.get());
00244 }
00245 }
00246
00247 for (int i = 0; i < proto.sequences_size(); ++i) {
00248 const CPSequenceVariableProto& sequence = proto.sequences(i);
00249 const string label = SequenceLabel(i);
00250 for (int j = 0; j < sequence.arguments_size(); ++j) {
00251 ExportLinks(proto, label, sequence.arguments(j), exporter.get());
00252 }
00253 }
00254
00255 for (int i = 0; i < proto.constraints_size(); ++i) {
00256 const CPConstraintProto& ct = proto.constraints(i);
00257 const string label = ConstraintLabel(i);
00258 for (int j = 0; j < ct.arguments_size(); ++j) {
00259 ExportLinks(proto, label, ct.arguments(j), exporter.get());
00260 }
00261 }
00262
00263 if (proto.has_objective()) {
00264 const CPObjectiveProto& obj = proto.objective();
00265 exporter->WriteLink(kObjLabel,
00266 ExprLabel(obj.objective_index()),
00267 ModelVisitor::kExpressionArgument);
00268 }
00269 exporter->WriteFooter();
00270 }
00271
00272
00273
00274 int Run() {
00275
00276
00277 File::Init();
00278 File* const file = File::Open(FLAGS_input, "r");
00279 if (file == NULL) {
00280 LOG(WARNING) << "Cannot open " << FLAGS_input;
00281 return kProblem;
00282 }
00283
00284 CPModelProto model_proto;
00285 RecordReader reader(file);
00286 if (!(reader.ReadProtocolMessage(&model_proto) && reader.Close())) {
00287 LOG(INFO) << "No model found in " << file->CreateFileName();
00288 return kProblem;
00289 }
00290
00291
00292
00293 LOG(INFO) << "Read model " << model_proto.model();
00294 if (model_proto.has_license_text()) {
00295 LOG(INFO) << "License = " << model_proto.license_text();
00296 }
00297
00298
00299
00300 if (!FLAGS_rename_model.empty()) {
00301 model_proto.set_model(FLAGS_rename_model);
00302 }
00303
00304 if (FLAGS_strip_limit) {
00305 model_proto.clear_search_limit();
00306 }
00307
00308 if (FLAGS_strip_groups) {
00309 model_proto.clear_variable_groups();
00310 }
00311
00312 if (FLAGS_upgrade_proto) {
00313 if (!Solver::UpgradeModel(&model_proto)) {
00314 LOG(ERROR) << "Model upgrade failed";
00315 return kProblem;
00316 }
00317 }
00318
00319 if (!FLAGS_insert_license.empty()) {
00320 File* const license = File::Open(FLAGS_insert_license, "rb");
00321 if (license == NULL) {
00322 LOG(WARNING) << "Cannot open " << FLAGS_insert_license;
00323 return kProblem;
00324 }
00325 const int size = license->Size();
00326 char* const text = new char[size + 1];
00327 license->Read(text, size);
00328 text[size] = '\0';
00329 model_proto.set_license_text(text);
00330 license->Close();
00331 }
00332
00333
00334
00335 if (FLAGS_print_proto) {
00336 LOG(INFO) << model_proto.DebugString();
00337 }
00338 if (FLAGS_test_proto ||
00339 FLAGS_model_stats ||
00340 FLAGS_print_model ||
00341 FLAGS_collect_variables) {
00342 Solver solver(model_proto.model());
00343 std::vector<SearchMonitor*> monitors;
00344 if (!solver.LoadModel(model_proto, &monitors)) {
00345 LOG(INFO) << "Could not load model into the solver";
00346 return kProblem;
00347 }
00348 if (FLAGS_test_proto) {
00349 LOG(INFO) << "Model " << model_proto.model() << " loaded OK";
00350 }
00351 if (FLAGS_model_stats) {
00352 ModelVisitor* const visitor = solver.MakeStatisticsModelVisitor();
00353 solver.Accept(visitor, monitors);
00354 }
00355 if (FLAGS_print_model) {
00356 ModelVisitor* const visitor = solver.MakePrintModelVisitor();
00357 solver.Accept(visitor, monitors);
00358 }
00359 if (FLAGS_collect_variables) {
00360 std::vector<IntVar*> primary_integer_variables;
00361 std::vector<IntVar*> secondary_integer_variables;
00362 std::vector<SequenceVar*> sequence_variables;
00363 std::vector<IntervalVar*> interval_variables;
00364 solver.CollectDecisionVariables(&primary_integer_variables,
00365 &secondary_integer_variables,
00366 &sequence_variables,
00367 &interval_variables);
00368 LOG(INFO) << "Primary integer variables = "
00369 << DebugStringVector(primary_integer_variables, ", ");
00370 LOG(INFO) << "Secondary integer variables = "
00371 << DebugStringVector(secondary_integer_variables, ", ");
00372 LOG(INFO) << "Sequence variables = "
00373 << DebugStringVector(sequence_variables, ", ");
00374 LOG(INFO) << "Interval variables = "
00375 << DebugStringVector(interval_variables, ", ");
00376 }
00377 }
00378
00379
00380
00381 if (!FLAGS_output.empty()) {
00382 File* const output = File::Open(FLAGS_output, "wb");
00383 if (output == NULL) {
00384 LOG(INFO) << "Cannot open " << FLAGS_output;
00385 return kProblem;
00386 }
00387 RecordWriter writer(output);
00388 if (!(writer.WriteProtocolMessage(model_proto) && writer.Close())) {
00389 return kProblem;
00390 } else {
00391 LOG(INFO) << "Model successfully written to " << FLAGS_output;
00392 }
00393 }
00394
00395 if (!FLAGS_dot_file.empty()) {
00396 File* const dot_file = File::Open(FLAGS_dot_file, "w");
00397 if (dot_file == NULL) {
00398 LOG(INFO) << "Cannot open " << FLAGS_dot_file;
00399 return kProblem;
00400 }
00401 ExportToGraphFile(model_proto, dot_file, GraphExporter::DOT_FORMAT);
00402 dot_file->Close();
00403 }
00404
00405 if (!FLAGS_gml_file.empty()) {
00406 File* const gml_file = File::Open(FLAGS_gml_file, "w");
00407 if (gml_file == NULL) {
00408 LOG(INFO) << "Cannot open " << FLAGS_gml_file;
00409 return kProblem;
00410 }
00411 ExportToGraphFile(model_proto, gml_file, GraphExporter::GML_FORMAT);
00412 gml_file->Close();
00413 }
00414 return kOk;
00415 }
00416 }
00417
00418 int main(int argc, char **argv) {
00419 google::ParseCommandLineFlags(&argc, &argv, true);
00420 if (FLAGS_input.empty()) {
00421 LOG(FATAL) << "Filename not specified";
00422 }
00423 return operations_research::Run();
00424 }