more SSSP algos for directed weighted
							parent
							
								
									5b1c05819e
								
							
						
					
					
						commit
						93e129ae7c
					
				| 
						 | 
					@ -113,8 +113,38 @@ namespace MoonTools.Core.Graph
 | 
				
			||||||
            yield break;
 | 
					            yield break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private IEnumerable<(TNode, TNode)> ShortestPath(TNode start, TNode end, Func<TNode, IEnumerable<(TNode, TNode, int)>> SSSPAlgorithm)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            CheckNodes(start, end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var cameFrom = new PooledDictionary<TNode, TNode>(ClearMode.Always);
 | 
				
			||||||
 | 
					            var reachable = new PooledSet<TNode>(ClearMode.Always);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var (node, previous, weight) in SSSPAlgorithm(start))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                cameFrom[node] = previous;
 | 
				
			||||||
 | 
					                reachable.Add(node);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!reachable.Contains(end))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                cameFrom.Dispose();
 | 
				
			||||||
 | 
					                reachable.Dispose();
 | 
				
			||||||
 | 
					                yield break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var edge in ReconstructPath(cameFrom, end).Reverse())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                yield return edge;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            cameFrom.Dispose();
 | 
				
			||||||
 | 
					            reachable.Dispose();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IEnumerable<(TNode, TNode, int)> DijkstraSingleSourceShortestPath(TNode source)
 | 
					        public IEnumerable<(TNode, TNode, int)> DijkstraSingleSourceShortestPath(TNode source)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            if (weights.Values.Any(w => w < 0)) { throw new NegativeWeightException("Dijkstra cannot be used on a graph with negative edge weights. Try Bellman-Ford"); }
 | 
				
			||||||
            CheckNodes(source);
 | 
					            CheckNodes(source);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var distance = new PooledDictionary<TNode, int>(ClearMode.Always);
 | 
					            var distance = new PooledDictionary<TNode, int>(ClearMode.Always);
 | 
				
			||||||
| 
						 | 
					@ -148,7 +178,7 @@ namespace MoonTools.Core.Graph
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            foreach (var node in Nodes)
 | 
					            foreach (var node in Nodes)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (!node.Equals(source))
 | 
					                if (previous.ContainsKey(node) && distance.ContainsKey(node))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    yield return (node, previous[node], distance[node]);
 | 
					                    yield return (node, previous[node], distance[node]);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					@ -157,5 +187,62 @@ namespace MoonTools.Core.Graph
 | 
				
			||||||
            distance.Dispose();
 | 
					            distance.Dispose();
 | 
				
			||||||
            previous.Dispose();
 | 
					            previous.Dispose();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IEnumerable<(TNode, TNode)> DijkstraShortestPath(TNode start, TNode end)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return ShortestPath(start, end, DijkstraSingleSourceShortestPath);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IEnumerable<(TNode, TNode, int)> BellmanFordSingleSourceShortestPath(TNode source)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            CheckNodes(source);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var distance = new PooledDictionary<TNode, int>(ClearMode.Always);
 | 
				
			||||||
 | 
					            var previous = new PooledDictionary<TNode, TNode>(ClearMode.Always);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var node in Nodes)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                distance[node] = int.MaxValue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            distance[source] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (int i = 0; i < Order; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                foreach (var (v, u) in Edges)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var weight = Weight(v, u);
 | 
				
			||||||
 | 
					                    if (distance[v] + weight < distance[u])
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        distance[u] = distance[v] + weight;
 | 
				
			||||||
 | 
					                        previous[u] = v;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var (v, u) in Edges)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (distance[v] + Weight(v, u) < distance[u])
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    throw new NegativeCycleException();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var node in Nodes)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (previous.ContainsKey(node) && distance.ContainsKey(node))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    yield return (node, previous[node], distance[node]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            distance.Dispose();
 | 
				
			||||||
 | 
					            previous.Dispose();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IEnumerable<(TNode, TNode)> BellmanFordShortestPath(TNode start, TNode end)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return ShortestPath(start, end, BellmanFordSingleSourceShortestPath);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,25 @@
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Runtime.Serialization;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace MoonTools.Core.Graph
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [Serializable]
 | 
				
			||||||
 | 
					    public class NegativeCycleException : Exception
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public NegativeCycleException()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public NegativeCycleException(string message) : base(message)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public NegativeCycleException(string message, Exception innerException) : base(message, innerException)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected NegativeCycleException(SerializationInfo info, StreamingContext context) : base(info, context)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,25 @@
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Runtime.Serialization;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace MoonTools.Core.Graph
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [Serializable]
 | 
				
			||||||
 | 
					    public class NegativeWeightException : Exception
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public NegativeWeightException()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public NegativeWeightException(string message) : base(message)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public NegativeWeightException(string message, Exception innerException) : base(message, innerException)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected NegativeWeightException(SerializationInfo info, StreamingContext context) : base(info, context)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -264,5 +264,273 @@ namespace Tests
 | 
				
			||||||
            // have to call Count() because otherwise the lazy evaluation wont trigger
 | 
					            // have to call Count() because otherwise the lazy evaluation wont trigger
 | 
				
			||||||
            myGraph.Invoking(x => x.DijkstraSingleSourceShortestPath('z').Count()).Should().Throw<System.ArgumentException>();
 | 
					            myGraph.Invoking(x => x.DijkstraSingleSourceShortestPath('z').Count()).Should().Throw<System.ArgumentException>();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void DijkstraShortestPath()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var run = new MoveTypeEdgeData { moveType = MoveType.Run };
 | 
				
			||||||
 | 
					            var jump = new MoveTypeEdgeData { moveType = MoveType.Jump };
 | 
				
			||||||
 | 
					            var wallJump = new MoveTypeEdgeData { moveType = MoveType.WallJump };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<char, MoveTypeEdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNodes('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h');
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                ('a', 'b', 2, run),
 | 
				
			||||||
 | 
					                ('a', 'c', 3, run),
 | 
				
			||||||
 | 
					                ('a', 'e', 4, wallJump),
 | 
				
			||||||
 | 
					                ('b', 'd', 2, jump),
 | 
				
			||||||
 | 
					                ('b', 'e', 1, run),
 | 
				
			||||||
 | 
					                ('c', 'g', 4, jump),
 | 
				
			||||||
 | 
					                ('c', 'h', 11, run),
 | 
				
			||||||
 | 
					                ('d', 'c', 3, jump),
 | 
				
			||||||
 | 
					                ('d', 'f', 2, run),
 | 
				
			||||||
 | 
					                ('d', 'h', 3, wallJump),
 | 
				
			||||||
 | 
					                ('e', 'f', 5, run),
 | 
				
			||||||
 | 
					                ('f', 'd', 2, run),
 | 
				
			||||||
 | 
					                ('f', 'h', 6, wallJump),
 | 
				
			||||||
 | 
					                ('g', 'h', 7, run),
 | 
				
			||||||
 | 
					                ('h', 'f', 1, jump)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph
 | 
				
			||||||
 | 
					                .DijkstraShortestPath('a', 'h')
 | 
				
			||||||
 | 
					                .Select(pair => myGraph.EdgeData(pair.Item1, pair.Item2))
 | 
				
			||||||
 | 
					                .Should()
 | 
				
			||||||
 | 
					                .ContainInOrder(
 | 
				
			||||||
 | 
					                    run, jump, wallJump
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                .And
 | 
				
			||||||
 | 
					                .HaveCount(3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // have to call Count() because otherwise the lazy evaluation wont trigger
 | 
				
			||||||
 | 
					            myGraph.Invoking(x => x.DijkstraShortestPath('a', 'z').Count()).Should().Throw<System.ArgumentException>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void DijkstraNotReachable()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var run = new MoveTypeEdgeData { moveType = MoveType.Run };
 | 
				
			||||||
 | 
					            var jump = new MoveTypeEdgeData { moveType = MoveType.Jump };
 | 
				
			||||||
 | 
					            var wallJump = new MoveTypeEdgeData { moveType = MoveType.WallJump };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<char, MoveTypeEdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNodes('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h');
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                ('a', 'b', 2, run),
 | 
				
			||||||
 | 
					                ('a', 'c', 3, run),
 | 
				
			||||||
 | 
					                ('a', 'e', 4, wallJump),
 | 
				
			||||||
 | 
					                ('b', 'd', 2, jump),
 | 
				
			||||||
 | 
					                ('b', 'e', 1, run),
 | 
				
			||||||
 | 
					                ('c', 'g', 4, jump),
 | 
				
			||||||
 | 
					                ('c', 'h', 11, run),
 | 
				
			||||||
 | 
					                ('d', 'c', 3, jump),
 | 
				
			||||||
 | 
					                ('d', 'h', 3, wallJump),
 | 
				
			||||||
 | 
					                ('f', 'd', 2, run),
 | 
				
			||||||
 | 
					                ('f', 'h', 6, wallJump),
 | 
				
			||||||
 | 
					                ('g', 'h', 7, run)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph
 | 
				
			||||||
 | 
					                .DijkstraShortestPath('a', 'f')
 | 
				
			||||||
 | 
					                .Should()
 | 
				
			||||||
 | 
					                .BeEmpty();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void DijkstraNegativeWeight()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var run = new MoveTypeEdgeData { moveType = MoveType.Run };
 | 
				
			||||||
 | 
					            var jump = new MoveTypeEdgeData { moveType = MoveType.Jump };
 | 
				
			||||||
 | 
					            var wallJump = new MoveTypeEdgeData { moveType = MoveType.WallJump };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<char, MoveTypeEdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNodes('a', 'b', 'c', 'd');
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                ('a', 'b', -2, run),
 | 
				
			||||||
 | 
					                ('a', 'c', 3, run),
 | 
				
			||||||
 | 
					                ('b', 'd', 2, jump),
 | 
				
			||||||
 | 
					                ('d', 'c', -3, jump)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph
 | 
				
			||||||
 | 
					                .Invoking(x => x.DijkstraShortestPath('a', 'd').Count())
 | 
				
			||||||
 | 
					                .Should()
 | 
				
			||||||
 | 
					                .Throw<NegativeWeightException>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void BellmanFordSingleSourceShortestPath()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var run = new MoveTypeEdgeData { moveType = MoveType.Run };
 | 
				
			||||||
 | 
					            var jump = new MoveTypeEdgeData { moveType = MoveType.Jump };
 | 
				
			||||||
 | 
					            var wallJump = new MoveTypeEdgeData { moveType = MoveType.WallJump };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<char, MoveTypeEdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNodes('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h');
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                ('a', 'b', 2, run),
 | 
				
			||||||
 | 
					                ('a', 'c', 3, run),
 | 
				
			||||||
 | 
					                ('a', 'e', 4, wallJump),
 | 
				
			||||||
 | 
					                ('b', 'd', 2, jump),
 | 
				
			||||||
 | 
					                ('b', 'e', 1, run),
 | 
				
			||||||
 | 
					                ('c', 'g', 4, jump),
 | 
				
			||||||
 | 
					                ('c', 'h', 11, run),
 | 
				
			||||||
 | 
					                ('d', 'c', 3, jump),
 | 
				
			||||||
 | 
					                ('d', 'f', 2, run),
 | 
				
			||||||
 | 
					                ('d', 'h', 3, wallJump),
 | 
				
			||||||
 | 
					                ('e', 'f', 5, run),
 | 
				
			||||||
 | 
					                ('f', 'd', 2, run),
 | 
				
			||||||
 | 
					                ('f', 'h', 6, wallJump),
 | 
				
			||||||
 | 
					                ('g', 'h', 7, run),
 | 
				
			||||||
 | 
					                ('h', 'f', 1, jump)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph
 | 
				
			||||||
 | 
					                .BellmanFordSingleSourceShortestPath('a')
 | 
				
			||||||
 | 
					                .Should()
 | 
				
			||||||
 | 
					                .Contain(('b', 'a', 2)).And
 | 
				
			||||||
 | 
					                .Contain(('c', 'a', 3)).And
 | 
				
			||||||
 | 
					                .Contain(('d', 'b', 4)).And
 | 
				
			||||||
 | 
					                .Contain(('e', 'b', 3)).And
 | 
				
			||||||
 | 
					                .Contain(('f', 'd', 6)).And
 | 
				
			||||||
 | 
					                .Contain(('g', 'c', 7)).And
 | 
				
			||||||
 | 
					                .Contain(('h', 'd', 7)).And
 | 
				
			||||||
 | 
					                .HaveCount(7);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // have to call Count() because otherwise the lazy evaluation wont trigger
 | 
				
			||||||
 | 
					            myGraph.Invoking(x => x.BellmanFordSingleSourceShortestPath('z').Count()).Should().Throw<System.ArgumentException>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void BellmanFordSingleSourceShortestPathWithNegative()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var run = new MoveTypeEdgeData { moveType = MoveType.Run };
 | 
				
			||||||
 | 
					            var jump = new MoveTypeEdgeData { moveType = MoveType.Jump };
 | 
				
			||||||
 | 
					            var wallJump = new MoveTypeEdgeData { moveType = MoveType.WallJump };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<char, MoveTypeEdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNodes('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h');
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                ('a', 'b', 2, run),
 | 
				
			||||||
 | 
					                ('a', 'c', 3, run),
 | 
				
			||||||
 | 
					                ('a', 'e', 4, wallJump),
 | 
				
			||||||
 | 
					                ('b', 'd', -1, jump),
 | 
				
			||||||
 | 
					                ('b', 'e', 1, run),
 | 
				
			||||||
 | 
					                ('c', 'g', 4, jump),
 | 
				
			||||||
 | 
					                ('c', 'h', 11, run),
 | 
				
			||||||
 | 
					                ('d', 'c', 3, jump),
 | 
				
			||||||
 | 
					                ('d', 'f', 2, run),
 | 
				
			||||||
 | 
					                ('d', 'h', 3, wallJump),
 | 
				
			||||||
 | 
					                ('e', 'f', 5, run),
 | 
				
			||||||
 | 
					                ('f', 'd', 2, run),
 | 
				
			||||||
 | 
					                ('f', 'h', 6, wallJump),
 | 
				
			||||||
 | 
					                ('g', 'h', 7, run),
 | 
				
			||||||
 | 
					                ('h', 'f', 1, jump)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph
 | 
				
			||||||
 | 
					                .BellmanFordSingleSourceShortestPath('a')
 | 
				
			||||||
 | 
					                .Should()
 | 
				
			||||||
 | 
					                .Contain(('b', 'a', 2)).And
 | 
				
			||||||
 | 
					                .Contain(('c', 'a', 3)).And
 | 
				
			||||||
 | 
					                .Contain(('d', 'b', 1)).And
 | 
				
			||||||
 | 
					                .Contain(('e', 'b', 3)).And
 | 
				
			||||||
 | 
					                .Contain(('f', 'd', 3)).And
 | 
				
			||||||
 | 
					                .Contain(('g', 'c', 7)).And
 | 
				
			||||||
 | 
					                .Contain(('h', 'd', 4)).And
 | 
				
			||||||
 | 
					                .HaveCount(7);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void BellmanFordSingleSourceShortestPathNegativeCycle()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var run = new MoveTypeEdgeData { moveType = MoveType.Run };
 | 
				
			||||||
 | 
					            var jump = new MoveTypeEdgeData { moveType = MoveType.Jump };
 | 
				
			||||||
 | 
					            var wallJump = new MoveTypeEdgeData { moveType = MoveType.WallJump };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<char, MoveTypeEdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNodes('a', 'b', 'c');
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                ('a', 'b', -2, run),
 | 
				
			||||||
 | 
					                ('b', 'c', -3, run),
 | 
				
			||||||
 | 
					                ('c', 'a', -1, jump)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph
 | 
				
			||||||
 | 
					                .Invoking(x => x.BellmanFordSingleSourceShortestPath('a').Count())
 | 
				
			||||||
 | 
					                .Should().
 | 
				
			||||||
 | 
					                Throw<NegativeCycleException>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void BellmanFordShortestPath()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var run = new MoveTypeEdgeData { moveType = MoveType.Run };
 | 
				
			||||||
 | 
					            var jump = new MoveTypeEdgeData { moveType = MoveType.Jump };
 | 
				
			||||||
 | 
					            var wallJump = new MoveTypeEdgeData { moveType = MoveType.WallJump };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<char, MoveTypeEdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNodes('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h');
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                ('a', 'b', 2, run),
 | 
				
			||||||
 | 
					                ('a', 'c', 3, run),
 | 
				
			||||||
 | 
					                ('a', 'e', 4, wallJump),
 | 
				
			||||||
 | 
					                ('b', 'd', 2, jump),
 | 
				
			||||||
 | 
					                ('b', 'e', 1, run),
 | 
				
			||||||
 | 
					                ('c', 'g', 4, jump),
 | 
				
			||||||
 | 
					                ('c', 'h', 11, run),
 | 
				
			||||||
 | 
					                ('d', 'c', 3, jump),
 | 
				
			||||||
 | 
					                ('d', 'f', 2, run),
 | 
				
			||||||
 | 
					                ('d', 'h', 3, wallJump),
 | 
				
			||||||
 | 
					                ('e', 'f', 5, run),
 | 
				
			||||||
 | 
					                ('f', 'd', 2, run),
 | 
				
			||||||
 | 
					                ('f', 'h', 6, wallJump),
 | 
				
			||||||
 | 
					                ('g', 'h', 7, run),
 | 
				
			||||||
 | 
					                ('h', 'f', 1, jump)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph
 | 
				
			||||||
 | 
					                .BellmanFordShortestPath('a', 'h')
 | 
				
			||||||
 | 
					                .Select(pair => myGraph.EdgeData(pair.Item1, pair.Item2))
 | 
				
			||||||
 | 
					                .Should()
 | 
				
			||||||
 | 
					                .ContainInOrder(
 | 
				
			||||||
 | 
					                    run, jump, wallJump
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                .And
 | 
				
			||||||
 | 
					                .HaveCount(3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // have to call Count() because otherwise the lazy evaluation wont trigger
 | 
				
			||||||
 | 
					            myGraph.Invoking(x => x.BellmanFordShortestPath('a', 'z').Count()).Should().Throw<System.ArgumentException>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void BellmanFordNotReachable()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var run = new MoveTypeEdgeData { moveType = MoveType.Run };
 | 
				
			||||||
 | 
					            var jump = new MoveTypeEdgeData { moveType = MoveType.Jump };
 | 
				
			||||||
 | 
					            var wallJump = new MoveTypeEdgeData { moveType = MoveType.WallJump };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var myGraph = new DirectedWeightedGraph<char, MoveTypeEdgeData>();
 | 
				
			||||||
 | 
					            myGraph.AddNodes('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h');
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                ('a', 'b', 2, run),
 | 
				
			||||||
 | 
					                ('a', 'c', 3, run),
 | 
				
			||||||
 | 
					                ('a', 'e', 4, wallJump),
 | 
				
			||||||
 | 
					                ('b', 'd', 2, jump),
 | 
				
			||||||
 | 
					                ('b', 'e', 1, run),
 | 
				
			||||||
 | 
					                ('c', 'g', 4, jump),
 | 
				
			||||||
 | 
					                ('c', 'h', 11, run),
 | 
				
			||||||
 | 
					                ('d', 'c', 3, jump),
 | 
				
			||||||
 | 
					                ('d', 'h', 3, wallJump),
 | 
				
			||||||
 | 
					                ('f', 'd', 2, run),
 | 
				
			||||||
 | 
					                ('f', 'h', 6, wallJump),
 | 
				
			||||||
 | 
					                ('g', 'h', 7, run)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph
 | 
				
			||||||
 | 
					                .BellmanFordShortestPath('a', 'f')
 | 
				
			||||||
 | 
					                .Should()
 | 
				
			||||||
 | 
					                .BeEmpty();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue