restructuring

master
Evan Hemsley 2019-10-22 00:28:29 -07:00
parent ad8f97e674
commit 0fb16abcbb
4 changed files with 316 additions and 232 deletions

View File

@ -10,63 +10,67 @@ namespace MoonTools.Core.Graph
finish finish
} }
public class DirectedGraph<T> public class DirectedGraph<TNode, TEdgeData> : IGraph<TNode, TEdgeData>
{ {
private class SimpleCycleComparer : IEqualityComparer<IEnumerable<T>> protected HashSet<TNode> nodes = new HashSet<TNode>();
protected HashSet<(TNode, TNode)> edges = new HashSet<(TNode, TNode)>();
protected Dictionary<(TNode, TNode), TEdgeData> edgesToEdgeData = new Dictionary<(TNode, TNode), TEdgeData>();
protected Dictionary<TNode, HashSet<TNode>> neighbors = new Dictionary<TNode, HashSet<TNode>>();
private class SimpleCycleComparer : IEqualityComparer<IEnumerable<TNode>>
{ {
public bool Equals(IEnumerable<T> x, IEnumerable<T> y) public bool Equals(IEnumerable<TNode> x, IEnumerable<TNode> y)
{ {
return x.SequenceEqual(y); return x.SequenceEqual(y);
} }
public int GetHashCode(IEnumerable<T> obj) public int GetHashCode(IEnumerable<TNode> obj)
{ {
return obj.Aggregate(0, (current, next) => current.GetHashCode() ^ next.GetHashCode()); return obj.Aggregate(0, (current, next) => current.GetHashCode() ^ next.GetHashCode());
} }
} }
protected List<T> _vertices = new List<T>(); public IEnumerable<TNode> Nodes { get { return nodes; } }
protected Dictionary<T, HashSet<T>> _neighbors = new Dictionary<T, HashSet<T>>(); public IEnumerable<(TNode, TNode)> Edges { get { return edges; } }
public IEnumerable<T> Vertices { get { return _vertices; } } public bool Exists(TNode node)
/*
* GRAPH STRUCTURE METHODS
*/
public void AddVertex(T vertex)
{ {
if (!VertexExists(vertex)) return nodes.Contains(node);
}
public bool Exists((TNode, TNode) edge)
{
return edges.Contains(edge);
}
public void AddNode(TNode node)
{
if (!Exists(node))
{ {
_vertices.Add(vertex); nodes.Add(node);
_neighbors.Add(vertex, new HashSet<T>()); neighbors.Add(node, new HashSet<TNode>());
} }
} }
public void AddVertices(params T[] vertices) public void AddNodes(params TNode[] nodes)
{ {
foreach (var vertex in vertices) foreach (var node in nodes)
{ {
AddVertex(vertex); AddNode(node);
} }
} }
public bool VertexExists(T vertex) public void RemoveNode(TNode node)
{ {
return Vertices.Contains(vertex); var edgesToRemove = new List<(TNode, TNode)>();
}
public void RemoveVertex(T vertex) if (Exists(node))
{
var edgesToRemove = new List<Tuple<T, T>>();
if (VertexExists(vertex))
{ {
foreach (var entry in _neighbors) foreach (var entry in neighbors)
{ {
if (entry.Value.Contains(vertex)) if (entry.Value.Contains(node))
{ {
edgesToRemove.Add(Tuple.Create(entry.Key, vertex)); edgesToRemove.Add((entry.Key, node));
} }
} }
@ -75,60 +79,63 @@ namespace MoonTools.Core.Graph
RemoveEdge(edge.Item1, edge.Item2); RemoveEdge(edge.Item1, edge.Item2);
} }
_vertices.Remove(vertex); nodes.Remove(node);
_neighbors.Remove(vertex); neighbors.Remove(node);
} }
} }
public void AddEdge(T v, T u) public void AddEdge(TNode v, TNode u, TEdgeData edgeData)
{ {
if (VertexExists(v) && VertexExists(u)) if (Exists(v) && Exists(u))
{ {
_neighbors[v].Add(u); neighbors[v].Add(u);
edges.Add((v, u));
this.edgesToEdgeData.Add((v, u), edgeData);
} }
} }
public void AddEdges(params Tuple<T, T>[] edges) public void AddEdges(params (TNode, TNode, TEdgeData)[] edges)
{ {
foreach (var edge in edges) foreach (var edge in edges)
{ {
AddEdge(edge.Item1, edge.Item2); AddEdge(edge.Item1, edge.Item2, edge.Item3);
} }
} }
public void RemoveEdge(T v, T u) public void RemoveEdge(TNode v, TNode u)
{ {
_neighbors[v].Remove(u); neighbors[v].Remove(u);
} }
public IEnumerable<T> Neighbors(T vertex) public TEdgeData EdgeData((TNode, TNode) edge)
{ {
if (VertexExists(vertex)) return edgesToEdgeData[edge];
}
public IEnumerable<TNode> Neighbors(TNode node)
{
if (Exists(node))
{ {
return _neighbors[vertex]; return neighbors[node];
} }
else else
{ {
return Enumerable.Empty<T>(); return Enumerable.Empty<TNode>();
} }
} }
/* public Dictionary<TNode, Dictionary<SearchSymbol, uint>> NodeDFS()
* GRAPH ANALYSIS METHODS
*/
public Dictionary<T, Dictionary<SearchSymbol, uint>> NodeDFS()
{ {
var discovered = new HashSet<T>(); var discovered = new HashSet<TNode>();
uint time = 0; uint time = 0;
var output = new Dictionary<T, Dictionary<SearchSymbol, uint>>(); var output = new Dictionary<TNode, Dictionary<SearchSymbol, uint>>();
foreach (var vertex in Vertices) foreach (var node in Nodes)
{ {
output.Add(vertex, new Dictionary<SearchSymbol, uint>()); output.Add(node, new Dictionary<SearchSymbol, uint>());
} }
void dfsHelper(T v) void dfsHelper(TNode v)
{ {
discovered.Add(v); discovered.Add(v);
time++; time++;
@ -146,11 +153,11 @@ namespace MoonTools.Core.Graph
output[v].Add(SearchSymbol.finish, time); output[v].Add(SearchSymbol.finish, time);
} }
foreach (var vertex in Vertices) foreach (var node in Nodes)
{ {
if (!discovered.Contains(vertex)) if (!discovered.Contains(node))
{ {
dfsHelper(vertex); dfsHelper(node);
} }
} }
@ -162,10 +169,10 @@ namespace MoonTools.Core.Graph
return StronglyConnectedComponents().Any((scc) => scc.Count() > 1); return StronglyConnectedComponents().Any((scc) => scc.Count() > 1);
} }
public IEnumerable<T> TopologicalSort() public IEnumerable<TNode> TopologicalSort()
{ {
var dfs = NodeDFS(); var dfs = NodeDFS();
var priority = new SortedList<uint, T>(); var priority = new SortedList<uint, TNode>();
foreach (var entry in dfs) foreach (var entry in dfs)
{ {
priority.Add(entry.Value[SearchSymbol.finish], entry.Key); priority.Add(entry.Value[SearchSymbol.finish], entry.Key);
@ -173,22 +180,22 @@ namespace MoonTools.Core.Graph
return priority.Values.Reverse(); return priority.Values.Reverse();
} }
public IEnumerable<IEnumerable<T>> StronglyConnectedComponents() public IEnumerable<IEnumerable<TNode>> StronglyConnectedComponents()
{ {
var preorder = new Dictionary<T, uint>(); var preorder = new Dictionary<TNode, uint>();
var lowlink = new Dictionary<T, uint>(); var lowlink = new Dictionary<TNode, uint>();
var sccFound = new Dictionary<T, bool>(); var sccFound = new Dictionary<TNode, bool>();
var sccQueue = new Stack<T>(); var sccQueue = new Stack<TNode>();
var result = new List<List<T>>(); var result = new List<List<TNode>>();
uint preorderCounter = 0; uint preorderCounter = 0;
foreach (var source in Vertices) foreach (var source in Nodes)
{ {
if (!sccFound.ContainsKey(source)) if (!sccFound.ContainsKey(source))
{ {
var queue = new Stack<T>(); var queue = new Stack<TNode>();
queue.Push(source); queue.Push(source);
while (queue.Count > 0) while (queue.Count > 0)
@ -233,7 +240,7 @@ namespace MoonTools.Core.Graph
if (lowlink[v] == preorder[v]) if (lowlink[v] == preorder[v])
{ {
sccFound[v] = true; sccFound[v] = true;
var scc = new List<T> var scc = new List<TNode>
{ {
v v
}; };
@ -257,11 +264,11 @@ namespace MoonTools.Core.Graph
return result; return result;
} }
public IEnumerable<IEnumerable<T>> SimpleCycles() public IEnumerable<IEnumerable<TNode>> SimpleCycles()
{ {
void unblock(T thisnode, HashSet<T> blocked, Dictionary<T, HashSet<T>> B) void unblock(TNode thisnode, HashSet<TNode> blocked, Dictionary<TNode, HashSet<TNode>> B)
{ {
var stack = new Stack<T>(); var stack = new Stack<TNode>();
stack.Push(thisnode); stack.Push(thisnode);
while (stack.Count > 0) while (stack.Count > 0)
@ -285,10 +292,10 @@ namespace MoonTools.Core.Graph
} }
} }
List<List<T>> result = new List<List<T>>(); List<List<TNode>> result = new List<List<TNode>>();
var subGraph = Clone(); var subGraph = Clone();
var sccs = new Stack<IEnumerable<T>>(); var sccs = new Stack<IEnumerable<TNode>>();
foreach (var scc in StronglyConnectedComponents()) foreach (var scc in StronglyConnectedComponents())
{ {
sccs.Push(scc); sccs.Push(scc);
@ -296,18 +303,18 @@ namespace MoonTools.Core.Graph
while (sccs.Count > 0) while (sccs.Count > 0)
{ {
var scc = new Stack<T>(sccs.Pop()); var scc = new Stack<TNode>(sccs.Pop());
var startNode = scc.Pop(); var startNode = scc.Pop();
var path = new Stack<T>(); var path = new Stack<TNode>();
path.Push(startNode); path.Push(startNode);
var blocked = new HashSet<T> var blocked = new HashSet<TNode>
{ {
startNode startNode
}; };
var closed = new HashSet<T>(); var closed = new HashSet<TNode>();
var B = new Dictionary<T, HashSet<T>>(); var B = new Dictionary<TNode, HashSet<TNode>>();
var stack = new Stack<Tuple<T, Stack<T>>>(); var stack = new Stack<Tuple<TNode, Stack<TNode>>>();
stack.Push(Tuple.Create(startNode, new Stack<T>(subGraph.Neighbors(startNode)))); stack.Push(Tuple.Create(startNode, new Stack<TNode>(subGraph.Neighbors(startNode))));
while (stack.Count > 0) while (stack.Count > 0)
{ {
@ -321,7 +328,7 @@ namespace MoonTools.Core.Graph
if (nextNode.Equals(startNode)) if (nextNode.Equals(startNode))
{ {
var resultPath = new List<T>(); var resultPath = new List<TNode>();
foreach (var v in path) foreach (var v in path)
{ {
resultPath.Add(v); resultPath.Add(v);
@ -335,7 +342,7 @@ namespace MoonTools.Core.Graph
else if (!blocked.Contains(nextNode)) else if (!blocked.Contains(nextNode))
{ {
path.Push(nextNode); path.Push(nextNode);
stack.Push(Tuple.Create(nextNode, new Stack<T>(subGraph.Neighbors(nextNode)))); stack.Push(Tuple.Create(nextNode, new Stack<TNode>(subGraph.Neighbors(nextNode))));
closed.Remove(nextNode); closed.Remove(nextNode);
blocked.Add(nextNode); blocked.Add(nextNode);
continue; continue;
@ -354,7 +361,7 @@ namespace MoonTools.Core.Graph
{ {
if (!B.ContainsKey(neighbor)) if (!B.ContainsKey(neighbor))
{ {
B[neighbor] = new HashSet<T>(); B[neighbor] = new HashSet<TNode>();
} }
B[neighbor].Add(thisnode); B[neighbor].Add(thisnode);
} }
@ -365,7 +372,7 @@ namespace MoonTools.Core.Graph
} }
} }
subGraph.RemoveVertex(startNode); subGraph.RemoveNode(startNode);
var H = subGraph.SubGraph(scc.ToArray()); var H = subGraph.SubGraph(scc.ToArray());
var HSccs = H.StronglyConnectedComponents(); var HSccs = H.StronglyConnectedComponents();
foreach (var HScc in HSccs) foreach (var HScc in HSccs)
@ -377,37 +384,37 @@ namespace MoonTools.Core.Graph
return result.Distinct(new SimpleCycleComparer()); return result.Distinct(new SimpleCycleComparer());
} }
public DirectedGraph<T> Clone() public DirectedGraph<TNode, TEdgeData> Clone()
{ {
var clone = new DirectedGraph<T>(); var clone = new DirectedGraph<TNode, TEdgeData>();
clone.AddVertices(Vertices.ToArray()); clone.AddNodes(Nodes.ToArray());
foreach (var v in Vertices) foreach (var v in Nodes)
{ {
foreach (var n in Neighbors(v)) foreach (var n in Neighbors(v))
{ {
clone.AddEdge(v, n); clone.AddEdge(v, n, EdgeData((v, n)));
} }
} }
return clone; return clone;
} }
public DirectedGraph<T> SubGraph(params T[] subVertices) public DirectedGraph<TNode, TEdgeData> SubGraph(params TNode[] subVertices)
{ {
var subGraph = new DirectedGraph<T>(); var subGraph = new DirectedGraph<TNode, TEdgeData>();
subGraph.AddVertices(subVertices.ToArray()); subGraph.AddNodes(subVertices.ToArray());
foreach (var v in Vertices) foreach (var n in Nodes)
{ {
if (Vertices.Contains(v)) if (Nodes.Contains(n))
{ {
var neighbors = Neighbors(v); var neighbors = Neighbors(n);
foreach (var u in neighbors) foreach (var u in neighbors)
{ {
if (subVertices.Contains(u)) if (subVertices.Contains(u))
{ {
subGraph.AddEdge(v, u); subGraph.AddEdge(n, u, EdgeData((n, u)));
} }
} }
} }
@ -415,5 +422,11 @@ namespace MoonTools.Core.Graph
return subGraph; return subGraph;
} }
public void Clear()
{
nodes.Clear();
neighbors.Clear();
}
} }
} }

View File

@ -0,0 +1,12 @@
using System;
namespace MoonTools.Core.Graph
{
public class InvalidVertexException : Exception
{
public InvalidVertexException(
string format,
params object[] args
) : base(string.Format(format, args)) { }
}
}

15
Graph/IGraph.cs Normal file
View File

@ -0,0 +1,15 @@
using System.Collections.Generic;
namespace MoonTools.Core.Graph
{
public interface IGraph<TNode, TEdgeData>
{
IEnumerable<TNode> Nodes { get; }
void AddNode(TNode node);
void AddNodes(params TNode[] nodes);
bool Exists(TNode node);
IEnumerable<TNode> Neighbors(TNode node);
void Clear();
}
}

View File

@ -8,34 +8,38 @@ using MoonTools.Core.Graph;
namespace Tests namespace Tests
{ {
struct EdgeData { }
public class DirectedGraphTest public class DirectedGraphTest
{ {
[Test] EdgeData dummyEdgeData;
public void AddVertex()
{
var myGraph = new DirectedGraph<int>();
myGraph.AddVertex(4);
Assert.That(myGraph.Vertices, Does.Contain(4)); [Test]
public void AddNode()
{
var myGraph = new DirectedGraph<int, EdgeData>();
myGraph.AddNode(4);
Assert.That(myGraph.Nodes, Does.Contain(4));
} }
[Test] [Test]
public void AddVertices() public void AddNodes()
{ {
var myGraph = new DirectedGraph<int>(); var myGraph = new DirectedGraph<int, EdgeData>();
myGraph.AddVertices(4, 20, 69); myGraph.AddNodes(4, 20, 69);
Assert.IsTrue(myGraph.VertexExists(4)); Assert.IsTrue(myGraph.Exists(4));
Assert.IsTrue(myGraph.VertexExists(20)); Assert.IsTrue(myGraph.Exists(20));
Assert.IsTrue(myGraph.VertexExists(69)); Assert.IsTrue(myGraph.Exists(69));
} }
[Test] [Test]
public void AddEdge() public void AddEdge()
{ {
var myGraph = new DirectedGraph<int>(); var myGraph = new DirectedGraph<int, EdgeData>();
myGraph.AddVertices(5, 6); myGraph.AddNodes(5, 6);
myGraph.AddEdge(5, 6); myGraph.AddEdge(5, 6, dummyEdgeData);
Assert.That(myGraph.Neighbors(5), Does.Contain(6)); Assert.That(myGraph.Neighbors(5), Does.Contain(6));
} }
@ -43,13 +47,13 @@ namespace Tests
[Test] [Test]
public void AddEdges() public void AddEdges()
{ {
var myGraph = new DirectedGraph<int>(); var myGraph = new DirectedGraph<int, EdgeData>();
myGraph.AddVertices(1, 2, 3, 4); myGraph.AddNodes(1, 2, 3, 4);
myGraph.AddEdges( myGraph.AddEdges(
Tuple.Create(1, 2), (1, 2, dummyEdgeData),
Tuple.Create(2, 3), (2, 3, dummyEdgeData),
Tuple.Create(2, 4), (2, 4, dummyEdgeData),
Tuple.Create(3, 4) (3, 4, dummyEdgeData)
); );
Assert.That(myGraph.Neighbors(1), Does.Contain(2)); Assert.That(myGraph.Neighbors(1), Does.Contain(2));
@ -62,13 +66,13 @@ namespace Tests
[Test] [Test]
public void RemoveEdge() public void RemoveEdge()
{ {
var myGraph = new DirectedGraph<int>(); var myGraph = new DirectedGraph<int, EdgeData>();
myGraph.AddVertices(1, 2, 3, 4); myGraph.AddNodes(1, 2, 3, 4);
myGraph.AddEdges( myGraph.AddEdges(
Tuple.Create(1, 2), (1, 2, dummyEdgeData),
Tuple.Create(2, 3), (2, 3, dummyEdgeData),
Tuple.Create(2, 4), (2, 4, dummyEdgeData),
Tuple.Create(3, 4) (3, 4, dummyEdgeData)
); );
myGraph.RemoveEdge(2, 3); myGraph.RemoveEdge(2, 3);
@ -78,20 +82,20 @@ namespace Tests
} }
[Test] [Test]
public void RemoveVertex() public void RemoveNode()
{ {
var myGraph = new DirectedGraph<int>(); var myGraph = new DirectedGraph<int, EdgeData>();
myGraph.AddVertices(1, 2, 3, 4); myGraph.AddNodes(1, 2, 3, 4);
myGraph.AddEdges( myGraph.AddEdges(
Tuple.Create(1, 2), (1, 2, dummyEdgeData),
Tuple.Create(2, 3), (2, 3, dummyEdgeData),
Tuple.Create(2, 4), (2, 4, dummyEdgeData),
Tuple.Create(3, 4) (3, 4, dummyEdgeData)
); );
myGraph.RemoveVertex(2); myGraph.RemoveNode(2);
myGraph.Vertices.Should().NotContain(2); myGraph.Nodes.Should().NotContain(2);
myGraph.Neighbors(1).Should().NotContain(2); myGraph.Neighbors(1).Should().NotContain(2);
myGraph.Neighbors(3).Should().Contain(4); myGraph.Neighbors(3).Should().Contain(4);
} }
@ -99,12 +103,12 @@ namespace Tests
[Test] [Test]
public void NodeDFS() public void NodeDFS()
{ {
var myGraph = new DirectedGraph<char>(); var myGraph = new DirectedGraph<char, EdgeData>();
myGraph.AddVertices('a', 'b', 'c', 'd'); myGraph.AddNodes('a', 'b', 'c', 'd');
myGraph.AddEdges( myGraph.AddEdges(
Tuple.Create('a', 'b'), ('a', 'b', dummyEdgeData),
Tuple.Create('a', 'c'), ('a', 'c', dummyEdgeData),
Tuple.Create('b', 'd') ('b', 'd', dummyEdgeData)
); );
var result = myGraph.NodeDFS(); var result = myGraph.NodeDFS();
@ -125,13 +129,13 @@ namespace Tests
[Test] [Test]
public void TopologicalSortSimple() public void TopologicalSortSimple()
{ {
var simpleGraph = new DirectedGraph<char>(); var simpleGraph = new DirectedGraph<char, EdgeData>();
simpleGraph.AddVertices('a', 'b', 'c', 'd'); simpleGraph.AddNodes('a', 'b', 'c', 'd');
simpleGraph.AddEdges( simpleGraph.AddEdges(
Tuple.Create('a', 'b'), ('a', 'b', dummyEdgeData),
Tuple.Create('a', 'c'), ('a', 'c', dummyEdgeData),
Tuple.Create('b', 'a'), ('b', 'a', dummyEdgeData),
Tuple.Create('b', 'd') ('b', 'd', dummyEdgeData)
); );
Assert.That(simpleGraph.TopologicalSort(), Is.EqualTo(new char[] { 'a', 'c', 'b', 'd' })); Assert.That(simpleGraph.TopologicalSort(), Is.EqualTo(new char[] { 'a', 'c', 'b', 'd' }));
@ -140,17 +144,17 @@ namespace Tests
[Test] [Test]
public void TopologicalSortComplex() public void TopologicalSortComplex()
{ {
var complexGraph = new DirectedGraph<char>(); var complexGraph = new DirectedGraph<char, EdgeData>();
complexGraph.AddVertices('a', 'b', 'c', 'd', 'e', 'f', 'g', 't', 'm'); complexGraph.AddNodes('a', 'b', 'c', 'd', 'e', 'f', 'g', 't', 'm');
complexGraph.AddEdges( complexGraph.AddEdges(
Tuple.Create('a', 'b'), ('a', 'b', dummyEdgeData),
Tuple.Create('a', 'c'), ('a', 'c', dummyEdgeData),
Tuple.Create('a', 'd'), ('a', 'd', dummyEdgeData),
Tuple.Create('b', 'f'), ('b', 'f', dummyEdgeData),
Tuple.Create('b', 'g'), ('b', 'g', dummyEdgeData),
Tuple.Create('c', 'g'), ('c', 'g', dummyEdgeData),
Tuple.Create('e', 't'), ('e', 't', dummyEdgeData),
Tuple.Create('t', 'm') ('t', 'm', dummyEdgeData)
); );
Assert.That( Assert.That(
@ -162,13 +166,13 @@ namespace Tests
[Test] [Test]
public void StronglyConnectedComponentsSimple() public void StronglyConnectedComponentsSimple()
{ {
var simpleGraph = new DirectedGraph<int>(); var simpleGraph = new DirectedGraph<int, EdgeData>();
simpleGraph.AddVertices(1, 2, 3); simpleGraph.AddNodes(1, 2, 3);
simpleGraph.AddEdges( simpleGraph.AddEdges(
Tuple.Create(1, 2), (1, 2, dummyEdgeData),
Tuple.Create(2, 3), (2, 3, dummyEdgeData),
Tuple.Create(3, 2), (3, 2, dummyEdgeData),
Tuple.Create(2, 1) (2, 1, dummyEdgeData)
); );
var result = simpleGraph.StronglyConnectedComponents(); var result = simpleGraph.StronglyConnectedComponents();
@ -181,15 +185,15 @@ namespace Tests
[Test] [Test]
public void StronglyConnectedComponentsMedium() public void StronglyConnectedComponentsMedium()
{ {
var mediumGraph = new DirectedGraph<int>(); var mediumGraph = new DirectedGraph<int, EdgeData>();
mediumGraph.AddVertices(1, 2, 3, 4); mediumGraph.AddNodes(1, 2, 3, 4);
mediumGraph.AddEdges( mediumGraph.AddEdges(
Tuple.Create(1, 2), (1, 2, dummyEdgeData),
Tuple.Create(1, 3), (1, 3, dummyEdgeData),
Tuple.Create(1, 4), (1, 4, dummyEdgeData),
Tuple.Create(4, 2), (4, 2, dummyEdgeData),
Tuple.Create(3, 4), (3, 4, dummyEdgeData),
Tuple.Create(2, 3) (2, 3, dummyEdgeData)
); );
var result = mediumGraph.StronglyConnectedComponents(); var result = mediumGraph.StronglyConnectedComponents();
@ -204,21 +208,21 @@ namespace Tests
[Test] [Test]
public void StronglyConnectedComponentsComplex() public void StronglyConnectedComponentsComplex()
{ {
var complexGraph = new DirectedGraph<int>(); var complexGraph = new DirectedGraph<int, EdgeData>();
complexGraph.AddVertices(1, 2, 3, 4, 5, 6, 7, 8); complexGraph.AddNodes(1, 2, 3, 4, 5, 6, 7, 8);
complexGraph.AddEdges( complexGraph.AddEdges(
Tuple.Create(1, 2), (1, 2, dummyEdgeData),
Tuple.Create(2, 3), (2, 3, dummyEdgeData),
Tuple.Create(2, 8), (2, 8, dummyEdgeData),
Tuple.Create(3, 4), (3, 4, dummyEdgeData),
Tuple.Create(3, 7), (3, 7, dummyEdgeData),
Tuple.Create(4, 5), (4, 5, dummyEdgeData),
Tuple.Create(5, 3), (5, 3, dummyEdgeData),
Tuple.Create(5, 6), (5, 6, dummyEdgeData),
Tuple.Create(7, 4), (7, 4, dummyEdgeData),
Tuple.Create(7, 6), (7, 6, dummyEdgeData),
Tuple.Create(8, 1), (8, 1, dummyEdgeData),
Tuple.Create(8, 7) (8, 7, dummyEdgeData)
); );
var result = complexGraph.StronglyConnectedComponents(); var result = complexGraph.StronglyConnectedComponents();
@ -235,19 +239,19 @@ namespace Tests
[Test] [Test]
public void Clone() public void Clone()
{ {
var myGraph = new DirectedGraph<int>(); var myGraph = new DirectedGraph<int, EdgeData>();
myGraph.AddVertices(1, 2, 3, 4); myGraph.AddNodes(1, 2, 3, 4);
myGraph.AddEdges( myGraph.AddEdges(
Tuple.Create(1, 1), (1, 1, dummyEdgeData),
Tuple.Create(1, 2), (1, 2, dummyEdgeData),
Tuple.Create(2, 3), (2, 3, dummyEdgeData),
Tuple.Create(2, 1), (2, 1, dummyEdgeData),
Tuple.Create(3, 4) (3, 4, dummyEdgeData)
); );
var clone = myGraph.Clone(); var clone = myGraph.Clone();
Assert.That(clone, Is.Not.EqualTo(myGraph)); Assert.That(clone, Is.Not.EqualTo(myGraph));
clone.Vertices.Should().BeEquivalentTo(1, 2, 3, 4); clone.Nodes.Should().BeEquivalentTo(1, 2, 3, 4);
clone.Neighbors(1).Should().BeEquivalentTo(1, 2); clone.Neighbors(1).Should().BeEquivalentTo(1, 2);
clone.Neighbors(2).Should().BeEquivalentTo(3, 1); clone.Neighbors(2).Should().BeEquivalentTo(3, 1);
clone.Neighbors(3).Should().BeEquivalentTo(4); clone.Neighbors(3).Should().BeEquivalentTo(4);
@ -256,18 +260,18 @@ namespace Tests
[Test] [Test]
public void SubGraph() public void SubGraph()
{ {
var myGraph = new DirectedGraph<int>(); var myGraph = new DirectedGraph<int, EdgeData>();
myGraph.AddVertices(1, 2, 3, 4); myGraph.AddNodes(1, 2, 3, 4);
myGraph.AddEdges( myGraph.AddEdges(
Tuple.Create(1, 1), (1, 1, dummyEdgeData),
Tuple.Create(1, 2), (1, 2, dummyEdgeData),
Tuple.Create(2, 3), (2, 3, dummyEdgeData),
Tuple.Create(2, 1), (2, 1, dummyEdgeData),
Tuple.Create(3, 4) (3, 4, dummyEdgeData)
); );
var subGraph = myGraph.SubGraph(1, 2, 3); var subGraph = myGraph.SubGraph(1, 2, 3);
subGraph.Vertices.Should().BeEquivalentTo(1, 2, 3); subGraph.Nodes.Should().BeEquivalentTo(1, 2, 3);
subGraph.Neighbors(1).Should().BeEquivalentTo(1, 2); subGraph.Neighbors(1).Should().BeEquivalentTo(1, 2);
subGraph.Neighbors(2).Should().BeEquivalentTo(1, 3); subGraph.Neighbors(2).Should().BeEquivalentTo(1, 3);
subGraph.Neighbors(3).Should().NotContain(4); subGraph.Neighbors(3).Should().NotContain(4);
@ -276,16 +280,16 @@ namespace Tests
[Test] [Test]
public void SimpleCyclesSimple() public void SimpleCyclesSimple()
{ {
var myGraph = new DirectedGraph<int>(); var myGraph = new DirectedGraph<int, EdgeData>();
myGraph.AddVertices(0, 1, 2); myGraph.AddNodes(0, 1, 2);
myGraph.AddEdges( myGraph.AddEdges(
Tuple.Create(0, 0), (0, 0, dummyEdgeData),
Tuple.Create(0, 1), (0, 1, dummyEdgeData),
Tuple.Create(0, 2), (0, 2, dummyEdgeData),
Tuple.Create(1, 2), (1, 2, dummyEdgeData),
Tuple.Create(2, 0), (2, 0, dummyEdgeData),
Tuple.Create(2, 1), (2, 1, dummyEdgeData),
Tuple.Create(2, 2) (2, 2, dummyEdgeData)
); );
var result = myGraph.SimpleCycles(); var result = myGraph.SimpleCycles();
@ -307,23 +311,22 @@ namespace Tests
[Test] [Test]
public void SimpleCyclesComplex() public void SimpleCyclesComplex()
{ {
var myGraph = new DirectedGraph<int>(); var myGraph = new DirectedGraph<int, EdgeData>();
myGraph.AddVertices(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); myGraph.AddNodes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
myGraph.AddEdges( myGraph.AddEdges(
Tuple.Create(0, 1), (0, 1, dummyEdgeData),
Tuple.Create(1, 2), (1, 2, dummyEdgeData),
Tuple.Create(2, 3), (2, 3, dummyEdgeData),
Tuple.Create(3, 0), (3, 0, dummyEdgeData),
Tuple.Create(0, 3), (0, 3, dummyEdgeData),
Tuple.Create(3, 4), (3, 4, dummyEdgeData),
Tuple.Create(4, 5), (4, 5, dummyEdgeData),
Tuple.Create(5, 0), (5, 0, dummyEdgeData),
Tuple.Create(0, 1), (1, 6, dummyEdgeData),
Tuple.Create(1, 6), (6, 7, dummyEdgeData),
Tuple.Create(6, 7), (7, 8, dummyEdgeData),
Tuple.Create(7, 8), (8, 0, dummyEdgeData),
Tuple.Create(8, 0), (8, 9, dummyEdgeData)
Tuple.Create(8, 9)
); );
var result = myGraph.SimpleCycles(); var result = myGraph.SimpleCycles();
@ -344,13 +347,13 @@ namespace Tests
[Test] [Test]
public void Cyclic() public void Cyclic()
{ {
var myGraph = new DirectedGraph<int>(); var myGraph = new DirectedGraph<int, EdgeData>();
myGraph.AddVertices(1, 2, 3, 4); myGraph.AddNodes(1, 2, 3, 4);
myGraph.AddEdges( myGraph.AddEdges(
Tuple.Create(1, 2), (1, 2, dummyEdgeData),
Tuple.Create(2, 3), (2, 3, dummyEdgeData),
Tuple.Create(3, 1), (3, 1, dummyEdgeData),
Tuple.Create(3, 4) (3, 4, dummyEdgeData)
); );
Assert.That(myGraph.Cyclic(), Is.True); Assert.That(myGraph.Cyclic(), Is.True);
@ -359,15 +362,56 @@ namespace Tests
[Test] [Test]
public void Acyclic() public void Acyclic()
{ {
var myGraph = new DirectedGraph<int>(); var myGraph = new DirectedGraph<int, EdgeData>();
myGraph.AddVertices(1, 2, 3, 4); myGraph.AddNodes(1, 2, 3, 4);
myGraph.AddEdges( myGraph.AddEdges(
Tuple.Create(1, 2), (1, 2, dummyEdgeData),
Tuple.Create(2, 3), (2, 3, dummyEdgeData),
Tuple.Create(3, 4) (3, 4, dummyEdgeData)
); );
Assert.That(myGraph.Cyclic(), Is.False); Assert.That(myGraph.Cyclic(), Is.False);
} }
[Test]
public void Clear()
{
var myGraph = new DirectedGraph<int, EdgeData>();
myGraph.AddNodes(1, 2, 3, 4);
myGraph.AddEdges(
(1, 2, dummyEdgeData),
(2, 3, dummyEdgeData),
(3, 4, dummyEdgeData)
);
myGraph.Clear();
myGraph.Nodes.Should().BeEmpty();
}
[Test]
public void EdgeExists()
{
var myGraph = new DirectedGraph<int, EdgeData>();
myGraph.AddNodes(1, 2);
myGraph.AddEdge(1, 2, dummyEdgeData);
myGraph.Exists((1, 2)).Should().BeTrue();
}
struct TestEdgeData
{
public int testNum;
}
[Test]
public void EdgeData()
{
var myGraph = new DirectedGraph<int, TestEdgeData>();
myGraph.AddNodes(1, 2);
myGraph.AddEdge(1, 2, new TestEdgeData { testNum = 4 });
myGraph.EdgeData((1, 2)).testNum.Should().Be(4);
}
} }
} }