public static ReductionResult RunTest(Graph graph) { var result = new ReductionResult(); List<int> bottlenecks = new List<int>(); for (int i = 0; i < graph.Terminals.Count; i++) { var pathToAll = Algorithms.DijkstraPathToAll(graph.Terminals[i], graph); // Only add the maximum bottleneck of all paths bottlenecks.Add(pathToAll.SelectMany(x => x.Value.Edges).Max(e => e.Cost)); } int B = bottlenecks.Max(); List<Edge> redundant = new List<Edge>(); foreach (var edge in graph.Edges.Where(edge => edge.Cost > B)) redundant.Add(edge); foreach (var edge in redundant) { graph.RemoveEdge(edge); result.RemovedEdges.Add(edge); } return result; }
public static ReductionResult RunTest(Graph graph) { var result = new ReductionResult(); var mst = Algorithms.Kruskal(graph.TerminalDistanceGraph); var S = mst.Edges.Max(edge => edge.Cost); foreach (var edge in graph.Edges.Where(e => e.Cost > S).ToList()) { graph.RemoveEdge(edge); result.RemovedEdges.Add(edge); } return result; }
public static ReductionResult RunTest(Graph graph, int upperBound) { var result = new ReductionResult(); // T. Polzin, lemma 25: Vertex removal int reductionBound = 0; int allRadiusesExceptTwoMostExpensive = graph.Terminals.Select(graph.GetVoronoiRadiusForTerminal).OrderBy(x => x).Take(graph.Terminals.Count - 2).Sum(); HashSet<Vertex> removeVertices = new HashSet<Vertex>(); foreach (var vertex in graph.Vertices.Except(graph.Required)) { var nearestTerminals = Algorithms.NearestTerminals(vertex, graph, 2); int lowerBound = nearestTerminals.Sum(x => x.TotalCost) + allRadiusesExceptTwoMostExpensive; if (lowerBound > upperBound) removeVertices.Add(vertex); else if (lowerBound > reductionBound) reductionBound = lowerBound; } foreach (var removeVertex in removeVertices) { graph.RemoveVertex(removeVertex); result.RemovedVertices.Add(removeVertex); } // Check for disconnected components (and remove those that not contain any terminals) var componentTable = graph.CreateComponentTable(); var terminalComponents = new HashSet<int>(); foreach (var vertex in graph.Terminals) terminalComponents.Add(componentTable[vertex]); foreach (var vertex in graph.Vertices.Where(x => !terminalComponents.Contains(componentTable[x])).ToList()) { graph.RemoveVertex(vertex); result.RemovedVertices.Add(vertex); } // T. Polzin, lemma 26: edge removal allRadiusesExceptTwoMostExpensive = graph.Terminals.Select(graph.GetVoronoiRadiusForTerminal).OrderBy(x => x).Take(graph.Terminals.Count - 2).Sum(); HashSet<Edge> removeEdges = new HashSet<Edge>(); Dictionary<Vertex, int> distancesToBase = new Dictionary<Vertex, int>(); foreach (var terminal in graph.Terminals) { var toAll = Algorithms.DijkstraToAll(terminal, graph); foreach (var vertex in graph.Vertices) { if (vertex == terminal) continue; if (!distancesToBase.ContainsKey(vertex)) distancesToBase.Add(vertex, toAll[vertex]); else if (toAll[vertex] < distancesToBase[vertex]) distancesToBase[vertex] = toAll[vertex]; } } foreach (var edge in graph.Edges) { var v1 = edge.Either(); var v2 = edge.Other(v1); if (graph.Terminals.Contains(v1) || graph.Terminals.Contains(v2)) continue; var v1z1 = distancesToBase[v1]; var v2z2 = distancesToBase[v2]; var lowerBound = edge.Cost + v1z1 + v2z2 + allRadiusesExceptTwoMostExpensive; if (lowerBound > upperBound) removeEdges.Add(edge); else if (lowerBound > reductionBound) reductionBound = lowerBound; } foreach (var removeEdge in removeEdges) { graph.RemoveEdge(removeEdge); result.RemovedEdges.Add(removeEdge); } result.ReductionUpperBound = reductionBound; return result; }
/// <summary> /// Runs an approximation of the Special Distance Test to reduce the graph. /// This test runs much faster and offers only a small difference in performance. /// </summary> /// <param name="graph">The graph on which to run the test.</param> /// <returns>The reduced graph.</returns> public static ReductionResult RunTest(Graph graph) { if (!graph.Terminals.All(graph.ContainsVertex)) Debugger.Break(); var tmst = Algorithms.Kruskal(graph.TerminalDistanceGraph); var terminalSpecialDistances = new MultiDictionary<Vertex, int>(); for (int i = 0; i < graph.Terminals.Count - 1; i++) { var tFrom = graph.Terminals[i]; var toAll = Algorithms.DijkstraPathToAll(tFrom, tmst); for (int j = i + 1; j < graph.Terminals.Count; j++) { var tTo = graph.Terminals[j]; var path = toAll[tTo]; var sd = path.Edges.Max(x => x.Cost); terminalSpecialDistances.Add(tFrom, tTo, sd); } } var result = new ReductionResult(); // Find all special distances between terminals int count = 0; int e = graph.NumberOfEdges; Dictionary<Vertex, Path> nearest = new Dictionary<Vertex, Path>(); HashSet<Edge> remove = new HashSet<Edge>(); int edgesWithoutRemoval = 0; foreach (var edge in graph.Edges.OrderByDescending(x => x.Cost)) { count++; var vFrom = edge.Either(); var vTo = edge.Other(vFrom); int SDEstimate = int.MaxValue; Path pathToNearestFrom = null; if (nearest.ContainsKey(vFrom)) pathToNearestFrom = nearest[vFrom]; else { pathToNearestFrom = Algorithms.NearestTerminal(vFrom, graph); nearest.Add(vFrom, pathToNearestFrom); } var aNearestTerminalFrom = pathToNearestFrom.End; Path pathToNearestTo = null; if (nearest.ContainsKey(vTo)) pathToNearestTo = nearest[vTo]; else { pathToNearestTo = Algorithms.NearestTerminal(vTo, graph); nearest.Add(vTo, pathToNearestTo); } var bNearestTerminalTo = pathToNearestTo.End; // SD = Max( dist(v, z_a), dist(w, z_b), sd(z_a, z_b) ) var sd = Math.Max(pathToNearestFrom.TotalCost, pathToNearestTo.TotalCost); if (aNearestTerminalFrom != bNearestTerminalTo) { var sdTerminals = terminalSpecialDistances[aNearestTerminalFrom, bNearestTerminalTo]; sd = Math.Max(sd, sdTerminals); } if (sd < SDEstimate) SDEstimate = sd; if (edge.Cost > SDEstimate) { edgesWithoutRemoval = 0; remove.Add(edge); } else if (++edgesWithoutRemoval >= graph.NumberOfEdges / 100) // Expecting a 1% reduction { break; } } foreach (var edge in remove) { graph.RemoveEdge(edge); result.RemovedEdges.Add(edge); } return result; }
private void AddEdgesToMST(Graph mst, List<Edge> edges) { foreach (var edge in edges) { if (edge.WhereBoth(x => mst.GetDegree(x) > 0)) //Both vertices of this edge are in the MST, introducing this edge creates cycle! { var v1 = edge.Either(); var v2 = edge.Other(v1); var components = mst.CreateComponentTable(); if (components[v1] == components[v2]) { // Both are in the same component, and a path exists. // Travel the path to see if adding this edge makes it cheaper var path = Algorithms.DijkstraPath(v1, v2, mst); // However, we can remove a set of edges between two nodes // When going from T1 to T3 // E.g.: T1 - v2 - v3 - v4 - T2 - v5 - v6 - T3 // The edges between T1, v2, v3, v4, T2 cost more than the path between T1 and T3. // Removing those edges, and adding the new edge from T1 to T3, also connects // T1 to T2, so still a tree! var from = path.Start; var last = path.Start; int betweenTerminals = 0; var subtractedPath = new Path(path.Start); List<Edge> edgesInSubtraction = new List<Edge>(); Dictionary<Edge, List<Edge>> subtractions = new Dictionary<Edge, List<Edge>>(); for (int i = 0; i < path.Edges.Count; i++) { var pe = path.Edges[i]; betweenTerminals += pe.Cost; last = pe.Other(last); edgesInSubtraction.Add(pe); if (mst.GetDegree(last) > 2 || mst.Terminals.Contains(last) || i == path.Edges.Count - 1) { var subtractedEdge = new Edge(from, last, betweenTerminals); subtractions.Add(subtractedEdge, edgesInSubtraction); edgesInSubtraction = new List<Edge>(); subtractedPath.Edges.Add(subtractedEdge); from = last; betweenTerminals = 0; } } var mostCostly = subtractedPath.Edges[0]; for (int i = 1; i < subtractedPath.Edges.Count; i++) { if (subtractedPath.Edges[i].Cost > mostCostly.Cost) mostCostly = subtractedPath.Edges[i]; } if (mostCostly.Cost >= edge.Cost) { foreach (var e in subtractions[mostCostly]) mst.RemoveEdge(e, false); mst.AddEdge(edge); } } else // Connect the two disconnected components! mst.AddEdge(edge); } else mst.AddEdge(edge); } }
/// <summary> /// Runs the Special Distance Test to reduce the graph. /// </summary> /// <param name="graph">The graph on which to run the test.</param> /// <returns>The reduced graph.</returns> public static ReductionResult RunTest(Graph graph) { List<Edge> redundant = new List<Edge>(); var result = new ReductionResult(); var distanceGraph = graph.CreateDistanceGraph(); var specialDistanceGraph = CreateInitialSpecialDistanceGraph(graph); for (int i = 0; i < graph.NumberOfVertices; i++) { Console.Write("SD Test: {0}/{1} \r", i, graph.NumberOfVertices); // Step 1. L := { i } // for all j set delta_j = d_ij // In each iteration, delta_j means the current special distance from the start vertex to j. var vFrom = graph.Vertices[i]; List<Vertex> L = new List<Vertex>(new [] { vFrom }); // Initially only the start veretx is labeled. // Initially set special distance equal to distance foreach (var edge in specialDistanceGraph.GetEdgesForVertex(vFrom)) { edge.Cost = distanceGraph.GetEdgesForVertex(vFrom).Single(x => x.Other(vFrom) == edge.Other(vFrom)).Cost; //edge.Cost = Math.Min(edge.Cost, // distanceGraph.GetEdgesForVertex(vFrom).Single(x => x.Other(vFrom) == edge.Other(vFrom)).Cost); } List<Vertex> unhandledTerminals = null; // K \ L while ((unhandledTerminals = graph.Terminals.Where(x => !L.Contains(x)).ToList()).Count > 0) { // While K \ L is not empty // Find the terminal which minimizes delta(j) for all j in K \ L int currentMinimum = int.MaxValue; Vertex k = null; var edgesFrom = specialDistanceGraph.GetEdgesForVertex(vFrom); foreach (var terminal in unhandledTerminals) { var deltaEdge = edgesFrom.First(x => x.Other(vFrom) == terminal); if (deltaEdge.Cost < currentMinimum) { currentMinimum = deltaEdge.Cost; k = terminal; } } L.Add(k); // Re-lable all vertices that haven't gotten a definitive label yet. var delta_k = edgesFrom.First(x => x.Other(vFrom) == k).Cost; foreach (var unlabeled in graph.Vertices.Where(x => !L.Contains(x))) { var d_kj = distanceGraph.GetEdgesForVertex(k).First(x => x.Other(k) == unlabeled).Cost; var deltaEdge = edgesFrom.First(x => x.Other(vFrom) == unlabeled); deltaEdge.Cost = Math.Min(deltaEdge.Cost, Math.Max(delta_k, d_kj)); } } var specialEdges = specialDistanceGraph.GetEdgesForVertex(vFrom); var distanceEdges = distanceGraph.GetEdgesForVertex(vFrom); var edges = graph.GetEdgesForVertex(vFrom); foreach (var redundantEdge in specialEdges.Where(x => x.Cost < distanceEdges.First(y => y.Other(vFrom) == x.Other(vFrom)).Cost)) { // Special distance is smaller than distance. Edge is redundant. var edge = edges.FirstOrDefault(x => x.Other(vFrom) == redundantEdge.Other(vFrom)); if (edge != null) redundant.Add(edge); } } foreach (var edge in redundant) { graph.RemoveEdge(edge); result.RemovedEdges.Add(edge); } Console.Write(" \r"); return result; }
public static Graph RunSolver(Graph graph) { var solution = new Graph(graph.Vertices); DijkstraState state = new DijkstraState(); // Create the states needed for every execution of the Dijkstra algorithm foreach (var terminal in graph.Terminals) state.AddVertexToInterleavingDijkstra(terminal, graph); // Initialize Vertex currentVertex = state.GetNextVertex(); FibonacciHeap<int, Vertex> labels = state.GetLabelsFibonacciHeap(); HashSet<Vertex> visited = state.GetVisitedHashSet(); Dictionary<Vertex, Path> paths = state.GetPathsFound(); Dictionary<Vertex, FibonacciHeap<int, Vertex>.Node> nodes = state.GetNodeMapping(); Dictionary<Vertex, Edge> comingFrom = state.GetComingFromDictionary(); Dictionary<Vertex, int> components = solution.CreateComponentTable(); Dictionary<Vertex, double> terminalFValues = CreateInitialFValuesTable(graph); int maxLoopsNeeded = graph.Terminals.Count * graph.NumberOfVertices; int loopsDone = 0; int updateInterval = 100; int longestPath = graph.Terminals.Max(x => Algorithms.DijkstraToAll(x, graph).Max(y => y.Value)); while (state.GetLowestLabelVertex() != null) { if (loopsDone % updateInterval == 0) Console.Write("\rRunning IDA... {0:0.0}% \r", 100.0 * loopsDone / maxLoopsNeeded); loopsDone++; if (state.GetLowestLabelVertex() != currentVertex) { // Interleave. Switch to the Dijkstra procedure of the vertex which currently has the lowest distance. state.SetLabelsFibonacciHeap(labels); state.SetVisitedHashSet(visited); state.SetPathsFound(paths); state.SetComingFromDictionary(comingFrom); currentVertex = state.GetNextVertex(); labels = state.GetLabelsFibonacciHeap(); visited = state.GetVisitedHashSet(); paths = state.GetPathsFound(); nodes = state.GetNodeMapping(); comingFrom = state.GetComingFromDictionary(); } // Do one loop in Dijkstra algorithm var currentNode = labels.ExtractMin(); var current = currentNode.Value; if (currentNode.Key > longestPath / 2) break; //Travelled across the half of longest distance. No use in going further. // Consider all edges ending in unvisited neighbours var edges = graph.GetEdgesForVertex(current).Where(x => !visited.Contains(x.Other(current))); // Update labels on the other end foreach (var edge in edges) { if (currentNode.Key + edge.Cost < nodes[edge.Other(current)].Key) { labels.DecreaseKey(nodes[edge.Other(current)], currentNode.Key + edge.Cost); comingFrom[edge.Other(current)] = edge; } } visited.Add(current); if (current != currentVertex) { // Travel back the new path List<Edge> pathEdges = new List<Edge>(); Vertex pathVertex = current; while (pathVertex != currentVertex) { pathEdges.Add(comingFrom[pathVertex]); pathVertex = comingFrom[pathVertex].Other(pathVertex); } pathEdges.Reverse(); Path path = new Path(currentVertex); path.Edges.AddRange(pathEdges); paths[current] = path; } // Find matching endpoints from two different terminals var mutualEnd = state.FindPathsEndingInThisVertex(current); if (mutualEnd.Count() > 1) { var terminals = mutualEnd.Select(x => x.Start).ToList(); // Step 1. Calculate new heuristic function value for this shared point. // f(x) = (Cost^2)/(NumberOfTerminals^3) var f1 = Math.Pow(mutualEnd.Sum(p => p.TotalCost), 2) / Math.Pow(terminals.Count, 3); var f2 = Math.Pow(mutualEnd.Sum(p => p.TotalCost), 1) / Math.Pow(terminals.Count, 2); var f3 = Math.Pow(mutualEnd.Sum(p => p.TotalCost), 3) / Math.Pow(terminals.Count, 2); var terminalsAvgF = terminals.Select(x => terminalFValues[x]).Average(); var terminalsMinF = terminals.Select(x => terminalFValues[x]).Min(); var f = (new[] { f1, f2, f3 }).Max(); Debug.WriteLine("F value: {0}, Fmin: {3} - Connecting terminals: {1} via {2}", f, string.Join(", ", terminals.Select(x => x.VertexName)), current.VertexName, terminalsMinF); // Do not proceed if f > avgF AND working in same component if (terminals.Select(x => components[x]).Distinct().Count() == 1 && f > terminalsMinF) continue; Debug.WriteLine("Proceeding with connection..."); // Step 2. Disconnect terminals in mutual component. foreach (var group in terminals.GroupBy(x => components[x])) { if (group.Count() <= 1) continue; HashSet<Edge> remove = new HashSet<Edge>(); var sameComponentTerminals = group.ToList(); for (int i = 0; i < sameComponentTerminals.Count-1; i++) { for (int j = i+1; j< sameComponentTerminals.Count; j++) { var removePath = Algorithms.DijkstraPath(sameComponentTerminals[i], sameComponentTerminals[j], solution); foreach (var e in removePath.Edges) remove.Add(e); } } foreach (var e in remove) solution.RemoveEdge(e, false); } components = solution.CreateComponentTable(); // Step 3. Reconnect all now disconnected terminals via shared endpoint foreach (var t in terminals) { var path = Algorithms.DijkstraPath(t, current, graph); foreach (var edge in path.Edges) solution.AddEdge(edge); // Update f value terminalFValues[t] = f; } components = solution.CreateComponentTable(); } } // If this solution is connected, take MST if (graph.Terminals.Select(x => components[x]).Distinct().Count() == 1) { // Clean up! foreach (var vertex in solution.Vertices.Where(x => solution.GetDegree(x) == 0).ToList()) solution.RemoveVertex(vertex); int componentNumber = graph.Terminals.Select(x => components[x]).Distinct().Single(); foreach (var vertex in components.Where(x => x.Value != componentNumber).Select(x => x.Key).ToList()) solution.RemoveVertex(vertex); solution = Algorithms.Kruskal(solution); return solution; } // If the solution is not connected, it is not a good solution. return null; }