You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

320 lines
7.1KB

  1. /* Graph Sort
  2. * Copyleft (C) 2002 David Griffiths <dave@pawfal.org>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. #include <iostream>
  19. #include "GraphSort.h"
  20. //#define GRAPHSORT_TRACE
  21. //////////////////////////////////////////////////////////
  22. GraphSort::GraphSort(bool UseTestSort)
  23. {
  24. m_UseTestSort=UseTestSort;
  25. }
  26. GraphSort::~GraphSort()
  27. {
  28. }
  29. void GraphSort::Clear()
  30. {
  31. //m_Sorted.clear();
  32. m_Graph.clear();
  33. }
  34. const list<int> &GraphSort::GetSortedList()
  35. {
  36. return m_Sorted;
  37. }
  38. void GraphSort::Sort()
  39. {
  40. m_UseTestSort?TestSort():OrigSort();
  41. }
  42. void GraphSort::TestSort()
  43. {
  44. m_Sorted.clear();
  45. list<int> Candidates;
  46. #ifdef GRAPHSORT_TRACE
  47. cerr<<"finding seed candidates"<<endl;
  48. #endif
  49. for (map<int,Node>::iterator i=m_Graph.begin();
  50. i!=m_Graph.end(); i++)
  51. {
  52. // all nodes need these vars reset
  53. i->second.UnsatisfiedOutputs = i->second.Outputs.size();
  54. i->second.IsSorted = false;
  55. if (i->second.Outputs.empty() || i->second.IsTerminal)
  56. {
  57. // terminals and roots are seed candidates
  58. Candidates.push_back(i->first);
  59. i->second.IsCandidate=true;
  60. #ifdef GRAPHSORT_TRACE
  61. cerr<<i->first<<" is seed candidate"<<endl;
  62. #endif
  63. }
  64. else
  65. {
  66. i->second.IsCandidate = false;
  67. }
  68. }
  69. while (!Candidates.empty())
  70. {
  71. int NodeToSort;
  72. bool FoundNodeToSort=false;
  73. // look for an ideal candidate
  74. for (list<int>::iterator i = Candidates.begin();
  75. i!=Candidates.end() && !FoundNodeToSort; i++)
  76. {
  77. if (!m_Graph[*i].UnsatisfiedOutputs)
  78. {
  79. NodeToSort=*i;
  80. FoundNodeToSort=true;
  81. #ifdef GRAPHSORT_TRACE
  82. cerr<<"sorted "<<NodeToSort<<" (ideal)"<<endl;
  83. #endif
  84. }
  85. }
  86. if (!FoundNodeToSort)
  87. {
  88. // The latest, ie closest to the outputs, feedback source is
  89. // first on the candidate list. (There may be several equally
  90. // late candidates, but the first will do fine in that case).
  91. NodeToSort=*Candidates.begin();
  92. #ifdef GRAPHSORT_TRACE
  93. cerr<<"sorted "<<NodeToSort<<" (feedback)"<<endl;
  94. #endif
  95. }
  96. // put the chosen candidate on the sort list
  97. Candidates.remove(NodeToSort);
  98. m_Sorted.push_back(NodeToSort);
  99. m_Graph[NodeToSort].IsCandidate=false;
  100. m_Graph[NodeToSort].IsSorted=true;
  101. // all nodes which fed the candidate...
  102. for (list<int>::iterator i=m_Graph[NodeToSort].Inputs.begin();
  103. i!=m_Graph[NodeToSort].Inputs.end(); i++)
  104. {
  105. // ...have another satisfied output...
  106. m_Graph[*i].UnsatisfiedOutputs--;
  107. if(!m_Graph[*i].IsCandidate && !m_Graph[*i].IsSorted)
  108. {
  109. // ..and are promoted to candidate if they haven't been already
  110. Candidates.push_back(*i);
  111. m_Graph[*i].IsCandidate=true;
  112. #ifdef GRAPHSORT_TRACE
  113. cerr<<*i<<" is now a candidate"<<endl;
  114. #endif
  115. }
  116. }
  117. }
  118. #ifdef GRAPHSORT_TRACE
  119. for(list<int>::iterator i=m_Sorted.begin();
  120. i!=m_Sorted.end(); i++)
  121. {
  122. cerr<<*i<<" ";
  123. }
  124. cerr<<endl;
  125. #endif
  126. }
  127. void GraphSort::OrigSort()
  128. {
  129. // walk back from all the roots
  130. m_Sorted.clear();
  131. list<int> RootNodes;
  132. bool FoundRoot=false;
  133. for (map<int,Node>::iterator i=m_Graph.begin();
  134. i!=m_Graph.end(); i++)
  135. {
  136. // if there are no outputs, this must be a root
  137. if (i->second.Outputs.empty())
  138. {
  139. FoundRoot=true;
  140. RecursiveWalk(i->first);
  141. }
  142. }
  143. // no roots found - try looking for a terminal node and recursing from
  144. // there, this makes circular graphs work.
  145. if (!FoundRoot)
  146. {
  147. for (map<int,Node>::iterator i=m_Graph.begin();
  148. i!=m_Graph.end(); i++)
  149. {
  150. // if there are no outputs, this must be a root
  151. if (i->second.IsTerminal)
  152. {
  153. RecursiveWalk(i->first);
  154. }
  155. }
  156. }
  157. #ifdef GRAPHSORT_TRACE
  158. for(list<int>::iterator i=m_Sorted.begin();
  159. i!=m_Sorted.end(); i++)
  160. {
  161. cerr<<*i<<" ";
  162. }
  163. cerr<<endl;
  164. #endif
  165. }
  166. void GraphSort::RecursiveWalk(int node)
  167. {
  168. // check it's not been logged already
  169. // (don't want to execute the node twice)
  170. if(find(m_Sorted.begin(),m_Sorted.end(),node)==m_Sorted.end())
  171. {
  172. #ifdef GRAPHSORT_TRACE
  173. //cerr<<"adding "<<node<<" to list"<<endl;
  174. #endif
  175. m_Sorted.push_back(node);
  176. }
  177. else
  178. {
  179. #ifdef GRAPHSORT_TRACE
  180. //cerr<<"Node "<<node<<" already logged, ending this path"<<endl;
  181. #endif
  182. return;
  183. }
  184. // branch back into the inputs
  185. map<int,Node>::iterator i=m_Graph.find(node);
  186. for(list<int>::iterator ii=i->second.Inputs.begin();
  187. ii!=i->second.Inputs.end(); ii++)
  188. {
  189. RecursiveWalk(*ii);
  190. }
  191. }
  192. void GraphSort::Dump()
  193. {
  194. for (map<int,Node>::iterator i=m_Graph.begin();
  195. i!=m_Graph.end(); i++)
  196. {
  197. cerr<<"Node "<<i->first<<endl;
  198. cerr<<"i=";
  199. for (list<int>::iterator ii=i->second.Inputs.begin();
  200. ii!=i->second.Inputs.end(); ii++)
  201. {
  202. cerr<<*ii<<" ";
  203. }
  204. cerr<<endl<<"o=";
  205. for (list<int>::iterator oi=i->second.Outputs.begin();
  206. oi!=i->second.Outputs.end(); oi++)
  207. {
  208. cerr<<*oi<<" ";
  209. }
  210. cerr<<endl;cerr<<endl;
  211. }
  212. }
  213. void GraphSort::AddConnection(int SID, bool STerminal, int DID, bool DTerminal)
  214. {
  215. map<int,Node>::iterator si=m_Graph.find(SID);
  216. if (si==m_Graph.end())
  217. {
  218. Node newnode;
  219. newnode.IsTerminal = STerminal;
  220. m_Graph[SID]=newnode;
  221. #ifdef GRAPHSORT_TRACE
  222. cerr<<"added "<<SID<<endl;
  223. #endif
  224. }
  225. map<int,Node>::iterator di=m_Graph.find(DID);
  226. if (di==m_Graph.end())
  227. {
  228. Node newnode;
  229. newnode.IsTerminal = DTerminal;
  230. m_Graph[DID]=newnode;
  231. #ifdef GRAPHSORT_TRACE
  232. cerr<<"added "<<DID<<endl;
  233. #endif
  234. }
  235. m_Graph[SID].Outputs.push_back(DID);
  236. m_Graph[DID].Inputs.push_back(SID);
  237. Sort();
  238. }
  239. void GraphSort::RemoveConnection(int SID, int DID)
  240. {
  241. map<int,Node>::iterator si=m_Graph.find(SID);
  242. if (si==m_Graph.end())
  243. {
  244. cerr<<"GraphSort::RemoveConnection - can't find source node"<<endl;
  245. }
  246. map<int,Node>::iterator di=m_Graph.find(DID);
  247. if (di==m_Graph.end())
  248. {
  249. cerr<<"GraphSort::RemoveConnection - can't find dest node"<<endl;
  250. }
  251. list<int>::iterator soi = find(si->second.Outputs.begin(), si->second.Outputs.end(), DID);
  252. if (soi==si->second.Outputs.end()) cerr<<"GraphSort::RemoveConnection - can't find soi"<<endl;
  253. else si->second.Outputs.erase(soi);
  254. list<int>::iterator dii = find(di->second.Inputs.begin(), di->second.Inputs.end(), SID);
  255. if (dii==di->second.Inputs.end()) cerr<<"GraphSort::RemoveConnection - can't find dii"<<endl;
  256. else di->second.Inputs.erase(dii);
  257. // check to remove the nodes
  258. if (si->second.Outputs.empty() && si->second.Inputs.empty())
  259. {
  260. m_Graph.erase(si);
  261. #ifdef GRAPHSORT_TRACE
  262. cerr<<"removed "<<SID<<endl;
  263. #endif
  264. }
  265. if (di->second.Outputs.empty() && di->second.Inputs.empty())
  266. {
  267. m_Graph.erase(di);
  268. #ifdef GRAPHSORT_TRACE
  269. cerr<<"removed "<<DID<<endl;
  270. #endif
  271. }
  272. Sort();
  273. }