// Kruskal's algorithm is (get the min weight edge from PQ and keep adding to tree if it does not cause a cycle // repeat until v-1 edges are added to the tree or until all edges are exhausted. private void Kruskal(EdgeWeightedGraph <V> graph) { PriorityQueueHeap <Edge <V> > _pq = new PriorityQueueHeap <Edge <V> >(); foreach (Edge <V> edge in graph.Edges()) { _pq.Insert(edge); } DisjointSets_UnionFind uf = new DisjointSets_UnionFind(); // This should be extractMin (but we can subtract the weight from 100 or something // such that the min weight becomes the max item while (!_pq.IsEmpty && _queue.Count < graph.TotalVertices() - 1) { var item = _pq.Extract(); V start = item.Either; V end = item.Other; var startHash = ModedHash(start.GetHashCode()); var endHash = ModedHash(end.GetHashCode()); // Union find works in iterated logarithm since path compression helps move the children // near the root or parent of the tree. if (!uf.Connected(startHash, endHash)) { uf.MakeSet(startHash); uf.MakeSet(endHash); uf.Union(startHash, endHash); _queue.Enqueue(item); } } }
// Eager prim needs indexed priority queue // start at first vertex, find the min weight edge and add it to the tree. // Now find a min weight edge that goes out from the tree to non-tree vertex and add it and so on. private void LazyPrim(EdgeWeightedGraph <V> graph) { var marked = new Boolean[graph.TotalVertices()]; var _pq = new PriorityQueueHeap <Edge <V> >(); LazyPrimVisit(graph, graph.Edges().First().Either, marked, _pq); while (!_pq.IsEmpty) { // This should be extractMin (but we can subtract the weight from 100 or something // such that the min weight becomes the max item var item = _pq.Extract(); V start = item.Either; V end = item.Other; var startHash = ModedHash(start.GetHashCode()); var endHash = ModedHash(end.GetHashCode()); if (marked[startHash] && marked[endHash]) { continue; } _queue.Enqueue(item); if (!marked[startHash]) { LazyPrimVisit(graph, start, marked, _pq); } if (!marked[endHash]) { LazyPrimVisit(graph, end, marked, _pq); } } }
private static void customHeapSort(int[] arr, int size) // O(n*log(n)) { PriorityQueueHeap priorityQueue = new PriorityQueueHeap(size); for (int i = 0; i < size; i++) { priorityQueue.Push(arr[i]); } for (int i = 0; i < size; i++) { arr[i] = priorityQueue.Top(); priorityQueue.Pop(); } }
private void LazyPrimVisit(EdgeWeightedGraph <V> graph, V either, Boolean[] marked, PriorityQueueHeap <Edge <V> > pq) { marked[ModedHash(either.GetHashCode())] = true; foreach (var edge in graph.Adjacency(either)) { if (!marked[ModedHash(edge.GetHashCode())]) { pq.Insert(edge); } } }
public List <SearchNode> Search(TData root, float costLimit = float.MaxValue) { NextCostLimitThreshhold = float.MaxValue; var priorityQueue = new PriorityQueueHeap <SearchNode>(); // Start at root var rootNode = new SearchNode { Data = root, Action = default(TAction), Parent = null, Cost = 0, EstimatedRemainingCost = Config.HeuristicFunc(root), }; priorityQueue.Insert(rootNode.EstimatedTotalCost, rootNode); while (!priorityQueue.IsEmpty) { CurrentNode = priorityQueue.ExtractTop(); if (Config.IsGoalFunc(CurrentNode)) { return(ReconstructPath(CurrentNode)); } var actions = Config.ActionsListFunc(CurrentNode); foreach (var action in actions) { var newNode = new SearchNode { Parent = CurrentNode, Data = Config.ActionApplierFunc(CurrentNode, action), Action = action, Cost = CurrentNode.Cost + Config.ActionCostFunc(CurrentNode, action), }; newNode.EstimatedRemainingCost = Config.HeuristicFunc(newNode.Data); if (newNode.Cost <= costLimit) { priorityQueue.Insert(newNode.EstimatedTotalCost, newNode); OnNodeGenerated(); } else { if (newNode.Cost < NextCostLimitThreshhold) { NextCostLimitThreshhold = newNode.Cost; } } } OnNodeExpanded(); NodesRetainedCount = priorityQueue.Count; } return(null); }
///////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////// BB Algorithm //////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// #region MainBBAlgorithm /// <summary> /// performs a Branch and Bound search of the state space of partial tours /// stops when time limit expires and uses BSSF as solution /// Time Complexity: O((n^2)*(2^n) as that is the most dominant factor in the code, and it is a result /// of the loop, for more details scroll to the comment above the loop in the function. /// Space Complexity: O((n^2)*(2^n) as that is the most dominant factor in the code, and it is a result /// of the loop, for more details scroll to the comment above the loop in the function. /// </summary> /// <returns>results array for GUI that contains three ints: cost of solution, time spent to find solution, number of solutions found during search (not counting initial BSSF estimate)</returns> public string[] bBSolveProblem() { string[] results = new string[3]; // Helper variables /* This part of the code takes O(1) space and time as we are just initializing some data */ int numOfCitiesLeft = Cities.Length; int numOfSolutions = 0; int numOfStatesCreated = 0; int numOfStatesNotExpanded = 0; // Initialize the time variable to stop after the time limit, which is defaulted to 60 seconds /* This part of the code takes O(1) space and time as we are just initializing some data */ DateTime start = DateTime.Now; DateTime end = start.AddSeconds(time_limit/1000); // Create the initial root State and set its priority to its lower bound as we don't have any extra info at this point /* This part of the code takes O(n^2) space and time as explained above */ State initialState = createInitialState(); numOfStatesCreated++; initialState.setPriority(calculateKey(numOfCitiesLeft - 1, initialState.getLowerBound())); // Create the initial BSSF Greedily /* This part of the code takes O(n^2) time and O(n) space as explained above */ double BSSFBOUND = createGreedyInitialBSSF(); // Create the queue and add the initial state to it, then subtract the number of cities left /* This part of the code takes O(1) time since we are just creating a data structure and O(1,000,000) space which is just a constant so O(1) space as well*/ PriorityQueueHeap queue = new PriorityQueueHeap(); queue.makeQueue(Cities.Length); queue.insert(initialState); // Branch and Bound until the queue is empty, we have exceeded the time limit, or we found the optimal solution /* This loop will have a iterate 2^n times approximately with expanding and pruning for each state, then for each state it does O(n^2) work by reducing the matrix, so over all O((n^2)*(2^n)) time and space as well as it creates a nxn matrix for each state*/ while (!queue.isEmpty() && DateTime.Now < end && queue.getMinLB() != BSSFBOUND) { // Grab the next state in the queue State currState = queue.deleteMin(); // check if lower bound is less than the BSSF, else prune it if (currState.getLowerBound() < BSSFBOUND) { // Branch and create the child states for (int i = 0; i < Cities.Length; i++) { // First check that we haven't exceeded the time limit if (DateTime.Now >= end) break; // Make sure we are only checking cities that we haven't checked already if (currState.getPath().Contains(Cities[i])) continue; // Create the State double[,] oldCostMatrix = currState.getCostMatrix(); double[,] newCostMatrix = new double[Cities.Length, Cities.Length]; // Copy the old array in the new one to modify the new without affecting the old for (int k = 0; k < Cities.Length; k++) { for (int l = 0; l < Cities.Length; l++) { newCostMatrix[k, l] = oldCostMatrix[k, l]; } } City lastCityinCurrState = (City)currState.getPath()[currState.getPath().Count-1]; double oldLB = currState.getLowerBound(); setUpMatrix(ref newCostMatrix, Array.IndexOf(Cities, lastCityinCurrState), i, ref oldLB); double newLB = oldLB + reduceMatrix(ref newCostMatrix); ArrayList oldPath = currState.getPath(); ArrayList newPath = new ArrayList(); foreach (City c in oldPath) { newPath.Add(c); } newPath.Add(Cities[i]); State childState = new State(ref newPath, ref newLB, ref newCostMatrix, Cities.Length); numOfStatesCreated++; // Prune States larger than the BSSF if (childState.getLowerBound() < BSSFBOUND) { City firstCity = (City)childState.getPath()[0]; City lastCity = (City)childState.getPath()[childState.getPath().Count-1]; double costToLoopBack = lastCity.costToGetTo(firstCity); // If we found a solution and it goes back from last city to first city if (childState.getPath().Count == Cities.Length && costToLoopBack != double.MaxValue) { childState.setLowerBound(childState.getLowerBound() + costToLoopBack); bssf = new TSPSolution(childState.getPath()); BSSFBOUND = bssf.costOfRoute(); numOfSolutions++; numOfStatesNotExpanded++; // this state is not expanded because it is not put on the queue } else { // Set the priority for the state and add the new state to the queue numOfCitiesLeft = Cities.Length - childState.getPath().Count; childState.setPriority(calculateKey(numOfCitiesLeft, childState.getLowerBound())); queue.insert(childState); } } else { numOfStatesNotExpanded++; // States that are pruned are not expanded } } } currState = null; } numOfStatesNotExpanded += queue.getSize(); // if the code terminated before queue is empty, then those states never got expanded Console.WriteLine("Number of states generated: " + numOfStatesCreated); Console.WriteLine("Number of states not Expanded: " + numOfStatesNotExpanded); Console.WriteLine("Max Number of states put in queue: " + queue.getMaxNumOfItems()); end = DateTime.Now; TimeSpan diff = end - start; double seconds = diff.TotalSeconds; results[COST] = System.Convert.ToString(bssf.costOfRoute()); // load results into array here, replacing these dummy values results[TIME] = System.Convert.ToString(seconds); results[COUNT] = System.Convert.ToString(numOfSolutions); return results; }