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, int upperBound) { var graphContracted = graph.Clone(); int reductionBound = int.MaxValue; // 1. Contract edges in MST that are in same Voronoi region var degreeTwo = graphContracted.Vertices.Where(x => graphContracted.GetDegree(x) == 2).ToList(); // Vertices which could be removed by contracting their adjacent edges foreach (var vertex in degreeTwo) { var voronoi = graph.GetVoronoiRegionForVertex(vertex); var edge1 = graphContracted.GetEdgesForVertex(vertex)[0]; var edge2 = graphContracted.GetEdgesForVertex(vertex)[1]; var vertex1 = edge1.Other(vertex); var vertex2 = edge2.Other(vertex); if (graph.GetVoronoiRegionForVertex(vertex1) == voronoi && graph.GetVoronoiRegionForVertex(vertex2) == voronoi) { // Contract the two edges. graphContracted.AddEdge(vertex1, vertex2, edge1.Cost + edge2.Cost); graphContracted.RemoveEdge(edge1); graphContracted.RemoveEdge(edge2); } } var G = new Graph(graph.Terminals); var result = new ReductionResult(); result.ReductionUpperBound = reductionBound; return result; }
/// <summary> /// Runs the Degree 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) { // Use some simple rules to reduce the problem. // The rules are: - if a vertex v has degree 1 and is not part of the required nodes, remove the vertex. // - if a vertex v has degree 1 and is part of the required nodes, the one edge it is // connected to has to be in the solution, and as a consequence, the node at the other side // is either a Steiner node or also required. // - (not implemented yet) if a vertex v is required and has degree 2, and thus is connected to 2 edges, // namely e1 and e2, and cost(e1) < cost(e2) and e1 = (u, v) and u is // also a required vertex, then every solution must contain e1 var result = new ReductionResult(); // Remove leaves as long as there are any var leaves = graph.Vertices.Where(v => graph.GetDegree(v) == 1 && !graph.Terminals.Contains(v)).ToList(); while (leaves.Count > 0) { foreach (var leaf in leaves) graph.RemoveVertex(leaf); result.RemovedVertices.AddRange(leaves); leaves = graph.Vertices.Where(v => graph.GetDegree(v) == 1 && !graph.Terminals.Contains(v)).ToList(); } // When a leaf is required, add the node on the other side of its one edge to required nodes var requiredLeaves = graph.Vertices.Where(v => graph.GetDegree(v) == 1 && graph.Terminals.Contains(v)).ToList(); foreach (var requiredLeaf in requiredLeaves) { // Find the edge this leaf is connected to var alsoRequired = graph.GetEdgesForVertex(requiredLeaf).Single().Other(requiredLeaf); if (!graph.Terminals.Contains(alsoRequired)) graph.RequiredSteinerNodes.Add(alsoRequired); } 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(); int reductionBound = 0; // Given an upper bound for a solution to the Steiner Tree Problem in graphs, // a vertex i can be removed if max{distance(i, k)} > upper bound (with k a terminal). HashSet<Vertex> remove = new HashSet<Vertex>(); Dictionary<Vertex, int> currentMaximums = graph.Vertices.ToDictionary(vertex => vertex, vertex => 0); foreach (var terminal in graph.Terminals) { var toAll = Algorithms.DijkstraToAll(terminal, graph); foreach (var vertex in graph.Vertices) { if (vertex == terminal) continue; if (toAll[vertex] > currentMaximums[vertex]) currentMaximums[vertex] = toAll[vertex]; } } foreach (var vertex in graph.Vertices) { if (currentMaximums[vertex] > upperBound) remove.Add(vertex); else if (currentMaximums[vertex] > reductionBound) reductionBound = currentMaximums[vertex]; } foreach (var vertex in remove) { graph.RemoveVertex(vertex); result.RemovedVertices.Add(vertex); } result.ReductionUpperBound = reductionBound; 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; }
/// <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; }
private void ExecuteFoundReduction(ReductionResult reductionResult) { if (reductionResult.RemovedEdges.Count == 0 && reductionResult.RemovedVertices.Count == 0) return; foreach (var edge in reductionResult.RemovedEdges) _instance.RemoveEdge(edge); foreach (var vertex in reductionResult.RemovedVertices) _instance.RemoveVertex(vertex); ReductionFound?.Invoke(reductionResult.RemovedEdges, reductionResult.RemovedVertices); }