restructuring
parent
ad8f97e674
commit
0fb16abcbb
|
@ -10,63 +10,67 @@ namespace MoonTools.Core.Graph
|
|||
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);
|
||||
}
|
||||
|
||||
public int GetHashCode(IEnumerable<T> obj)
|
||||
public int GetHashCode(IEnumerable<TNode> obj)
|
||||
{
|
||||
return obj.Aggregate(0, (current, next) => current.GetHashCode() ^ next.GetHashCode());
|
||||
}
|
||||
}
|
||||
|
||||
protected List<T> _vertices = new List<T>();
|
||||
protected Dictionary<T, HashSet<T>> _neighbors = new Dictionary<T, HashSet<T>>();
|
||||
public IEnumerable<TNode> Nodes { get { return nodes; } }
|
||||
public IEnumerable<(TNode, TNode)> Edges { get { return edges; } }
|
||||
|
||||
public IEnumerable<T> Vertices { get { return _vertices; } }
|
||||
|
||||
/*
|
||||
* GRAPH STRUCTURE METHODS
|
||||
*/
|
||||
|
||||
public void AddVertex(T vertex)
|
||||
public bool Exists(TNode node)
|
||||
{
|
||||
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);
|
||||
_neighbors.Add(vertex, new HashSet<T>());
|
||||
nodes.Add(node);
|
||||
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)
|
||||
{
|
||||
var edgesToRemove = new List<Tuple<T, T>>();
|
||||
|
||||
if (VertexExists(vertex))
|
||||
if (Exists(node))
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
_vertices.Remove(vertex);
|
||||
_neighbors.Remove(vertex);
|
||||
nodes.Remove(node);
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
return Enumerable.Empty<T>();
|
||||
return Enumerable.Empty<TNode>();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* GRAPH ANALYSIS METHODS
|
||||
*/
|
||||
|
||||
public Dictionary<T, Dictionary<SearchSymbol, uint>> NodeDFS()
|
||||
public Dictionary<TNode, Dictionary<SearchSymbol, uint>> NodeDFS()
|
||||
{
|
||||
var discovered = new HashSet<T>();
|
||||
var discovered = new HashSet<TNode>();
|
||||
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);
|
||||
time++;
|
||||
|
@ -146,11 +153,11 @@ namespace MoonTools.Core.Graph
|
|||
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);
|
||||
}
|
||||
|
||||
public IEnumerable<T> TopologicalSort()
|
||||
public IEnumerable<TNode> TopologicalSort()
|
||||
{
|
||||
var dfs = NodeDFS();
|
||||
var priority = new SortedList<uint, T>();
|
||||
var priority = new SortedList<uint, TNode>();
|
||||
foreach (var entry in dfs)
|
||||
{
|
||||
priority.Add(entry.Value[SearchSymbol.finish], entry.Key);
|
||||
|
@ -173,22 +180,22 @@ namespace MoonTools.Core.Graph
|
|||
return priority.Values.Reverse();
|
||||
}
|
||||
|
||||
public IEnumerable<IEnumerable<T>> StronglyConnectedComponents()
|
||||
public IEnumerable<IEnumerable<TNode>> StronglyConnectedComponents()
|
||||
{
|
||||
var preorder = new Dictionary<T, uint>();
|
||||
var lowlink = new Dictionary<T, uint>();
|
||||
var sccFound = new Dictionary<T, bool>();
|
||||
var sccQueue = new Stack<T>();
|
||||
var preorder = new Dictionary<TNode, uint>();
|
||||
var lowlink = new Dictionary<TNode, uint>();
|
||||
var sccFound = new Dictionary<TNode, bool>();
|
||||
var sccQueue = new Stack<TNode>();
|
||||
|
||||
var result = new List<List<T>>();
|
||||
var result = new List<List<TNode>>();
|
||||
|
||||
uint preorderCounter = 0;
|
||||
|
||||
foreach (var source in Vertices)
|
||||
foreach (var source in Nodes)
|
||||
{
|
||||
if (!sccFound.ContainsKey(source))
|
||||
{
|
||||
var queue = new Stack<T>();
|
||||
var queue = new Stack<TNode>();
|
||||
queue.Push(source);
|
||||
|
||||
while (queue.Count > 0)
|
||||
|
@ -233,7 +240,7 @@ namespace MoonTools.Core.Graph
|
|||
if (lowlink[v] == preorder[v])
|
||||
{
|
||||
sccFound[v] = true;
|
||||
var scc = new List<T>
|
||||
var scc = new List<TNode>
|
||||
{
|
||||
v
|
||||
};
|
||||
|
@ -257,11 +264,11 @@ namespace MoonTools.Core.Graph
|
|||
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);
|
||||
|
||||
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 sccs = new Stack<IEnumerable<T>>();
|
||||
var sccs = new Stack<IEnumerable<TNode>>();
|
||||
foreach (var scc in StronglyConnectedComponents())
|
||||
{
|
||||
sccs.Push(scc);
|
||||
|
@ -296,18 +303,18 @@ namespace MoonTools.Core.Graph
|
|||
|
||||
while (sccs.Count > 0)
|
||||
{
|
||||
var scc = new Stack<T>(sccs.Pop());
|
||||
var scc = new Stack<TNode>(sccs.Pop());
|
||||
var startNode = scc.Pop();
|
||||
var path = new Stack<T>();
|
||||
var path = new Stack<TNode>();
|
||||
path.Push(startNode);
|
||||
var blocked = new HashSet<T>
|
||||
var blocked = new HashSet<TNode>
|
||||
{
|
||||
startNode
|
||||
};
|
||||
var closed = new HashSet<T>();
|
||||
var B = new Dictionary<T, HashSet<T>>();
|
||||
var stack = new Stack<Tuple<T, Stack<T>>>();
|
||||
stack.Push(Tuple.Create(startNode, new Stack<T>(subGraph.Neighbors(startNode))));
|
||||
var closed = new HashSet<TNode>();
|
||||
var B = new Dictionary<TNode, HashSet<TNode>>();
|
||||
var stack = new Stack<Tuple<TNode, Stack<TNode>>>();
|
||||
stack.Push(Tuple.Create(startNode, new Stack<TNode>(subGraph.Neighbors(startNode))));
|
||||
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
|
@ -321,7 +328,7 @@ namespace MoonTools.Core.Graph
|
|||
|
||||
if (nextNode.Equals(startNode))
|
||||
{
|
||||
var resultPath = new List<T>();
|
||||
var resultPath = new List<TNode>();
|
||||
foreach (var v in path)
|
||||
{
|
||||
resultPath.Add(v);
|
||||
|
@ -335,7 +342,7 @@ namespace MoonTools.Core.Graph
|
|||
else if (!blocked.Contains(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);
|
||||
blocked.Add(nextNode);
|
||||
continue;
|
||||
|
@ -354,7 +361,7 @@ namespace MoonTools.Core.Graph
|
|||
{
|
||||
if (!B.ContainsKey(neighbor))
|
||||
{
|
||||
B[neighbor] = new HashSet<T>();
|
||||
B[neighbor] = new HashSet<TNode>();
|
||||
}
|
||||
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 HSccs = H.StronglyConnectedComponents();
|
||||
foreach (var HScc in HSccs)
|
||||
|
@ -377,37 +384,37 @@ namespace MoonTools.Core.Graph
|
|||
return result.Distinct(new SimpleCycleComparer());
|
||||
}
|
||||
|
||||
public DirectedGraph<T> Clone()
|
||||
public DirectedGraph<TNode, TEdgeData> Clone()
|
||||
{
|
||||
var clone = new DirectedGraph<T>();
|
||||
clone.AddVertices(Vertices.ToArray());
|
||||
var clone = new DirectedGraph<TNode, TEdgeData>();
|
||||
clone.AddNodes(Nodes.ToArray());
|
||||
|
||||
foreach (var v in Vertices)
|
||||
foreach (var v in Nodes)
|
||||
{
|
||||
foreach (var n in Neighbors(v))
|
||||
{
|
||||
clone.AddEdge(v, n);
|
||||
clone.AddEdge(v, n, EdgeData((v, n)));
|
||||
}
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
public DirectedGraph<T> SubGraph(params T[] subVertices)
|
||||
public DirectedGraph<TNode, TEdgeData> SubGraph(params TNode[] subVertices)
|
||||
{
|
||||
var subGraph = new DirectedGraph<T>();
|
||||
subGraph.AddVertices(subVertices.ToArray());
|
||||
var subGraph = new DirectedGraph<TNode, TEdgeData>();
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
nodes.Clear();
|
||||
neighbors.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)) { }
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -8,34 +8,38 @@ using MoonTools.Core.Graph;
|
|||
|
||||
namespace Tests
|
||||
{
|
||||
struct EdgeData { }
|
||||
|
||||
public class DirectedGraphTest
|
||||
{
|
||||
[Test]
|
||||
public void AddVertex()
|
||||
{
|
||||
var myGraph = new DirectedGraph<int>();
|
||||
myGraph.AddVertex(4);
|
||||
EdgeData dummyEdgeData;
|
||||
|
||||
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]
|
||||
public void AddVertices()
|
||||
public void AddNodes()
|
||||
{
|
||||
var myGraph = new DirectedGraph<int>();
|
||||
myGraph.AddVertices(4, 20, 69);
|
||||
var myGraph = new DirectedGraph<int, EdgeData>();
|
||||
myGraph.AddNodes(4, 20, 69);
|
||||
|
||||
Assert.IsTrue(myGraph.VertexExists(4));
|
||||
Assert.IsTrue(myGraph.VertexExists(20));
|
||||
Assert.IsTrue(myGraph.VertexExists(69));
|
||||
Assert.IsTrue(myGraph.Exists(4));
|
||||
Assert.IsTrue(myGraph.Exists(20));
|
||||
Assert.IsTrue(myGraph.Exists(69));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddEdge()
|
||||
{
|
||||
var myGraph = new DirectedGraph<int>();
|
||||
myGraph.AddVertices(5, 6);
|
||||
myGraph.AddEdge(5, 6);
|
||||
var myGraph = new DirectedGraph<int, EdgeData>();
|
||||
myGraph.AddNodes(5, 6);
|
||||
myGraph.AddEdge(5, 6, dummyEdgeData);
|
||||
|
||||
Assert.That(myGraph.Neighbors(5), Does.Contain(6));
|
||||
}
|
||||
|
@ -43,13 +47,13 @@ namespace Tests
|
|||
[Test]
|
||||
public void AddEdges()
|
||||
{
|
||||
var myGraph = new DirectedGraph<int>();
|
||||
myGraph.AddVertices(1, 2, 3, 4);
|
||||
var myGraph = new DirectedGraph<int, EdgeData>();
|
||||
myGraph.AddNodes(1, 2, 3, 4);
|
||||
myGraph.AddEdges(
|
||||
Tuple.Create(1, 2),
|
||||
Tuple.Create(2, 3),
|
||||
Tuple.Create(2, 4),
|
||||
Tuple.Create(3, 4)
|
||||
(1, 2, dummyEdgeData),
|
||||
(2, 3, dummyEdgeData),
|
||||
(2, 4, dummyEdgeData),
|
||||
(3, 4, dummyEdgeData)
|
||||
);
|
||||
|
||||
Assert.That(myGraph.Neighbors(1), Does.Contain(2));
|
||||
|
@ -62,13 +66,13 @@ namespace Tests
|
|||
[Test]
|
||||
public void RemoveEdge()
|
||||
{
|
||||
var myGraph = new DirectedGraph<int>();
|
||||
myGraph.AddVertices(1, 2, 3, 4);
|
||||
var myGraph = new DirectedGraph<int, EdgeData>();
|
||||
myGraph.AddNodes(1, 2, 3, 4);
|
||||
myGraph.AddEdges(
|
||||
Tuple.Create(1, 2),
|
||||
Tuple.Create(2, 3),
|
||||
Tuple.Create(2, 4),
|
||||
Tuple.Create(3, 4)
|
||||
(1, 2, dummyEdgeData),
|
||||
(2, 3, dummyEdgeData),
|
||||
(2, 4, dummyEdgeData),
|
||||
(3, 4, dummyEdgeData)
|
||||
);
|
||||
|
||||
myGraph.RemoveEdge(2, 3);
|
||||
|
@ -78,20 +82,20 @@ namespace Tests
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveVertex()
|
||||
public void RemoveNode()
|
||||
{
|
||||
var myGraph = new DirectedGraph<int>();
|
||||
myGraph.AddVertices(1, 2, 3, 4);
|
||||
var myGraph = new DirectedGraph<int, EdgeData>();
|
||||
myGraph.AddNodes(1, 2, 3, 4);
|
||||
myGraph.AddEdges(
|
||||
Tuple.Create(1, 2),
|
||||
Tuple.Create(2, 3),
|
||||
Tuple.Create(2, 4),
|
||||
Tuple.Create(3, 4)
|
||||
(1, 2, dummyEdgeData),
|
||||
(2, 3, dummyEdgeData),
|
||||
(2, 4, dummyEdgeData),
|
||||
(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(3).Should().Contain(4);
|
||||
}
|
||||
|
@ -99,12 +103,12 @@ namespace Tests
|
|||
[Test]
|
||||
public void NodeDFS()
|
||||
{
|
||||
var myGraph = new DirectedGraph<char>();
|
||||
myGraph.AddVertices('a', 'b', 'c', 'd');
|
||||
var myGraph = new DirectedGraph<char, EdgeData>();
|
||||
myGraph.AddNodes('a', 'b', 'c', 'd');
|
||||
myGraph.AddEdges(
|
||||
Tuple.Create('a', 'b'),
|
||||
Tuple.Create('a', 'c'),
|
||||
Tuple.Create('b', 'd')
|
||||
('a', 'b', dummyEdgeData),
|
||||
('a', 'c', dummyEdgeData),
|
||||
('b', 'd', dummyEdgeData)
|
||||
);
|
||||
|
||||
var result = myGraph.NodeDFS();
|
||||
|
@ -125,13 +129,13 @@ namespace Tests
|
|||
[Test]
|
||||
public void TopologicalSortSimple()
|
||||
{
|
||||
var simpleGraph = new DirectedGraph<char>();
|
||||
simpleGraph.AddVertices('a', 'b', 'c', 'd');
|
||||
var simpleGraph = new DirectedGraph<char, EdgeData>();
|
||||
simpleGraph.AddNodes('a', 'b', 'c', 'd');
|
||||
simpleGraph.AddEdges(
|
||||
Tuple.Create('a', 'b'),
|
||||
Tuple.Create('a', 'c'),
|
||||
Tuple.Create('b', 'a'),
|
||||
Tuple.Create('b', 'd')
|
||||
('a', 'b', dummyEdgeData),
|
||||
('a', 'c', dummyEdgeData),
|
||||
('b', 'a', dummyEdgeData),
|
||||
('b', 'd', dummyEdgeData)
|
||||
);
|
||||
|
||||
Assert.That(simpleGraph.TopologicalSort(), Is.EqualTo(new char[] { 'a', 'c', 'b', 'd' }));
|
||||
|
@ -140,17 +144,17 @@ namespace Tests
|
|||
[Test]
|
||||
public void TopologicalSortComplex()
|
||||
{
|
||||
var complexGraph = new DirectedGraph<char>();
|
||||
complexGraph.AddVertices('a', 'b', 'c', 'd', 'e', 'f', 'g', 't', 'm');
|
||||
var complexGraph = new DirectedGraph<char, EdgeData>();
|
||||
complexGraph.AddNodes('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')
|
||||
('a', 'b', dummyEdgeData),
|
||||
('a', 'c', dummyEdgeData),
|
||||
('a', 'd', dummyEdgeData),
|
||||
('b', 'f', dummyEdgeData),
|
||||
('b', 'g', dummyEdgeData),
|
||||
('c', 'g', dummyEdgeData),
|
||||
('e', 't', dummyEdgeData),
|
||||
('t', 'm', dummyEdgeData)
|
||||
);
|
||||
|
||||
Assert.That(
|
||||
|
@ -162,13 +166,13 @@ namespace Tests
|
|||
[Test]
|
||||
public void StronglyConnectedComponentsSimple()
|
||||
{
|
||||
var simpleGraph = new DirectedGraph<int>();
|
||||
simpleGraph.AddVertices(1, 2, 3);
|
||||
var simpleGraph = new DirectedGraph<int, EdgeData>();
|
||||
simpleGraph.AddNodes(1, 2, 3);
|
||||
simpleGraph.AddEdges(
|
||||
Tuple.Create(1, 2),
|
||||
Tuple.Create(2, 3),
|
||||
Tuple.Create(3, 2),
|
||||
Tuple.Create(2, 1)
|
||||
(1, 2, dummyEdgeData),
|
||||
(2, 3, dummyEdgeData),
|
||||
(3, 2, dummyEdgeData),
|
||||
(2, 1, dummyEdgeData)
|
||||
);
|
||||
|
||||
var result = simpleGraph.StronglyConnectedComponents();
|
||||
|
@ -181,15 +185,15 @@ namespace Tests
|
|||
[Test]
|
||||
public void StronglyConnectedComponentsMedium()
|
||||
{
|
||||
var mediumGraph = new DirectedGraph<int>();
|
||||
mediumGraph.AddVertices(1, 2, 3, 4);
|
||||
var mediumGraph = new DirectedGraph<int, EdgeData>();
|
||||
mediumGraph.AddNodes(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)
|
||||
(1, 2, dummyEdgeData),
|
||||
(1, 3, dummyEdgeData),
|
||||
(1, 4, dummyEdgeData),
|
||||
(4, 2, dummyEdgeData),
|
||||
(3, 4, dummyEdgeData),
|
||||
(2, 3, dummyEdgeData)
|
||||
);
|
||||
|
||||
var result = mediumGraph.StronglyConnectedComponents();
|
||||
|
@ -204,21 +208,21 @@ namespace Tests
|
|||
[Test]
|
||||
public void StronglyConnectedComponentsComplex()
|
||||
{
|
||||
var complexGraph = new DirectedGraph<int>();
|
||||
complexGraph.AddVertices(1, 2, 3, 4, 5, 6, 7, 8);
|
||||
var complexGraph = new DirectedGraph<int, EdgeData>();
|
||||
complexGraph.AddNodes(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)
|
||||
(1, 2, dummyEdgeData),
|
||||
(2, 3, dummyEdgeData),
|
||||
(2, 8, dummyEdgeData),
|
||||
(3, 4, dummyEdgeData),
|
||||
(3, 7, dummyEdgeData),
|
||||
(4, 5, dummyEdgeData),
|
||||
(5, 3, dummyEdgeData),
|
||||
(5, 6, dummyEdgeData),
|
||||
(7, 4, dummyEdgeData),
|
||||
(7, 6, dummyEdgeData),
|
||||
(8, 1, dummyEdgeData),
|
||||
(8, 7, dummyEdgeData)
|
||||
);
|
||||
|
||||
var result = complexGraph.StronglyConnectedComponents();
|
||||
|
@ -235,19 +239,19 @@ namespace Tests
|
|||
[Test]
|
||||
public void Clone()
|
||||
{
|
||||
var myGraph = new DirectedGraph<int>();
|
||||
myGraph.AddVertices(1, 2, 3, 4);
|
||||
var myGraph = new DirectedGraph<int, EdgeData>();
|
||||
myGraph.AddNodes(1, 2, 3, 4);
|
||||
myGraph.AddEdges(
|
||||
Tuple.Create(1, 1),
|
||||
Tuple.Create(1, 2),
|
||||
Tuple.Create(2, 3),
|
||||
Tuple.Create(2, 1),
|
||||
Tuple.Create(3, 4)
|
||||
(1, 1, dummyEdgeData),
|
||||
(1, 2, dummyEdgeData),
|
||||
(2, 3, dummyEdgeData),
|
||||
(2, 1, dummyEdgeData),
|
||||
(3, 4, dummyEdgeData)
|
||||
);
|
||||
|
||||
var clone = myGraph.Clone();
|
||||
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(2).Should().BeEquivalentTo(3, 1);
|
||||
clone.Neighbors(3).Should().BeEquivalentTo(4);
|
||||
|
@ -256,18 +260,18 @@ namespace Tests
|
|||
[Test]
|
||||
public void SubGraph()
|
||||
{
|
||||
var myGraph = new DirectedGraph<int>();
|
||||
myGraph.AddVertices(1, 2, 3, 4);
|
||||
var myGraph = new DirectedGraph<int, EdgeData>();
|
||||
myGraph.AddNodes(1, 2, 3, 4);
|
||||
myGraph.AddEdges(
|
||||
Tuple.Create(1, 1),
|
||||
Tuple.Create(1, 2),
|
||||
Tuple.Create(2, 3),
|
||||
Tuple.Create(2, 1),
|
||||
Tuple.Create(3, 4)
|
||||
(1, 1, dummyEdgeData),
|
||||
(1, 2, dummyEdgeData),
|
||||
(2, 3, dummyEdgeData),
|
||||
(2, 1, dummyEdgeData),
|
||||
(3, 4, dummyEdgeData)
|
||||
);
|
||||
|
||||
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(2).Should().BeEquivalentTo(1, 3);
|
||||
subGraph.Neighbors(3).Should().NotContain(4);
|
||||
|
@ -276,16 +280,16 @@ namespace Tests
|
|||
[Test]
|
||||
public void SimpleCyclesSimple()
|
||||
{
|
||||
var myGraph = new DirectedGraph<int>();
|
||||
myGraph.AddVertices(0, 1, 2);
|
||||
var myGraph = new DirectedGraph<int, EdgeData>();
|
||||
myGraph.AddNodes(0, 1, 2);
|
||||
myGraph.AddEdges(
|
||||
Tuple.Create(0, 0),
|
||||
Tuple.Create(0, 1),
|
||||
Tuple.Create(0, 2),
|
||||
Tuple.Create(1, 2),
|
||||
Tuple.Create(2, 0),
|
||||
Tuple.Create(2, 1),
|
||||
Tuple.Create(2, 2)
|
||||
(0, 0, dummyEdgeData),
|
||||
(0, 1, dummyEdgeData),
|
||||
(0, 2, dummyEdgeData),
|
||||
(1, 2, dummyEdgeData),
|
||||
(2, 0, dummyEdgeData),
|
||||
(2, 1, dummyEdgeData),
|
||||
(2, 2, dummyEdgeData)
|
||||
);
|
||||
|
||||
var result = myGraph.SimpleCycles();
|
||||
|
@ -307,23 +311,22 @@ namespace Tests
|
|||
[Test]
|
||||
public void SimpleCyclesComplex()
|
||||
{
|
||||
var myGraph = new DirectedGraph<int>();
|
||||
myGraph.AddVertices(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
|
||||
var myGraph = new DirectedGraph<int, EdgeData>();
|
||||
myGraph.AddNodes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
|
||||
myGraph.AddEdges(
|
||||
Tuple.Create(0, 1),
|
||||
Tuple.Create(1, 2),
|
||||
Tuple.Create(2, 3),
|
||||
Tuple.Create(3, 0),
|
||||
Tuple.Create(0, 3),
|
||||
Tuple.Create(3, 4),
|
||||
Tuple.Create(4, 5),
|
||||
Tuple.Create(5, 0),
|
||||
Tuple.Create(0, 1),
|
||||
Tuple.Create(1, 6),
|
||||
Tuple.Create(6, 7),
|
||||
Tuple.Create(7, 8),
|
||||
Tuple.Create(8, 0),
|
||||
Tuple.Create(8, 9)
|
||||
(0, 1, dummyEdgeData),
|
||||
(1, 2, dummyEdgeData),
|
||||
(2, 3, dummyEdgeData),
|
||||
(3, 0, dummyEdgeData),
|
||||
(0, 3, dummyEdgeData),
|
||||
(3, 4, dummyEdgeData),
|
||||
(4, 5, dummyEdgeData),
|
||||
(5, 0, dummyEdgeData),
|
||||
(1, 6, dummyEdgeData),
|
||||
(6, 7, dummyEdgeData),
|
||||
(7, 8, dummyEdgeData),
|
||||
(8, 0, dummyEdgeData),
|
||||
(8, 9, dummyEdgeData)
|
||||
);
|
||||
|
||||
var result = myGraph.SimpleCycles();
|
||||
|
@ -344,13 +347,13 @@ namespace Tests
|
|||
[Test]
|
||||
public void Cyclic()
|
||||
{
|
||||
var myGraph = new DirectedGraph<int>();
|
||||
myGraph.AddVertices(1, 2, 3, 4);
|
||||
var myGraph = new DirectedGraph<int, EdgeData>();
|
||||
myGraph.AddNodes(1, 2, 3, 4);
|
||||
myGraph.AddEdges(
|
||||
Tuple.Create(1, 2),
|
||||
Tuple.Create(2, 3),
|
||||
Tuple.Create(3, 1),
|
||||
Tuple.Create(3, 4)
|
||||
(1, 2, dummyEdgeData),
|
||||
(2, 3, dummyEdgeData),
|
||||
(3, 1, dummyEdgeData),
|
||||
(3, 4, dummyEdgeData)
|
||||
);
|
||||
|
||||
Assert.That(myGraph.Cyclic(), Is.True);
|
||||
|
@ -359,15 +362,56 @@ namespace Tests
|
|||
[Test]
|
||||
public void Acyclic()
|
||||
{
|
||||
var myGraph = new DirectedGraph<int>();
|
||||
myGraph.AddVertices(1, 2, 3, 4);
|
||||
var myGraph = new DirectedGraph<int, EdgeData>();
|
||||
myGraph.AddNodes(1, 2, 3, 4);
|
||||
myGraph.AddEdges(
|
||||
Tuple.Create(1, 2),
|
||||
Tuple.Create(2, 3),
|
||||
Tuple.Create(3, 4)
|
||||
(1, 2, dummyEdgeData),
|
||||
(2, 3, dummyEdgeData),
|
||||
(3, 4, dummyEdgeData)
|
||||
);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue