using System; using System.Collections.Generic; using System.Linq; namespace Encompass { public enum SearchSymbol { start, finish } public class DirectedGraph { protected List _vertices = new List(); protected Dictionary> _edges = new Dictionary>(); public IEnumerable Vertices { get { return _vertices; } } /* * GRAPH STRUCTURE METHODS */ public void AddVertex(T vertex) { if (!VertexExists(vertex)) { _vertices.Add(vertex); _edges.Add(vertex, new List()); } } public void AddVertices(params T[] vertices) { foreach (var vertex in vertices) { AddVertex(vertex); } } public bool VertexExists(T vertex) { return Vertices.Contains(vertex); } public void RemoveVertex(T vertex) { if (VertexExists(vertex)) { foreach (var u in Neighbors(vertex)) { RemoveEdge(vertex, u); } _vertices.Remove(vertex); } } public void AddEdge(T v, T u) { if (VertexExists(v) && VertexExists(u)) { _edges[v].Add(u); } } public void AddEdges(params Tuple[] edges) { foreach (var edge in edges) { AddEdge(edge.Item1, edge.Item2); } } public void RemoveEdge(T v, T u) { _edges[v].Remove(u); } public IEnumerable Neighbors(T vertex) { if (VertexExists(vertex)) { return _edges[vertex]; } else { return Enumerable.Empty(); } } /* * GRAPH ANALYSIS METHODS */ public Dictionary> NodeDFS() { var discovered = new HashSet(); uint time = 0; var output = new Dictionary>(); foreach (var vertex in Vertices) { output.Add(vertex, new Dictionary()); } Action dfsHelper = null; dfsHelper = (T v) => { discovered.Add(v); time += 1; output[v].Add(SearchSymbol.start, time); foreach (var neighbor in Neighbors(v)) { if (!discovered.Contains(neighbor)) { dfsHelper(neighbor); } } time += 1; output[v].Add(SearchSymbol.finish, time); }; foreach (var vertex in Vertices) { if (!discovered.Contains(vertex)) { dfsHelper(vertex); } } return output; } public IEnumerable TopologicalSort() { var dfs = NodeDFS(); var priority = new SortedList(); foreach (var entry in dfs) { priority.Add(entry.Value[SearchSymbol.finish], entry.Key); } return priority.Values.Reverse(); } public IEnumerable> StronglyConnectedComponents() { var preorder = new Dictionary(); var lowlink = new Dictionary(); var sccFound = new Dictionary(); var sccQueue = new Stack(); var result = new List>(); uint preorderCounter = 0; foreach (var source in Vertices) { if (!sccFound.ContainsKey(source)) { var queue = new Stack(); queue.Push(source); while (queue.Count > 0) { var v = queue.Peek(); if (!preorder.ContainsKey(v)) { preorderCounter += 1; preorder[v] = preorderCounter; } var done = true; var vNeighbors = Neighbors(v); foreach (var w in vNeighbors) { if (!preorder.ContainsKey(w)) { queue.Push(w); done = false; break; } } if (done) { lowlink[v] = preorder[v]; foreach (var w in vNeighbors) { if (!sccFound.ContainsKey(w)) { if (preorder[w] > preorder[v]) { lowlink[v] = Math.Min(lowlink[v], lowlink[w]); } else { lowlink[v] = Math.Min(lowlink[v], preorder[w]); } } } queue.Pop(); if (lowlink[v] == preorder[v]) { sccFound[v] = true; var scc = new List(); scc.Add(v); while (sccQueue.Count > 0 && preorder[sccQueue.Peek()] > preorder[v]) { var k = sccQueue.Pop(); sccFound[k] = true; scc.Add(k); } result.Add(scc); } else { sccQueue.Push(v); } } } } } return result; } } }