public void FibornacciMinHeap_Test() { int nodeCount = 1000 * 10; //insert test var tree = new FibornacciMinHeap <int>(); for (int i = 0; i <= nodeCount; i++) { tree.Insert(i); } for (int i = 0; i <= nodeCount; i++) { tree.DecrementKey(i, i - 1); } int min = 0; for (int i = 0; i <= nodeCount; i++) { min = tree.ExtractMin(); Assert.AreEqual(min, i - 1); } //IEnumerable tests. Assert.AreEqual(tree.Count, tree.Count()); var rnd = new Random(); var testSeries = Enumerable.Range(0, nodeCount - 1).OrderBy(x => rnd.Next()).ToList(); foreach (var item in testSeries) { tree.Insert(item); } for (int i = 0; i < testSeries.Count; i++) { var decremented = testSeries[i] - rnd.Next(0, 1000); tree.DecrementKey(testSeries[i], decremented); testSeries[i] = decremented; } testSeries.Sort(); for (int i = 0; i < nodeCount - 2; i++) { min = tree.ExtractMin(); Assert.AreEqual(testSeries[i], min); } //IEnumerable tests. Assert.AreEqual(tree.Count, tree.Count()); }
/// <summary> /// Get shortest distance to target /// </summary> /// <param name="graph"></param> /// <param name="source"></param> /// <param name="destination"></param> /// <returns></returns> public ShortestPathResult <T, W> GetShortestPath(WeightedDiGraph <T, W> graph, T source, T destination) { //regular argument checks if (graph == null || 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 FibornacciMinHeap <MinHeapWrap <T, W> >(); //keep references of heap Node for decrement key operation var heapMapping = new Dictionary <T, FibornacciHeapNode <MinHeapWrap <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; } //construct heap for all vertices with Max Distance as default var wrap = new MinHeapWrap <T, W>() { Distance = operators.MaxValue, Target = vertex.Key }; var heapNode = minHeap.Insert(wrap); heapMapping.Add(vertex.Key, heapNode); } //start from source vertex as current var sourceVertex = graph.Vertices[source]; var current = new MinHeapWrap <T, W>() { Distance = operators.DefaultValue, Target = source }; //until heap is empty while (minHeap.Count > 0) { //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.Target].OutEdges) { //new distance to neighbour var newDistance = operators.Sum(current.Distance, graph.Vertices[current.Target].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; heapMapping[neighbour.Key.Value].Value.Distance = newDistance; //decrement distance to neighbour in heap minHeap.DecrementKey(heapMapping[neighbour.Key.Value]); //trace parent parentMap[neighbour.Key.Value] = current.Target; } } //next min vertex to visit current = minHeap.ExtractMin(); } return(tracePath(graph, parentMap, source, destination)); }
public ShortestPathResult <T, W> GetShortestPath(WeightedDiGraph <T, W> graph, T source, T destination) { if (graph == null || graph.FindVertex(source) == null || graph.FindVertex(destination) == null) { throw new ArgumentException(); } var progress = new Dictionary <T, W>(); var parentMap = new Dictionary <T, T>(); var minHeap = new FibornacciMinHeap <MinHeapWrap <T, W> >(); var heapMapping = new Dictionary <T, FibornacciHeapNode <MinHeapWrap <T, W> > >(); foreach (var vertex in graph.Vertices) { parentMap.Add(vertex.Key, default(T)); progress.Add(vertex.Key, operators.MaxValue); if (vertex.Key.Equals(source)) { continue; } var wrap = new MinHeapWrap <T, W>() { Distance = operators.MaxValue, Target = vertex.Key }; var heapNode = minHeap.Insert(wrap); heapMapping.Add(vertex.Key, heapNode); } var sourceVertex = graph.Vertices[source]; var current = new MinHeapWrap <T, W>() { Distance = operators.DefaultValue, Target = source }; while (minHeap.Count > 0) { if (current.Distance.Equals(operators.MaxValue)) { return(new ShortestPathResult <T, W>(null, operators.MaxValue)); } foreach (var neighbour in graph.Vertices[current.Target].OutEdges) { var newDistance = operators.Sum(current.Distance, graph.Vertices[current.Target].OutEdges[neighbour.Key]); var existingDistance = progress[neighbour.Key.Value]; if (newDistance.CompareTo(existingDistance) < 0) { progress[neighbour.Key.Value] = newDistance; heapMapping[neighbour.Key.Value].Value.Distance = newDistance; minHeap.DecrementKey(heapMapping[neighbour.Key.Value]); parentMap[neighbour.Key.Value] = current.Target; } } current = minHeap.ExtractMin(); } return(tracePath(graph, parentMap, source, destination)); }
public void FibornacciMinHeap_Test() { int nodeCount = 1000 * 10; //insert test var tree = new FibornacciMinHeap <int>(); var nodePointers = new List <FibornacciHeapNode <int> >(); for (int i = 0; i <= nodeCount; i++) { var node = tree.Insert(i); nodePointers.Add(node); } for (int i = 0; i <= nodeCount; i++) { nodePointers[i].Value--; tree.DecrementKey(nodePointers[i]); } int min = 0; for (int i = 0; i <= nodeCount; i++) { min = tree.ExtractMin(); Assert.AreEqual(min, i - 1); } nodePointers.Clear(); var rnd = new Random(); var testSeries = Enumerable.Range(0, nodeCount - 1).OrderBy(x => rnd.Next()).ToList(); foreach (var item in testSeries) { nodePointers.Add(tree.Insert(item)); } min = tree.ExtractMin(); nodePointers = nodePointers.Where(x => x.Value != min).ToList(); var resultSeries = new List <int>(); for (int i = 0; i < nodePointers.Count; i++) { nodePointers[i].Value = nodePointers[i].Value - rnd.Next(0, 1000); tree.DecrementKey(nodePointers[i]); } foreach (var item in nodePointers) { resultSeries.Add(item.Value); } resultSeries.Sort(); for (int i = 0; i < nodeCount - 2; i++) { min = tree.ExtractMin(); Assert.AreEqual(resultSeries[i], min); } }
/// <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 FibornacciMinHeap <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.ExtractMin(); 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.DecrementKey(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)); }