public void Min_FibonacciHeap_Test() { int nodeCount = 1000 * 10; var minHeap = new FibonacciHeap <int>(); for (int i = 0; i <= nodeCount; i++) { minHeap.Insert(i); } for (int i = 0; i <= nodeCount; i++) { minHeap.UpdateKey(i, i - 1); } int min = 0; for (int i = 0; i <= nodeCount; i++) { min = minHeap.Extract(); Assert.AreEqual(min, i - 1); } //IEnumerable tests. Assert.AreEqual(minHeap.Count, minHeap.Count()); var rnd = new Random(); var testSeries = Enumerable.Range(0, nodeCount - 1).OrderBy(x => rnd.Next()).ToList(); foreach (var item in testSeries) { minHeap.Insert(item); } for (int i = 0; i < testSeries.Count; i++) { var decremented = testSeries[i] - rnd.Next(0, 1000); minHeap.UpdateKey(testSeries[i], decremented); testSeries[i] = decremented; } testSeries.Sort(); for (int i = 0; i < nodeCount - 2; i++) { min = minHeap.Extract(); Assert.AreEqual(testSeries[i], min); } //IEnumerable tests. Assert.AreEqual(minHeap.Count, minHeap.Count()); }
public void Max_FibonacciHeap_Test() { int nodeCount = 1000 * 10; var maxHeap = new FibonacciHeap <int>(SortDirection.Descending); for (int i = 0; i <= nodeCount; i++) { maxHeap.Insert(i); } for (int i = 0; i <= nodeCount; i++) { maxHeap.UpdateKey(i, i + 1); } int max = 0; for (int i = nodeCount; i >= 0; i--) { max = maxHeap.Extract(); Assert.AreEqual(max, i + 1); } //IEnumerable tests. Assert.AreEqual(maxHeap.Count, maxHeap.Count()); var rnd = new Random(); var testSeries = Enumerable.Range(0, nodeCount - 1).OrderBy(x => rnd.Next()).ToList(); foreach (var item in testSeries) { maxHeap.Insert(item); } for (int i = 0; i < testSeries.Count; i++) { var incremented = testSeries[i] + rnd.Next(0, 1000); maxHeap.UpdateKey(testSeries[i], incremented); testSeries[i] = incremented; } testSeries = testSeries.OrderByDescending(x => x).ToList(); for (int i = 0; i < nodeCount - 2; i++) { max = maxHeap.Extract(); Assert.AreEqual(testSeries[i], max); } //IEnumerable tests. Assert.AreEqual(maxHeap.Count, maxHeap.Count()); }
private void CheckHeap(FibonacciHeap <int> heap) { FibonacciNode <int> prePeak = null; while (!heap.IsEmpty) { var peak = heap.Extract(); Console.WriteLine(); Console.WriteLine($"Extract {peak}"); heap.Traverse(heap.Peak, (node) => { Console.Write($"{node} "); } ); if (prePeak == null) { prePeak = peak; } else { Assert.IsTrue(prePeak.Key < peak.Key); prePeak = peak; } } }
/// <summary> /// Get shortest distance to target. /// </summary> public ShortestPathResult <T, W> FindShortestPath(IGraph <T> graph, T source, T destination) { //regular argument checks if (graph?.GetVertex(source) == null || graph.GetVertex(destination) == null) { throw new ArgumentException(); } if (this.@operator == null) { throw new ArgumentException("Provide an operator implementation for generic type W during initialization."); } if (!graph.IsWeightedGraph) { if ([email protected]() != typeof(int)) { throw new ArgumentException("Edges of unweighted graphs are assigned an imaginary weight of one (1)." + "Provide an appropriate IShortestPathOperators<int> operator implementation during initialization."); } } //track progress for distance to each Vertex from source var progress = new Dictionary <T, W>(); //trace our current path by mapping current vertex to its Parent var parentMap = new Dictionary <T, T>(); //min heap to pick next closest vertex var minHeap = new FibonacciHeap <MinHeapWrap <T, W> >(); //keep references of heap Node for decrement key operation var heapMapping = new Dictionary <T, MinHeapWrap <T, W> >(); //add vertices to min heap and progress map foreach (var vertex in graph.VerticesAsEnumberable) { //init parent parentMap.Add(vertex.Key, default(T)); //init to max value progress.Add(vertex.Key, @operator.MaxValue); if (vertex.Key.Equals(source)) { continue; } } //start from source vertex as current var current = new MinHeapWrap <T, W>() { Distance = @operator.DefaultValue, Vertex = source }; minHeap.Insert(current); heapMapping.Add(current.Vertex, current); //until heap is empty while (minHeap.Count > 0) { //next min vertex to visit current = minHeap.Extract(); heapMapping.Remove(current.Vertex); //no path exists, so return max value if (current.Distance.Equals(@operator.MaxValue)) { return(new ShortestPathResult <T, W>(null, @operator.MaxValue)); } //visit neighbours of current foreach (var neighbour in graph.GetVertex(current.Vertex).Edges.Where(x => !x.TargetVertexKey.Equals(source))) { //new distance to neighbour var newDistance = @operator.Sum(current.Distance, graph.GetVertex(current.Vertex).GetEdge(neighbour.TargetVertex).Weight <W>()); //current distance to neighbour var existingDistance = progress[neighbour.TargetVertexKey]; //update distance if new is better if (newDistance.CompareTo(existingDistance) < 0) { progress[neighbour.TargetVertexKey] = newDistance; if (!heapMapping.ContainsKey(neighbour.TargetVertexKey)) { var wrap = new MinHeapWrap <T, W>() { Distance = newDistance, Vertex = neighbour.TargetVertexKey }; minHeap.Insert(wrap); heapMapping.Add(neighbour.TargetVertexKey, wrap); } else { //decrement distance to neighbour in heap var decremented = new MinHeapWrap <T, W>() { Distance = newDistance, Vertex = neighbour.TargetVertexKey }; minHeap.UpdateKey(heapMapping[neighbour.TargetVertexKey], decremented); heapMapping[neighbour.TargetVertexKey] = decremented; } //trace parent parentMap[neighbour.TargetVertexKey] = current.Vertex; } } } return(tracePath(graph, parentMap, source, destination)); }
/// <summary> /// Search path to target using the heuristic. /// </summary> public ShortestPathResult <T, W> FindShortestPath(WeightedDiGraph <T, W> graph, T source, T destination) { //regular argument checks if (graph?.FindVertex(source) == null || graph.FindVertex(destination) == null) { throw new ArgumentException(); } //track progress for distance to each Vertex from source var progress = new Dictionary <T, W>(); //trace our current path by mapping current vertex to its Parent var parentMap = new Dictionary <T, T>(); //min heap to pick next closest vertex var minHeap = new FibonacciHeap <AStarWrap <T, W> >(); //keep references of heap Node for decrement key operation var heapMapping = new Dictionary <T, AStarWrap <T, W> >(); //add vertices to min heap and progress map foreach (var vertex in graph.Vertices) { //init parent parentMap.Add(vertex.Key, default(T)); //init to max value progress.Add(vertex.Key, operators.MaxValue); if (vertex.Key.Equals(source)) { continue; } } //start from source vertex as current var current = new AStarWrap <T, W>(heuristic, destination) { Distance = operators.DefaultValue, Vertex = source }; //insert neighbour in heap minHeap.Insert(current); heapMapping[source] = current; //until heap is empty while (minHeap.Count > 0) { //next min vertex to visit current = minHeap.Extract(); heapMapping.Remove(current.Vertex); //no path exists, so return max value if (current.Distance.Equals(operators.MaxValue)) { return(new ShortestPathResult <T, W>(null, operators.MaxValue)); } //visit neighbours of current foreach (var neighbour in graph.Vertices[current.Vertex].OutEdges.Where(x => !x.Key.Value.Equals(source))) { //new distance to neighbour var newDistance = operators.Sum(current.Distance, graph.Vertices[current.Vertex].OutEdges[neighbour.Key]); //current distance to neighbour var existingDistance = progress[neighbour.Key.Value]; //update distance if new is better if (newDistance.CompareTo(existingDistance) < 0) { progress[neighbour.Key.Value] = newDistance; if (heapMapping.ContainsKey(neighbour.Key.Value)) { //decrement distance to neighbour in heap var decremented = new AStarWrap <T, W>(heuristic, destination) { Distance = newDistance, Vertex = neighbour.Key.Value }; minHeap.UpdateKey(heapMapping[neighbour.Key.Value], decremented); heapMapping[neighbour.Key.Value] = decremented; } else { //insert neighbour in heap var discovered = new AStarWrap <T, W>(heuristic, destination) { Distance = newDistance, Vertex = neighbour.Key.Value }; minHeap.Insert(discovered); heapMapping[neighbour.Key.Value] = discovered; } //trace parent parentMap[neighbour.Key.Value] = current.Vertex; } } } return(tracePath(graph, parentMap, source, destination)); }