DGraph.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  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.apache.org/licenses/LICENSE-2.0.txt
  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. // CTK includes
  15. #include <ctkDependencyGraph.h>
  16. // STD includes
  17. #include <cstdlib>
  18. #include <iostream>
  19. #include <fstream>
  20. #include <sstream>
  21. #include <map>
  22. #include <list>
  23. #include <vector>
  24. #include <cassert>
  25. using namespace std;
  26. //----------------------------------------------------------------------------
  27. std::string help(const std::string& progName)
  28. {
  29. std::string msg = std::string("Usage: ") + progName + std::string(" <graphfile> [-paths Label | -sort Label]");
  30. return msg;
  31. }
  32. //----------------------------------------------------------------------------
  33. void displayError(const std::string& progName, const std::string& msg)
  34. {
  35. std::cerr << progName << std::endl << msg << std::endl << help(progName) << std::endl;
  36. }
  37. std::vector< std::string > splitString(const std::string& string)
  38. {
  39. std::vector<std::string> results;
  40. std::stringstream stringStream;
  41. stringStream << string;
  42. do
  43. {
  44. std::string nextString;
  45. stringStream >> nextString;
  46. size_t found = nextString.find_first_not_of(" ");
  47. if (found != string::npos)
  48. {
  49. results.push_back(nextString.substr(found));
  50. }
  51. } while (!stringStream.eof());
  52. return results;
  53. }
  54. std::string listToString(const std::list<int>& list)
  55. {
  56. std::stringstream stream;
  57. if (list.size() == 0)
  58. {
  59. stream << "empty";
  60. }
  61. else
  62. {
  63. unsigned int counter = 0;
  64. std::list<int>::const_iterator iterator;
  65. for (iterator = list.begin(); iterator != list.end(); iterator++)
  66. {
  67. stream << *iterator;
  68. counter++;
  69. if (counter != list.size())
  70. {
  71. stream << " ";
  72. }
  73. }
  74. }
  75. return stream.str();
  76. }
  77. int getLastElement(const std::list<int>& list)
  78. {
  79. int result = -1;
  80. if (list.size() > 0)
  81. {
  82. std::list<int>::const_reverse_iterator iterator;
  83. iterator = list.rend();
  84. result = *iterator;
  85. }
  86. return result;
  87. }
  88. //----------------------------------------------------------------------------
  89. int getOrGenerateId(std::map<int, std::string>& vertexIdToLabel,
  90. std::map<std::string, int>& vertexLabelToId,
  91. const std::string& label)
  92. {
  93. // If needed, generate vertex id
  94. int vertexId = -1;
  95. if (vertexLabelToId.find(label) == vertexLabelToId.end())
  96. {
  97. vertexId = vertexLabelToId.size() + 1;
  98. vertexLabelToId[label] = vertexId;
  99. vertexIdToLabel[vertexId] = label;
  100. }
  101. else
  102. {
  103. vertexId = vertexLabelToId[label];
  104. }
  105. return vertexId;
  106. }
  107. //----------------------------------------------------------------------------
  108. int main(int argc, char** argv)
  109. {
  110. bool verbose = false;
  111. bool outputTopologicalOrder = true;
  112. // a graph file is expected
  113. if (argc < 2)
  114. {
  115. displayError(argv[0], std::string("Missing one argument"));
  116. return EXIT_FAILURE;
  117. }
  118. bool outputPath = false;
  119. bool outputSort = false;
  120. std::string label;
  121. if (argc == 3)
  122. {
  123. displayError(argv[0], std::string("Wrong argument"));
  124. return EXIT_FAILURE;
  125. }
  126. if (argc == 4)
  127. {
  128. std::string arg2 = std::string(argv[2]);
  129. if (arg2.compare("-paths")!=0 && arg2.compare("-sort")!=0)
  130. {
  131. displayError(argv[0], std::string("Wrong argument: ") + arg2);
  132. return EXIT_FAILURE;
  133. }
  134. label = std::string(argv[3]);
  135. outputTopologicalOrder = false;
  136. if (arg2.compare("-paths") == 0)
  137. {
  138. outputPath = true;
  139. }
  140. else
  141. {
  142. outputSort = true;
  143. }
  144. if (verbose)
  145. {
  146. std::cout << "label:" << label << std::endl;
  147. }
  148. }
  149. // Open File.
  150. std::string filepath = std::string(argv[1]);
  151. if (verbose)
  152. {
  153. std::cout << "filename:" << filepath << std::endl;
  154. }
  155. std::ifstream data;
  156. data.open(filepath.c_str(), ifstream::in);
  157. if (!data.is_open())
  158. {
  159. displayError(argv[0], std::string("Failed to open file '") + filepath + "' !");
  160. return EXIT_FAILURE;
  161. }
  162. // Read first line, called the header.
  163. std::string header;
  164. std::getline (data, header);
  165. if (verbose)
  166. {
  167. std::cout << "header:" << header << std::endl;
  168. }
  169. if (header.length() == 0)
  170. {
  171. displayError(argv[0], std::string("Failed to read Header line in file '") + filepath + "' !");
  172. return EXIT_FAILURE;
  173. }
  174. // Extract two integers
  175. int numberOfVertices = -1;
  176. int numberOfEdges = -1;
  177. std::stringstream stringStream;
  178. stringStream << header;
  179. stringStream >> numberOfVertices;
  180. stringStream >> numberOfEdges;
  181. if (numberOfVertices == -1 || numberOfEdges == -1)
  182. {
  183. displayError(argv[0], std::string("Error in file '") + filepath + "' - First line should look like: <#Vertices> <#Edges>");
  184. return EXIT_FAILURE;
  185. }
  186. if (verbose)
  187. {
  188. std::cout << "#Vertices:" << numberOfVertices << " #Edges:" << numberOfEdges << std::endl;
  189. }
  190. // Init dependency graph, and maps.
  191. ctkDependencyGraph mygraph(numberOfVertices);
  192. mygraph.setVerbose(verbose);
  193. std::map<int, std::string> vertexIdToLabel;
  194. std::map<std::string, int> vertexLabelToId;
  195. // Repeatedly read lines containing labels.
  196. std::string line;
  197. int lineNumber = 2;
  198. std::getline(data, line);
  199. do
  200. {
  201. // Skip empty line or commented line
  202. if (line.length() == 0 || line[0] == '#')
  203. {
  204. std::getline(data, line);
  205. continue;
  206. }
  207. // Extract two strings
  208. stringStream.clear();
  209. stringStream << line;
  210. std::vector<std::string> strings = splitString(line);
  211. if (strings.size() < 1 || strings.size() > 2)
  212. {
  213. stringStream << "Error in file '" << filepath << "' - line:" << lineNumber << " - Expected format is: <label> [<label>]" << std::endl;
  214. std::string message;
  215. stringStream >> message;
  216. displayError(argv[0], message);
  217. }
  218. lineNumber++;
  219. int from = -1;
  220. int to = -1;
  221. if (strings.size() == 2)
  222. {
  223. from = getOrGenerateId(vertexIdToLabel, vertexLabelToId, strings[0]);
  224. to = getOrGenerateId(vertexIdToLabel, vertexLabelToId, strings[1]);
  225. if (verbose)
  226. {
  227. std::cout << "Line='" << line << "', line number " << lineNumber << ", from (" << strings[0] << ", " << from << ") to (" << strings[1] << ", " << to << ")" << std::endl;
  228. }
  229. }
  230. else
  231. {
  232. if (verbose)
  233. {
  234. std::cout << "Line='" << line << "', line number " << lineNumber << ", from (" << strings[0] << ", " << from << ") to (<null>, " << to << ")" << std::endl;
  235. }
  236. }
  237. if (to > -1)
  238. {
  239. // Insert edge if we got two vertices
  240. mygraph.insertEdge(from, to);
  241. }
  242. else
  243. {
  244. // Just generate an entry in the vertexIdToLabel map
  245. getOrGenerateId(vertexIdToLabel, vertexLabelToId, "");
  246. }
  247. std::getline(data, line);
  248. }
  249. while (!data.eof());
  250. assert(numberOfEdges == mygraph.numberOfEdges());
  251. if (verbose)
  252. {
  253. mygraph.printGraph();
  254. std::cout << "> Check for cycle ..." << std::endl;
  255. }
  256. mygraph.checkForCycle();
  257. if (mygraph.cycleDetected())
  258. {
  259. std::cerr << "Cycle detected !" << std::endl;
  260. std::list<int> path;
  261. std::list<int>::iterator pathIterator;
  262. unsigned int pathIteratorCounter = 0;
  263. mygraph.findPath(mygraph.cycleOrigin(), mygraph.cycleEnd(), path);
  264. for (pathIterator = path.begin(); pathIterator != path.end(); pathIterator++)
  265. {
  266. std::cerr << vertexIdToLabel[*pathIterator];
  267. if (pathIteratorCounter != path.size() - 1)
  268. {
  269. std::cerr << " -> ";
  270. }
  271. pathIteratorCounter++;
  272. }
  273. std::cerr << std::endl;
  274. path.clear();
  275. mygraph.findPath(mygraph.cycleEnd(), mygraph.cycleOrigin(), path);
  276. pathIteratorCounter = 0;
  277. for (pathIterator = path.begin(); pathIterator != path.end(); pathIterator++)
  278. {
  279. std::cerr << vertexIdToLabel[*pathIterator];
  280. if (pathIteratorCounter != path.size() - 1)
  281. {
  282. std::cerr << " -> ";
  283. }
  284. }
  285. std::cerr << std::endl;
  286. return EXIT_FAILURE;
  287. }
  288. if (outputTopologicalOrder)
  289. {
  290. if (verbose)
  291. {
  292. std::cerr << "> Topological order ..." << std::endl;
  293. }
  294. std::list<int> out;
  295. std::list<int>::reverse_iterator outIterator;
  296. unsigned int outIteratorCounter = 0;
  297. if (mygraph.topologicalSort(out))
  298. {
  299. outIteratorCounter = 0;
  300. for (outIterator = out.rbegin(); outIterator != out.rend(); outIterator++)
  301. {
  302. std::cout << vertexIdToLabel[*outIterator];
  303. if (outIteratorCounter != out.size() - 1)
  304. {
  305. std::cout << " ";
  306. }
  307. }
  308. std::cout << std::endl;
  309. }
  310. }
  311. if (verbose)
  312. {
  313. std::list<int> sources;
  314. mygraph.sourceVertices(sources);
  315. std::cout << "Source vertices: " << listToString(sources) << std::endl;
  316. }
  317. if (outputPath)
  318. {
  319. // TODO Make sure label is valid
  320. std::list<int> out;
  321. if (mygraph.topologicalSort(out))
  322. {
  323. std::list<int>::iterator outIterator;
  324. for (outIterator = out.begin(); outIterator != out.end(); outIterator++)
  325. {
  326. // Assume all targets depend on the first lib
  327. // We could get all sinks and find all paths
  328. // from the rootId to the sink vertices.
  329. int rootId = getLastElement(out);
  330. int labelId = vertexLabelToId[label];
  331. std::list<std::list<int>*> paths;
  332. mygraph.findPaths(labelId, rootId, paths);
  333. std::list<std::list<int>*>::iterator pathsIterator;
  334. std::list<std::list<int>*>::iterator pathsIteratorPlus1;
  335. for (pathsIterator = paths.begin(); pathsIterator != paths.end(); pathsIterator++)
  336. {
  337. std::list<int>* p = *pathsIterator;
  338. assert(p);
  339. std::list<int>::iterator pIterator;
  340. std::list<int>::iterator pIteratorPlus1;
  341. for (pIterator = p->begin(); pIterator != p->end(); pIterator++)
  342. {
  343. int id = *pIterator;
  344. std::cout << vertexIdToLabel[id];
  345. pIteratorPlus1 = pIterator;
  346. pIteratorPlus1++;
  347. if (pIteratorPlus1 != p->end())
  348. {
  349. std::cout << " ";
  350. }
  351. }
  352. pathsIteratorPlus1 = pathsIterator;
  353. pathsIteratorPlus1++;
  354. if (pathsIteratorPlus1 != paths.end())
  355. {
  356. std::cout << ";";
  357. }
  358. }
  359. for (pathsIterator = paths.begin(); pathsIterator != paths.end(); pathsIterator++)
  360. {
  361. if (*pathsIterator != NULL)
  362. {
  363. delete *pathsIterator;
  364. }
  365. }
  366. }
  367. }
  368. }
  369. if (outputSort)
  370. {
  371. // TODO Make sure label is valid
  372. std::list<int> out;
  373. int labelId = vertexLabelToId[label];
  374. if (labelId < 1)
  375. {
  376. std::cout << label;
  377. return EXIT_SUCCESS;
  378. }
  379. if (mygraph.topologicalSort(out, labelId))
  380. {
  381. std::list<int>::iterator outIterator;
  382. std::list<int>::iterator outIteratorPlus1;
  383. for (outIterator = out.begin(); outIterator != out.end(); outIterator++)
  384. {
  385. int id = *outIterator;
  386. std::cout << vertexIdToLabel[id];
  387. outIteratorPlus1 = outIterator;
  388. outIteratorPlus1++;
  389. if (outIteratorPlus1 != out.end())
  390. {
  391. std::cout << " ";
  392. }
  393. }
  394. }
  395. }
  396. return EXIT_SUCCESS;
  397. }