00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <algorithm>
00015 #include <cstdlib>
00016 #include "base/hash.h"
00017 #include <string>
00018 #include <vector>
00019
00020 #include "base/commandlineflags.h"
00021 #include "base/commandlineflags.h"
00022 #include "base/logging.h"
00023 #include "base/stringprintf.h"
00024 #include "base/timer.h"
00025 #include "algorithms/hungarian.h"
00026 #include "graph/ebert_graph.h"
00027 #include "graph/linear_assignment.h"
00028 #include "cpp/parse_dimacs_assignment.h"
00029 #include "cpp/print_dimacs_assignment.h"
00030
00031 DEFINE_bool(assignment_compare_hungarian, false,
00032 "Compare result and speed against Hungarian method.");
00033 DEFINE_string(assignment_problem_output_file, "",
00034 "Print the problem to this file in DIMACS format (after layout "
00035 "is optimized, if applicable).");
00036
00037 namespace operations_research {
00038
00039 CostValue BuildAndSolveHungarianInstance(
00040 const LinearSumAssignment<ForwardStarGraph>& assignment) {
00041 const ForwardStarGraph& graph = assignment.Graph();
00042 typedef std::vector<double> HungarianRow;
00043 typedef std::vector<HungarianRow> HungarianProblem;
00044 HungarianProblem hungarian_cost;
00045 hungarian_cost.resize(assignment.NumLeftNodes());
00046
00047
00048 CostValue largest_cost_magnitude = 0;
00049 for (ForwardStarGraph::ArcIterator arc_it(graph);
00050 arc_it.Ok();
00051 arc_it.Next()) {
00052 ArcIndex arc = arc_it.Index();
00053 CostValue cost_magnitude = ::std::abs(assignment.ArcCost(arc));
00054 largest_cost_magnitude = ::std::max(largest_cost_magnitude, cost_magnitude);
00055 }
00056 double missing_arc_cost = static_cast<double>((assignment.NumLeftNodes() *
00057 largest_cost_magnitude) +
00058 1);
00059 for (HungarianProblem::iterator row = hungarian_cost.begin();
00060 row != hungarian_cost.end();
00061 ++row) {
00062 row->resize(assignment.NumNodes() - assignment.NumLeftNodes(),
00063 missing_arc_cost);
00064 }
00065
00066
00067
00068
00069
00070
00071
00072 for (ForwardStarGraph::NodeIterator node_it(graph);
00073 node_it.Ok();
00074 node_it.Next()) {
00075 NodeIndex node = node_it.Index();
00076 NodeIndex tail = (node - ForwardStarGraph::kFirstNode);
00077 for (ForwardStarGraph::OutgoingArcIterator arc_it(graph, node);
00078 arc_it.Ok();
00079 arc_it.Next()) {
00080 ArcIndex arc = arc_it.Index();
00081 NodeIndex head = (graph.Head(arc) - assignment.NumLeftNodes() -
00082 ForwardStarGraph::kFirstNode);
00083 double cost = static_cast<double>(assignment.ArcCost(arc));
00084 hungarian_cost[tail][head] = cost;
00085 }
00086 }
00087 hash_map<int, int> result;
00088 hash_map<int, int> wish_this_could_be_null;
00089 WallTimer timer;
00090 VLOG(1) << "Beginning Hungarian method.";
00091 timer.Start();
00092 MinimizeLinearAssignment(hungarian_cost, &result, &wish_this_could_be_null);
00093 double elapsed = timer.GetInMs() / 1000.0;
00094 LOG(INFO) << "Hungarian result computed in " << elapsed << " seconds.";
00095 double result_cost = 0.0;
00096 for (int i = 0; i < assignment.NumLeftNodes(); ++i) {
00097 int mate = result[i];
00098 result_cost += hungarian_cost[i][mate];
00099 }
00100 return static_cast<CostValue>(result_cost);
00101 }
00102
00103 void DisplayAssignment(
00104 const LinearSumAssignment<ForwardStarGraph>& assignment) {
00105 for (LinearSumAssignment<ForwardStarGraph>::BipartiteLeftNodeIterator
00106 node_it(assignment);
00107 node_it.Ok();
00108 node_it.Next()) {
00109 const NodeIndex left_node = node_it.Index();
00110 const ArcIndex matching_arc = assignment.GetAssignmentArc(left_node);
00111 const NodeIndex right_node = assignment.Head(matching_arc);
00112 VLOG(5) << "assigned (" << left_node << ", " << right_node << "): "
00113 << assignment.ArcCost(matching_arc);
00114 }
00115 }
00116
00117 static const char* const kUsageTemplate = "usage: %s <filename>";
00118
00119 int solve_dimacs_assignment(int argc, char* argv[]) {
00120 string usage;
00121 if (argc < 1) {
00122 usage = StringPrintf(kUsageTemplate, "solve_dimacs_assignment");
00123 } else {
00124 usage = StringPrintf(kUsageTemplate, argv[0]);
00125 }
00126 google::SetUsageMessage(usage);
00127 google::ParseCommandLineFlags(&argc, &argv, true);
00128
00129 if (argc < 2) {
00130 LOG(FATAL) << usage;
00131 }
00132 string error_message;
00133
00134
00135 ForwardStarGraph* graph = NULL;
00136 LinearSumAssignment<ForwardStarGraph>* assignment =
00137 ParseDimacsAssignment(argv[1], &error_message, &graph);
00138 if (assignment == NULL) {
00139 LOG(FATAL) << error_message;
00140 }
00141 if (!FLAGS_assignment_problem_output_file.empty()) {
00142
00143
00144
00145
00146
00147
00148 TailArrayManager<ForwardStarGraph> tail_array_manager(graph);
00149 PrintDimacsAssignmentProblem(*assignment, tail_array_manager,
00150 FLAGS_assignment_problem_output_file);
00151 tail_array_manager.ReleaseTailArrayIfForwardGraph();
00152 }
00153 CostValue hungarian_cost = 0.0;
00154 bool hungarian_solved = false;
00155 if (FLAGS_assignment_compare_hungarian) {
00156 hungarian_cost = BuildAndSolveHungarianInstance(*assignment);
00157 hungarian_solved = true;
00158 }
00159 WallTimer timer;
00160 timer.Start();
00161 bool success = assignment->ComputeAssignment();
00162 double elapsed = timer.GetInMs() / 1000.0;
00163 if (success) {
00164 CostValue cost = assignment->GetCost();
00165 DisplayAssignment(*assignment);
00166 LOG(INFO) << "Cost of optimum assignment: " << cost;
00167 LOG(INFO) << "Computed in " << elapsed << " seconds.";
00168 LOG(INFO) << assignment->StatsString();
00169 if (hungarian_solved && (cost != hungarian_cost)) {
00170 LOG(ERROR) << "Optimum cost mismatch: " << cost << " vs. "
00171 << hungarian_cost << ".";
00172 }
00173 } else {
00174 LOG(WARNING) << "Given problem is infeasible.";
00175 }
00176 delete assignment;
00177 delete graph;
00178 return 0;
00179 }
00180 }
00181
00182 int main(int argc, char* argv[]) {
00183 return ::operations_research::solve_dimacs_assignment(argc, argv);
00184 }