DGraph.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.commontk.org/LICENSE
  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. =========================================================================*/
  14. // Qt includes
  15. #include <QFile>
  16. #include <QTextStream>
  17. #include <QRegExp>
  18. #include <QStringList>
  19. #include <QDebug>
  20. // CTK includes
  21. #include <ctkDependencyGraph.h>
  22. // STD includes
  23. #include <cstdlib>
  24. #include <iostream>
  25. //----------------------------------------------------------------------------
  26. QString help(const QString& progName)
  27. {
  28. QString msg = "Usage: %1 <graphfile> [-paths Label | -sort Label]";
  29. return msg.arg(progName);
  30. }
  31. //----------------------------------------------------------------------------
  32. void displayError(const QString& progName, const QString& msg)
  33. {
  34. std::cerr << qPrintable(QString("%1\n%2\n%3\n").arg(progName).
  35. arg(msg).
  36. arg(help(progName)));
  37. }
  38. //----------------------------------------------------------------------------
  39. int getOrGenerateId(QHash<int, QString>& vertexIdToLabel,
  40. QHash<QString, int>& vertexLabelToId,
  41. const QString& label)
  42. {
  43. // If needed, generate vertex id
  44. int vertexId = -1;
  45. if (!vertexLabelToId.keys().contains(label))
  46. {
  47. vertexId = vertexLabelToId.keys().size() + 1;
  48. vertexLabelToId[label] = vertexId;
  49. vertexIdToLabel[vertexId] = label;
  50. }
  51. else
  52. {
  53. vertexId = vertexLabelToId[label];
  54. }
  55. return vertexId;
  56. }
  57. //----------------------------------------------------------------------------
  58. int main(int argc, char** argv)
  59. {
  60. bool verbose = false;
  61. bool outputTopologicalOrder = true;
  62. // a graph file is expected
  63. if (argc < 2)
  64. {
  65. displayError(argv[0], QLatin1String("Missing one argument"));
  66. return EXIT_FAILURE;
  67. }
  68. bool outputPath = false;
  69. bool outputSort = false;
  70. QString label;
  71. if (argc == 3)
  72. {
  73. displayError(argv[0], QLatin1String("Wrong argument"));
  74. return EXIT_FAILURE;
  75. }
  76. if (argc == 4)
  77. {
  78. QString arg2 = QString::fromLatin1(argv[2]);
  79. if (arg2.compare("-paths")!=0 && arg2.compare("-sort")!=0)
  80. {
  81. displayError(argv[0], QString("Wrong argument: %1").arg(arg2));
  82. return EXIT_FAILURE;
  83. }
  84. label = QLatin1String(argv[3]);
  85. outputTopologicalOrder = false;
  86. if (arg2.compare("-paths") == 0)
  87. {
  88. outputPath = true;
  89. }
  90. else
  91. {
  92. outputSort = true;
  93. }
  94. if (verbose)
  95. {
  96. qDebug() << "label:" << label;
  97. }
  98. }
  99. QString filepath = QString::fromLatin1(argv[1]);
  100. if (!QFile::exists(filepath))
  101. {
  102. displayError(argv[0], QString("File '%1' doesn't exists !").arg(filepath));
  103. return EXIT_FAILURE;
  104. }
  105. QFile data(filepath);
  106. if (!data.open(QFile::ReadOnly))
  107. {
  108. displayError(argv[0], QString("Failed to open file '%1' !").arg(filepath));
  109. return EXIT_FAILURE;
  110. }
  111. QTextStream in(&data);
  112. QString header = in.readLine();
  113. if (header.isNull())
  114. {
  115. displayError(argv[0], QString("Failed to read Header line in file '%1' !").arg(filepath));
  116. return EXIT_FAILURE;
  117. }
  118. // Regular expression to extract two integers
  119. QRegExp twoint_re("^([0-9]+)\\s+([0-9]+)");
  120. // Extract numberOfVertices and numberOfEdges
  121. int pos = twoint_re.indexIn(header.trimmed());
  122. if (pos != 0)
  123. {
  124. displayError(argv[0], QString("Error in file '%1' - First line should look like: <#Vertices> <#Edges>")
  125. .arg(filepath));
  126. return EXIT_FAILURE;
  127. }
  128. QStringList list = twoint_re.capturedTexts();
  129. Q_ASSERT(list.size() == 3);
  130. int numberOfVertices = list[1].toInt();
  131. int numberOfEdges = list[2].toInt();
  132. if (verbose)
  133. {
  134. qDebug() << "#Vertices:" << numberOfVertices << "#Edges:" << numberOfEdges;
  135. }
  136. // Init
  137. ctkDependencyGraph mygraph(numberOfVertices);
  138. mygraph.setVerbose(verbose);
  139. // Map between vertex label and vertex id
  140. QHash<int, QString> vertexIdToLabel;
  141. QHash<QString, int> vertexLabelToId;
  142. // Regular expression to extract two label
  143. QRegExp twolabel_re("^\\s*(\\S+)\\s*$|^\\s*(\\S+)\\s*(\\S+)\\s*$");
  144. // Read vertex connection
  145. int lineNumber = 2;
  146. QString line = in.readLine();
  147. do
  148. {
  149. // Skip empty line or commented line
  150. if (line.isEmpty() || line.startsWith("#"))
  151. {
  152. line = in.readLine();
  153. continue;
  154. }
  155. // Extract vertex points
  156. int pos = twolabel_re.indexIn(line.trimmed());
  157. if (pos != 0)
  158. {
  159. displayError(argv[0], QString("Error in file '%1' - line:%2 - Expected format is: <label> [<label>]")
  160. .arg(filepath).arg(lineNumber));
  161. return EXIT_FAILURE;
  162. }
  163. lineNumber++;
  164. QStringList list = twolabel_re.capturedTexts();
  165. Q_ASSERT(list.size() == 4);
  166. int from = -1;
  167. int to = -1;
  168. if (list[1].isEmpty())
  169. {
  170. from = getOrGenerateId(vertexIdToLabel, vertexLabelToId, list[2]);
  171. to = getOrGenerateId(vertexIdToLabel, vertexLabelToId, list[3]);
  172. }
  173. if (to > -1)
  174. {
  175. // Insert edge if we got two vertices
  176. mygraph.insertEdge(from, to);
  177. }
  178. else
  179. {
  180. // Just generate an entry in the vertexIdToLabel map
  181. getOrGenerateId(vertexIdToLabel, vertexLabelToId, list[1]);
  182. }
  183. line = in.readLine();
  184. }
  185. while (!line.isNull());
  186. Q_ASSERT(numberOfEdges == mygraph.numberOfEdges());
  187. if (verbose)
  188. {
  189. mygraph.printGraph();
  190. qDebug() << "> Check for cycle ...";
  191. }
  192. mygraph.checkForCycle();
  193. if (mygraph.cycleDetected())
  194. {
  195. std::cerr << "Cycle detected !" << std::endl;
  196. QList<int> path;
  197. mygraph.findPath(mygraph.cycleOrigin(), mygraph.cycleEnd(), path);
  198. for(int i = 0; i < path.size(); ++i)
  199. {
  200. std::cerr << qPrintable(vertexIdToLabel[path[i]]);
  201. if (i != path.size() - 1)
  202. {
  203. std::cerr << " -> ";
  204. }
  205. }
  206. std::cerr << std::endl;
  207. path.clear();
  208. mygraph.findPath(mygraph.cycleEnd(), mygraph.cycleOrigin(), path);
  209. for(int i = 0; i < path.size(); ++i)
  210. {
  211. std::cerr << qPrintable(vertexIdToLabel[path[i]]);
  212. if (i != path.size() - 1)
  213. {
  214. std::cerr << " -> ";
  215. }
  216. }
  217. std::cerr << std::endl;
  218. return EXIT_FAILURE;
  219. }
  220. if (outputTopologicalOrder)
  221. {
  222. if (verbose)
  223. {
  224. qDebug() << "> Topological order ...";
  225. }
  226. QList<int> out;
  227. if (mygraph.topologicalSort(out))
  228. {
  229. for(int i=out.size() - 1; i >= 0; --i)
  230. {
  231. std::cout << qPrintable(vertexIdToLabel[out[i]]);
  232. if (i != 0)
  233. {
  234. std::cout << " ";
  235. }
  236. }
  237. std::cout << std::endl;
  238. }
  239. }
  240. if (verbose)
  241. {
  242. QList<int> sources;
  243. mygraph.sourceVertices(sources);
  244. qDebug() << "Source vertices: " << sources;
  245. }
  246. if (outputPath)
  247. {
  248. // TODO Make sure label is valid
  249. QList<int> out;
  250. if (mygraph.topologicalSort(out))
  251. {
  252. for(int i=0; i < out.size(); i++)
  253. {
  254. // Assume all targets depend on the first lib
  255. // We could get all sinks and find all paths
  256. // from the rootId to the sink vertices.
  257. int rootId = out.last();
  258. int labelId = vertexLabelToId[label];
  259. QList<QList<int>*> paths;
  260. mygraph.findPaths(labelId, rootId, paths);
  261. for(int i=0; i < paths.size(); i++)
  262. {
  263. QList<int>* p = paths[i];
  264. Q_ASSERT(p);
  265. for(int j=0; j < p->size(); j++)
  266. {
  267. int id = p->at(j);
  268. std::cout << qPrintable(vertexIdToLabel[id]);
  269. if (j != p->size() - 1)
  270. {
  271. std::cout << " ";
  272. }
  273. }
  274. if (i != paths.size() - 1)
  275. {
  276. std::cout << ";";
  277. }
  278. }
  279. }
  280. }
  281. }
  282. if (outputSort)
  283. {
  284. // TODO Make sure label is valid
  285. QList<int> out;
  286. int labelId = vertexLabelToId[label];
  287. if (mygraph.topologicalSort(out, labelId))
  288. {
  289. for(int i=0; i < out.size(); i++)
  290. {
  291. int id = out.at(i);
  292. std::cout << qPrintable(vertexIdToLabel[id]);
  293. if (i != out.size() - 1)
  294. {
  295. std::cout << " ";
  296. }
  297. }
  298. }
  299. }
  300. return EXIT_SUCCESS;
  301. }