diff --git a/src/encompass-cs.csproj b/src/encompass-cs.csproj
index a625a72..72e33ce 100644
--- a/src/encompass-cs.csproj
+++ b/src/encompass-cs.csproj
@@ -15,5 +15,6 @@
+
\ No newline at end of file
diff --git a/src/graph/DirectedGraph.cs b/src/graph/DirectedGraph.cs
new file mode 100644
index 0000000..9aba493
--- /dev/null
+++ b/src/graph/DirectedGraph.cs
@@ -0,0 +1,230 @@
+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;
+ }
+ }
+}
diff --git a/test/DirectedGraphTest.cs b/test/DirectedGraphTest.cs
new file mode 100644
index 0000000..a7e2652
--- /dev/null
+++ b/test/DirectedGraphTest.cs
@@ -0,0 +1,216 @@
+using NUnit.Framework;
+using FluentAssertions;
+
+using System;
+using System.Linq;
+
+using Encompass;
+using System.Collections.Generic;
+
+namespace Tests
+{
+ public class DirectedGraphTest
+ {
+ [Test]
+ public void AddVertex()
+ {
+ var myGraph = new DirectedGraph();
+ myGraph.AddVertex(4);
+
+ Assert.That(myGraph.Vertices, Does.Contain(4));
+ }
+
+ [Test]
+ public void AddVertices()
+ {
+ var myGraph = new DirectedGraph();
+ myGraph.AddVertices(4, 20, 69);
+
+ Assert.IsTrue(myGraph.VertexExists(4));
+ Assert.IsTrue(myGraph.VertexExists(20));
+ Assert.IsTrue(myGraph.VertexExists(69));
+ }
+
+ [Test]
+ public void AddEdge()
+ {
+ var myGraph = new DirectedGraph();
+ myGraph.AddVertices(5, 6);
+ myGraph.AddEdge(5, 6);
+
+ Assert.That(myGraph.Neighbors(5), Does.Contain(6));
+ }
+
+ [Test]
+ public void AddEdges()
+ {
+ var myGraph = new DirectedGraph();
+ myGraph.AddVertices(1, 2, 3, 4);
+ myGraph.AddEdges(
+ Tuple.Create(1, 2),
+ Tuple.Create(2, 3),
+ Tuple.Create(2, 4),
+ Tuple.Create(3, 4)
+ );
+
+ Assert.That(myGraph.Neighbors(1), Does.Contain(2));
+ Assert.That(myGraph.Neighbors(2), Does.Contain(3));
+ Assert.That(myGraph.Neighbors(2), Does.Contain(4));
+ Assert.That(myGraph.Neighbors(3), Does.Contain(4));
+ Assert.That(myGraph.Neighbors(1), Does.Not.Contain(4));
+ }
+
+ [Test]
+ public void RemoveEdge()
+ {
+ var myGraph = new DirectedGraph();
+ myGraph.AddVertices(1, 2, 3, 4);
+ myGraph.AddEdges(
+ Tuple.Create(1, 2),
+ Tuple.Create(2, 3),
+ Tuple.Create(2, 4),
+ Tuple.Create(3, 4)
+ );
+
+ myGraph.RemoveEdge(2, 3);
+
+ Assert.That(myGraph.Neighbors(2), Does.Not.Contain(3));
+ Assert.That(myGraph.Neighbors(2), Does.Contain(4));
+ }
+ [Test]
+ public void NodeDFS()
+ {
+ var myGraph = new DirectedGraph();
+ myGraph.AddVertices('a', 'b', 'c', 'd');
+ myGraph.AddEdges(
+ Tuple.Create('a', 'b'),
+ Tuple.Create('a', 'c'),
+ Tuple.Create('b', 'd')
+ );
+
+ var result = myGraph.NodeDFS();
+
+ Assert.That(result['a'][SearchSymbol.start], Is.EqualTo(1));
+ Assert.That(result['a'][SearchSymbol.finish], Is.EqualTo(8));
+
+ Assert.That(result['b'][SearchSymbol.start], Is.EqualTo(2));
+ Assert.That(result['b'][SearchSymbol.finish], Is.EqualTo(5));
+
+ Assert.That(result['c'][SearchSymbol.start], Is.EqualTo(6));
+ Assert.That(result['c'][SearchSymbol.finish], Is.EqualTo(7));
+
+ Assert.That(result['d'][SearchSymbol.start], Is.EqualTo(3));
+ Assert.That(result['d'][SearchSymbol.finish], Is.EqualTo(4));
+ }
+
+ [Test]
+ public void TopologicalSortSimple()
+ {
+ var simpleGraph = new DirectedGraph();
+ simpleGraph.AddVertices('a', 'b', 'c', 'd');
+ simpleGraph.AddEdges(
+ Tuple.Create('a', 'b'),
+ Tuple.Create('a', 'c'),
+ Tuple.Create('b', 'a'),
+ Tuple.Create('b', 'd')
+ );
+
+ Assert.That(simpleGraph.TopologicalSort(), Is.EqualTo(new char[] { 'a', 'c', 'b', 'd' }));
+ }
+
+ [Test]
+ public void TopologicalSortComplex()
+ {
+ var complexGraph = new DirectedGraph();
+ complexGraph.AddVertices('a', 'b', 'c', 'd', 'e', 'f', 'g', 't', 'm');
+ complexGraph.AddEdges(
+ Tuple.Create('a', 'b'),
+ Tuple.Create('a', 'c'),
+ Tuple.Create('a', 'd'),
+ Tuple.Create('b', 'f'),
+ Tuple.Create('b', 'g'),
+ Tuple.Create('c', 'g'),
+ Tuple.Create('e', 't'),
+ Tuple.Create('t', 'm')
+ );
+
+ Assert.That(
+ complexGraph.TopologicalSort(),
+ Is.EqualTo(new char[] { 'e', 't', 'm', 'a', 'd', 'c', 'b', 'g', 'f' })
+ );
+ }
+
+ [Test]
+ public void StronglyConnectedComponentsSimple()
+ {
+ var simpleGraph = new DirectedGraph();
+ simpleGraph.AddVertices(1, 2, 3);
+ simpleGraph.AddEdges(
+ Tuple.Create(1, 2),
+ Tuple.Create(2, 3),
+ Tuple.Create(3, 2),
+ Tuple.Create(2, 1)
+ );
+
+ var result = simpleGraph.StronglyConnectedComponents();
+ var scc = new int[] { 1, 2, 3 };
+
+ result.Should().ContainEquivalentOf(scc);
+ Assert.That(result.Count, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void StronglyConnectedComponentsMedium()
+ {
+ var mediumGraph = new DirectedGraph();
+ mediumGraph.AddVertices(1, 2, 3, 4);
+ mediumGraph.AddEdges(
+ Tuple.Create(1, 2),
+ Tuple.Create(1, 3),
+ Tuple.Create(1, 4),
+ Tuple.Create(4, 2),
+ Tuple.Create(3, 4),
+ Tuple.Create(2, 3)
+ );
+
+ var result = mediumGraph.StronglyConnectedComponents();
+ var sccA = new int[] { 2, 3, 4 };
+ var sccB = new int[] { 1 };
+
+ result.Should().ContainEquivalentOf(sccA);
+ result.Should().ContainEquivalentOf(sccB);
+ Assert.That(result.Count, Is.EqualTo(2));
+ }
+
+ [Test]
+ public void StronglyConnectedComponentsComplex()
+ {
+ var complexGraph = new DirectedGraph();
+ complexGraph.AddVertices(1, 2, 3, 4, 5, 6, 7, 8);
+ complexGraph.AddEdges(
+ Tuple.Create(1, 2),
+ Tuple.Create(2, 3),
+ Tuple.Create(2, 8),
+ Tuple.Create(3, 4),
+ Tuple.Create(3, 7),
+ Tuple.Create(4, 5),
+ Tuple.Create(5, 3),
+ Tuple.Create(5, 6),
+ Tuple.Create(7, 4),
+ Tuple.Create(7, 6),
+ Tuple.Create(8, 1),
+ Tuple.Create(8, 7)
+ );
+
+ var result = complexGraph.StronglyConnectedComponents();
+ var sccA = new int[] { 3, 4, 5, 7 };
+ var sccB = new int[] { 1, 2, 8 };
+ var sccC = new int[] { 6 };
+
+ result.Should().ContainEquivalentOf(sccA);
+ result.Should().ContainEquivalentOf(sccB);
+ result.Should().ContainEquivalentOf(sccC);
+ Assert.That(result.Count, Is.EqualTo(3));
+ }
+ }
+}
diff --git a/test/test.csproj b/test/test.csproj
index 7b887e7..e69bcea 100644
--- a/test/test.csproj
+++ b/test/test.csproj
@@ -5,6 +5,7 @@
false
+
@@ -13,5 +14,6 @@
+
\ No newline at end of file