public void PopTest() { // Heap FibonacciHeap <float, char> heap = new FibonacciHeap <float, char>(); HashSet <float> equalPriorirtyMinimums = new HashSet <float>() { 'b', 'e', 'f', 'g' }; // Check heap starts with no nodes Assert.AreEqual(heap.Count, 0); // Add collection of nodes HeapNode <float, char> node2 = heap.Insert(7, 'b'); HeapNode <float, char> node1 = heap.Insert(3, 'a'); HeapNode <float, char> node3 = heap.Insert(14, 'c'); HeapNode <float, char> node4 = heap.Insert(35, 'd'); HeapNode <float, char> node5 = heap.Insert(7, 'e'); HeapNode <float, char> node6 = heap.Insert(7, 'f'); HeapNode <float, char> node7 = heap.Insert(7, 'g'); // Check heap has correct number of nodes Assert.AreEqual(heap.Count, 7); char minimum = heap.Pop(); // Check returned item is the correct value, and is not still in heap Assert.AreEqual(minimum, 'a'); Assert.AreNotEqual(heap.Minimum.Value, minimum); Assert.AreEqual(heap.Count, 6); // Pop a set of equal priority values, check heap outputs them all (order is undefined) for (int i = 0; i < equalPriorirtyMinimums.Count; i++) { minimum = heap.Pop(); // Check returned item is the correct value, and is not still in heap Assert.IsTrue(equalPriorirtyMinimums.Contains(minimum)); Assert.AreNotEqual(heap.Minimum.Value, minimum); Assert.AreEqual(heap.Count, 5 - i); } minimum = heap.Pop(); // Check returned item is the correct value, and is not still in heap Assert.AreEqual(minimum, 'c'); Assert.AreNotEqual(heap.Minimum.Value, minimum); Assert.AreEqual(heap.Count, 1); minimum = heap.Pop(); // Check returned item is the correct value Assert.AreEqual(minimum, 'd'); Assert.AreEqual(heap.Count, 0); }
public static void Union_NonEmptyHeap_ReturnsSortedOrder() { var oddHeap = new FibonacciHeap <int>(); for (var i = 1; i < 10; i += 2) { oddHeap.Push(i); } var evenHeap = new FibonacciHeap <int>(); for (var i = 0; i < 10; i += 2) { evenHeap.Push(i); } oddHeap.Union(evenHeap); for (var i = 0; i < 10; i++) { Assert.AreEqual(i, oddHeap.Pop()); } Assert.Zero(oddHeap.Count); Assert.Zero(evenHeap.Count); }
public static void DecreaseKey_NonEmptyHeap_PreservesHeapStructure() { var heap = new FibonacciHeap <int>(); for (var i = 11; i < 20; i++) { heap.Push(i); } var item = heap.Push(10); for (var i = 0; i < 10; i++) { heap.Push(i); } var bigItem = heap.Push(20); heap.DecreaseKey(item, -1); Assert.AreEqual(heap.Pop(), -1); var currentVal = -1; for (var i = 0; i < 10; i++) { var newVal = heap.Pop(); Assert.True(currentVal < newVal); currentVal = newVal; } heap.DecreaseKey(bigItem, -1); Assert.AreEqual(heap.Pop(), -1); currentVal = -1; for (var i = 0; i < 9; i++) { var newVal = heap.Pop(); Assert.True(currentVal < newVal); currentVal = newVal; } }
public void TestBasicFunctionality() { var heap = new FibonacciHeap <int>(); heap.Insert(4, 4); heap.Insert(1, 1); heap.Insert(5, 5); heap.Insert(2, 2); heap.Insert(3, 3); int a = heap.Pop(); int b = heap.Pop(); int c = heap.Pop(); int d = heap.Pop(); int e = heap.Pop(); Assert.AreEqual(1, a); Assert.AreEqual(2, b); Assert.AreEqual(3, c); Assert.AreEqual(4, d); Assert.AreEqual(5, e); }
/// <summary> /// Uses A*-algorithm to find the best route between two tiles. /// </summary> /// <param name="start">First tile to search from.</param> /// <param name="goal">Goal to find.</param> /// <param name="previous">Tile just before the first tile.</param> /// <param name="forbidden">List of tiles that should be never used on route.</param> /// <param name="sign">Optional function for building signs.</param> /// <returns></returns> internal static List <PathInfo> FindPath(TileIndex start, TileIndex goal, TileIndex previous, HashSet <TileIndex> forbidden = null, Action <TileIndex, string> sign = null) { // Nodes to evaluate var tilesToProcess = new FibonacciHeap <TileIndex>(); tilesToProcess.Insert(start, 0); // Nodes evaluated var cameFrom = new Dictionary <TileIndex, PathInfo>(); cameFrom[start] = new PathInfo(start, 1, 0, BuildType.Basic, previous != null ? new PathInfo(previous, 1, 0, BuildType.Basic, null) : null); while (tilesToProcess.Count() > 0) { var current = tilesToProcess.Pop(); //AILog.Info($"Processing: {Helper.FormatTile(current)}"); if (current == goal) { // We found the target. return(RoadBuilder.BuildFinalPath(cameFrom[current])); } var neighbors = RoadBuilder.GetNeighbors(current, cameFrom[current]); foreach (var neighborItem in neighbors) { var neighbor = neighborItem.Tile; if ((neighbor == previous) || ((forbidden != null) && forbidden.Contains(neighbor))) { // We can't go here. continue; } var neighborDist = neighborItem.Length; if (!cameFrom.ContainsKey(neighbor)) { tilesToProcess.Insert(neighbor, neighborItem.Cost); } else { if (neighborItem.Cost >= cameFrom[neighbor].Cost) { continue; } } sign?.Invoke(neighbor, neighborItem.Cost.ToString()); cameFrom[neighbor] = neighborItem; } } return(null); }
public void FibonacciHeapTest1() { const int Count = 1000000; Random random = new Random(0); FibonacciHeap <int, int> heap = new FibonacciHeap <int, int>(100); int count = 0; while (count < Count) { // add more elements to the heap for (int i = 0, ii = random.Next(10, 100); i < ii; i++, count++) { heap.Push(random.Next(0, 100), 1000); } // pop some elements Pop(random.Next(heap.Count / 2, 3 * heap.Count / 4)); } // pop remaining element Pop(heap.Count); void Pop(int popcount) { if (popcount > 0) { int previous = heap.Pop().key; for (int i = 0, ii = Math.Max(0, popcount - 1); i < ii; i++) { int value = heap.Pop().key; Assert.IsTrue(previous <= value); previous = value; } } } }
public static void Pop_NonEmptyHeap_ReturnsInSortedOrder() { var heap = new FibonacciHeap <int>(); var rand = new Random(); var heapSize = 100; for (var i = 0; i < heapSize; i++) { heap.Push(rand.Next(1000)); } var element = heap.Pop(); for (var i = 0; i < heapSize - 1; i++) { var newElement = heap.Pop(); Assert.LessOrEqual(element, newElement); element = newElement; } Assert.Zero(heap.Count); }
public List <Tile> FindReachableTiles(Unit unit, Tile center, int ap) { List <Tile> tiles = new List <Tile>(); Dictionary <Tile, FibonacciHeapNode <TileMeta> > tileMap = new Dictionary <Tile, FibonacciHeapNode <TileMeta> >(); FibonacciHeap <TileMeta> heap = new FibonacciHeap <TileMeta>(); tileMap.Add(center, heap.Push(new TileMeta(center, 0))); while (!heap.IsEmpty()) { TileMeta tileMeta = heap.Pop().Value; Tile tile = tileMeta.tile; tiles.Add(tile); int previousCost = tileMeta.value; foreach (Vector2Int gridPosition in GetAdjacentGridPositions(tile.x, tile.y)) { tile = GetTile(gridPosition); if (IsAccessible(unit, tile)) { int cost = previousCost + unit.Statistics.CalculateEffectiveFatigue(tile.Cost, FatigueType.Movement); if (tileMap.ContainsKey(tile)) { FibonacciHeapNode <TileMeta> node = tileMap[tile]; if (cost < node.Value.value) { heap.Decrement(node, new TileMeta(tile, cost)); } } else if (cost <= ap) { tileMap.Add(tile, heap.Push(new TileMeta(tile, cost))); } } } } return(tiles); }
public static void Pop_EmptyHeap_ThrowsCorrectException() { var heap = new FibonacciHeap <int>(); Assert.Throws <InvalidOperationException>(() => heap.Pop()); }
public static Path <T> FindPath <T>(INavGrid <T> navGrid, T start, T destination, AccessibilityPredicate IsAccessible) where T : IEquatable <T> { Vector2Int startIndices = navGrid.GetGridPosition(start); Vector2Int destinationIndices = navGrid.GetGridPosition(destination); if (!IsAccessible(startIndices.x, startIndices.y) || !IsAccessible(destinationIndices.x, destinationIndices.y)) { return(null); } if (start.Equals(destination)) { return(new Path <T>(start)); } int length = navGrid.Length; int width = navGrid.Width; bool[,] closedList = new bool[length, width]; AStarTile <T>[,] tiles = new AStarTile <T> [length, width]; for (int x = 0; x < length; x++) { for (int y = 0; y < width; y++) { tiles[x, y].indices = new Vector2Int(x, y); tiles[x, y].previous = new Vector2Int(-1, -1); tiles[x, y].f = float.MaxValue; tiles[x, y].g = float.MaxValue; tiles[x, y].h = float.MaxValue; } } FibonacciHeap <AStarTile <T> > openList = new FibonacciHeap <AStarTile <T> >(); Dictionary <Vector2Int, FibonacciHeapNode <AStarTile <T> > > openListMap = new Dictionary <Vector2Int, FibonacciHeapNode <AStarTile <T> > >(); tiles[startIndices.x, startIndices.y].indices = startIndices; tiles[startIndices.x, startIndices.y].previous = startIndices; tiles[startIndices.x, startIndices.y].f = 0; tiles[startIndices.x, startIndices.y].g = 0; tiles[startIndices.x, startIndices.y].h = 0; openListMap.Add(startIndices, openList.Push(tiles[startIndices.x, startIndices.y])); while (!openList.IsEmpty()) { AStarTile <T> current = openList.Pop().Value; Vector2Int currentIndices = current.indices; int x = currentIndices.x; int y = currentIndices.y; closedList[x, y] = true; List <Vector2Int> adjacentGridPositions = navGrid.GetAdjacentGridPositions(x, y); for (int i = 0; i < adjacentGridPositions.Count; i++) { Vector2Int neighborIndices = adjacentGridPositions[i]; int xi = neighborIndices.x; int yi = neighborIndices.y; if (neighborIndices == destinationIndices) { tiles[xi, yi].previous = currentIndices; LinkedList <T> wayPoints = new LinkedList <T>(); while (neighborIndices != startIndices) { wayPoints.AddFirst(navGrid.GetTile(neighborIndices)); neighborIndices = tiles[neighborIndices.x, neighborIndices.y].previous; } return(new Path <T>(start, wayPoints)); } if (closedList[xi, yi] || !IsAccessible(xi, yi)) { continue; } float gNew = current.g + MathUtility.ManhattanDistance(xi, yi, x, y); float hNew = MathUtility.ManhattanDistance(xi, yi, destinationIndices.x, destinationIndices.y); float fNew = gNew + hNew; if (tiles[xi, yi].f < fNew) { continue; } tiles[xi, yi].previous = currentIndices; tiles[xi, yi].g = gNew; tiles[xi, yi].h = hNew; tiles[xi, yi].f = fNew; if (!openListMap.ContainsKey(neighborIndices)) { openListMap.Add(neighborIndices, openList.Push(tiles[xi, yi])); } else { openList.Decrement(openListMap[neighborIndices], tiles[xi, yi]); } } } return(null); }
private List <TraceEvent> Sort1007(IDictionary <int, List <TraceEvent> > rawBatches) { var pending = 0; Span <EventBatch> batches = new EventBatch[rawBatches.Count]; var result = new List <TraceEvent>(); foreach (var(i, eventList) in rawBatches.Values.Select((val, i) => (i, val))) { pending += eventList.Count; batches[i] = new EventBatch(eventList, false); } using var totalProgress = _registry?.Start("Sort Events", "Sort events based on states transition"); var gs = new Dictionary <ulong, GState>(); var frontier = new FibonacciHeap <OrderEvent>(); var totalCount = pending; using (var progress = _registry?.Start("Reorganize events", "Reorganize events based on relationship", totalProgress)) { for (; pending != 0; pending--) { if (!(progress is null)) { progress.PercentComplete = (totalCount - pending) / (float)totalCount; } for (var i = 0; i < rawBatches.Count; i++) { ref var b = ref batches[i]; if (b.Selected || !b.HasMore()) { continue; } var ev = b.Head; var(g, init, next) = StateTransition(ev); if (!TransitionReady(g, gs.GetValueOrDefault(g), init)) { continue; } frontier.Add(new OrderEvent(ev, i, g, init, next)); b.MoveNext(); b.Selected = true; switch (ev.Type) { case EventType.GoStartLocal: ev.Type = EventType.GoStart; break; case EventType.GoUnblockLocal: ev.Type = EventType.GoUnblock; break; case EventType.GoSysExitLocal: ev.Type = EventType.GoSysExit; break; } } if (frontier.Count == 0) { throw new InvalidTraceException("no consistent ordering of events possible"); } var f = frontier.Pop(); Transition(gs, f.G, f.Init, f.Next); result.Add(f.Event); if (!batches[f.Batch].Selected) { throw new Exception("frontier batch is not selected"); } batches[f.Batch].Selected = false; } }
public override IPath FindPath(Grid grid, Location start, Location goal) { OnStarted(); Statistics.Reset(); Statistics.TotalGridNodes = grid.Width * grid.Height; Statistics.StartTimer(); if (!ValidateGoal(grid, goal)) { var p = new Path(start, start); p.PushBack(start); OnPathNotFound(); return(p); } var openList = new FibonacciHeap <uint, Location>(0); var isClosed = new bool[grid.Width, grid.Height]; var soFarCost = new uint[grid.Width, grid.Height]; var parents = new Location?[grid.Width, grid.Height]; var queueNode = new IPair <uint, Location> [grid.Width, grid.Height]; var hotspot = start; queueNode[start.X, start.Y] = openList.Push(0, hotspot); var adjacents = new Location[8]; while (hotspot != goal) { Statistics.UpdateMaximumOpenNodes((uint)openList.Count); if (openList.Count <= 0) { OnPathNotFound(); return(null); } hotspot = openList.Pop().Value; isClosed[hotspot.X, hotspot.Y] = true; Statistics.AddClosedNode(); SetAdjacentArray(adjacents, hotspot); for (var i = 0; i < adjacents.Length; i++) { var pos = adjacents[i]; if (ProbeMode == EProbeMode.FourDirections && pos.X != hotspot.X && pos.Y != hotspot.Y) { continue; } if (grid.InBounds(pos) && hotspot != pos && grid[pos] && !isClosed[pos.X, pos.Y]) { if (!HasCornerBetween(grid, hotspot, pos) && !HasDiagonalWall(grid, hotspot, pos)) { if (queueNode[pos.X, pos.Y] == null) { parents[pos.X, pos.Y] = hotspot; var scoreH = CalculateHeuristicCost(pos, goal); var scoreG = soFarCost[hotspot.X, hotspot.Y] + CalculateDistance(pos, hotspot); var score = scoreH + scoreG; queueNode[pos.X, pos.Y] = openList.Push(score, pos); soFarCost[pos.X, pos.Y] = scoreG; Statistics.AddOpenedNode(); } else { if (!parents[pos.X, pos.Y].HasValue) { continue; } var currentParent = parents[pos.X, pos.Y].Value; var currentScoreG = soFarCost[currentParent.X, currentParent.Y] + CalculateDistance(pos, currentParent); var newScoreG = soFarCost[hotspot.X, hotspot.Y] + CalculateDistance(pos, hotspot); if (newScoreG < currentScoreG) { parents[pos.X, pos.Y] = hotspot; soFarCost[pos.X, pos.Y] = newScoreG; var score = newScoreG + CalculateHeuristicCost(pos, goal); openList.DecreaseKey(queueNode[pos.X, pos.Y], score); } } } } OnIteration(); Statistics.AddIteration(); } } Statistics.PathCost = soFarCost[hotspot.X, hotspot.Y]; var inverter = new Stack <Location>(); Location?aux = hotspot; while (aux.HasValue) { inverter.Push(aux.Value); aux = parents[aux.Value.X, aux.Value.Y]; } var path = new Path(start, goal); while (inverter.Count > 0) { path.PushBack(inverter.Pop()); } OnPathFound(); Statistics.StopTimer(); Statistics.PathLength = path.Size; return(path); }