GraphUtils.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. using System;
  2. using System.Linq;
  3. using System.Collections.Generic;
  4. namespace GraphProcessor
  5. {
  6. public static class GraphUtils
  7. {
  8. enum State
  9. {
  10. White,
  11. Grey,
  12. Black,
  13. }
  14. class TarversalNode
  15. {
  16. public BaseNode node;
  17. public List<TarversalNode> inputs = new List<TarversalNode>();
  18. public List<TarversalNode> outputs = new List<TarversalNode>();
  19. public State state = State.White;
  20. public TarversalNode(BaseNode node) { this.node = node; }
  21. }
  22. // A structure made for easy graph traversal
  23. class TraversalGraph
  24. {
  25. public List<TarversalNode> nodes = new List<TarversalNode>();
  26. public List<TarversalNode> outputs = new List<TarversalNode>();
  27. }
  28. static TraversalGraph ConvertGraphToTraversalGraph(BaseGraph graph)
  29. {
  30. TraversalGraph g = new TraversalGraph();
  31. Dictionary<BaseNode, TarversalNode> nodeMap = new Dictionary<BaseNode, TarversalNode>();
  32. foreach (var node in graph.nodes)
  33. {
  34. var tn = new TarversalNode(node);
  35. g.nodes.Add(tn);
  36. nodeMap[node] = tn;
  37. if (graph.graphOutputs.Contains(node))
  38. g.outputs.Add(tn);
  39. }
  40. foreach (var tn in g.nodes)
  41. {
  42. tn.inputs = tn.node.GetInputNodes().Where(n => nodeMap.ContainsKey(n)).Select(n => nodeMap[n]).ToList();
  43. tn.outputs = tn.node.GetOutputNodes().Where(n => nodeMap.ContainsKey(n)).Select(n => nodeMap[n]).ToList();
  44. }
  45. return g;
  46. }
  47. public static List<BaseNode> DepthFirstSort(BaseGraph g)
  48. {
  49. var graph = ConvertGraphToTraversalGraph(g);
  50. List<BaseNode> depthFirstNodes = new List<BaseNode>();
  51. foreach (var n in graph.nodes)
  52. DFS(n);
  53. void DFS(TarversalNode n)
  54. {
  55. if (n.state == State.Black)
  56. return;
  57. n.state = State.Grey;
  58. if (n.node is ParameterNode parameterNode && parameterNode.accessor == ParameterAccessor.Get)
  59. {
  60. foreach (var setter in graph.nodes.Where(x=>
  61. x.node is ParameterNode p &&
  62. p.parameterGUID == parameterNode.parameterGUID &&
  63. p.accessor == ParameterAccessor.Set))
  64. {
  65. if (setter.state == State.White)
  66. DFS(setter);
  67. }
  68. }
  69. else
  70. {
  71. foreach (var input in n.inputs)
  72. {
  73. if (input.state == State.White)
  74. DFS(input);
  75. }
  76. }
  77. n.state = State.Black;
  78. // Only add the node when his children are completely visited
  79. depthFirstNodes.Add(n.node);
  80. }
  81. return depthFirstNodes;
  82. }
  83. public static void FindCyclesInGraph(BaseGraph g, Action<BaseNode> cyclicNode)
  84. {
  85. var graph = ConvertGraphToTraversalGraph(g);
  86. List<TarversalNode> cyclicNodes = new List<TarversalNode>();
  87. foreach (var n in graph.nodes)
  88. DFS(n);
  89. void DFS(TarversalNode n)
  90. {
  91. if (n.state == State.Black)
  92. return;
  93. n.state = State.Grey;
  94. foreach (var input in n.inputs)
  95. {
  96. if (input.state == State.White)
  97. DFS(input);
  98. else if (input.state == State.Grey)
  99. cyclicNodes.Add(n);
  100. }
  101. n.state = State.Black;
  102. }
  103. cyclicNodes.ForEach((tn) => cyclicNode?.Invoke(tn.node));
  104. }
  105. }
  106. }