private static IEnumerable<List<Edge>> AllTriangles(Graph graph) { List<Vertex> vertices = new List<Vertex>(graph.Vertices); vertices.Sort((x, y) => graph.GetDegree(x).CompareTo(graph.GetDegree(y))); vertices.Reverse(); // From highest to lowest Dictionary<Vertex, int> index = new Dictionary<Vertex, int>(); Dictionary<Vertex, List<Vertex>> A = new Dictionary<Vertex, List<Vertex>>(); for (int i = 0; i < vertices.Count; i++) { index.Add(vertices[i], i); A.Add(graph.Vertices[i], new List<Vertex>()); } foreach (var firstVertex in vertices) { foreach (var firstEdge in graph.GetEdgesForVertex(firstVertex)) { var secondVertex = firstEdge.Other(firstVertex); if (index[firstVertex] < index[secondVertex]) { foreach (var thirdVertex in A[firstVertex].Intersect(A[secondVertex])) { var secondEdge = graph.GetEdgesForVertex(firstVertex).Single(x => x.Other(firstVertex) == thirdVertex); var thirdEdge = graph.GetEdgesForVertex(secondVertex).Single(x => x.Other(secondVertex) == thirdVertex); yield return new List<Edge>(new [] { firstEdge, secondEdge, thirdEdge }); } A[secondVertex].Add(firstVertex); } } } }
/// <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 int Dijkstra(Vertex from, Vertex to, Graph graph) { HashSet<Vertex> visited = new HashSet<Vertex>(); Dictionary<Vertex, FibonacciHeap<int, Vertex>.Node> nodes = new Dictionary<Vertex, FibonacciHeap<int, Vertex>.Node>(); FibonacciHeap<int, Vertex> labels = new FibonacciHeap<int, Vertex>(); // Initialize labels. foreach (var vertex in graph.Vertices) { var n = labels.Add(vertex == from ? 0 : int.MaxValue, vertex); nodes.Add(vertex, n); } int currentLabel = int.MaxValue; while (!visited.Contains(to)) { var currentNode = labels.ExtractMin(); var current = currentNode.Value; currentLabel = currentNode.Key; // 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); } visited.Add(current); } return currentLabel; }
public static Path DijkstraPath(Vertex from, Vertex to, Graph graph) { HashSet<Vertex> visited = new HashSet<Vertex>(); Dictionary<Vertex, FibonacciHeap<int, Vertex>.Node> nodes = new Dictionary<Vertex, FibonacciHeap<int, Vertex>.Node>(); Dictionary<Vertex, Edge> comingFrom = new Dictionary<Vertex, Edge>(); FibonacciHeap<int, Vertex> labels = new FibonacciHeap<int, Vertex>(); // Initialize labels. foreach (var vertex in graph.Vertices) { var n = labels.Add(vertex == from ? 0 : int.MaxValue, vertex); nodes.Add(vertex, n); comingFrom.Add(vertex, null); } while (!visited.Contains(to)) { var currentNode = labels.ExtractMin(); var current = currentNode.Value; // 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); } // Now travel back, to find the actual path List<Edge> pathEdges = new List<Edge>(); Vertex pathVertex = to; while (pathVertex != from) { pathEdges.Add(comingFrom[pathVertex]); pathVertex = comingFrom[pathVertex].Other(pathVertex); } pathEdges.Reverse(); Path path = new Path(from); path.Edges.AddRange(pathEdges); return path; }
private void ReconnectTerminals(Graph workingSolution, Graph problemInstance, Graph problemInstanceDistance) { Stopwatch reconnectStopwatch = new Stopwatch(); reconnectStopwatch.Start(); var components = workingSolution.CreateComponentTable(); var componentsToConnect = components.Where(x => problemInstance.Terminals.Contains(x.Key)) .Select(x => x.Value) .Distinct() .ToList(); if (componentsToConnect.Count <= 1) return; MultiDictionary<int, Tuple<Vertex, Vertex>> componentConnectingPathDictionary = new MultiDictionary<int, Tuple<Vertex, Vertex>>(); List<Vertex> componentGraphVertices = new List<Vertex>(); foreach (var i in componentsToConnect) componentGraphVertices.Add(new Vertex(i)); Graph componentGraph = new Graph(componentGraphVertices); for (int i = 0; i < componentsToConnect.Count; i++) { int fromComponent = componentsToConnect[i]; for (int j = i + 1; j < componentsToConnect.Count; j++) { int toComponent = componentsToConnect[j]; int minDistance = int.MaxValue; foreach (var fromVertex in components.Where(x => x.Value == fromComponent) .Select(x => x.Key)) { var distanceEdges = problemInstanceDistance.GetEdgesForVertex(fromVertex); foreach (var toVertexEdge in distanceEdges) { var toVertex = toVertexEdge.Other(fromVertex); if (components[toVertex] != toComponent) continue; int distance = toVertexEdge.Cost; if (!componentConnectingPathDictionary.ContainsKey(fromComponent, toComponent)) { componentConnectingPathDictionary.Add(fromComponent, toComponent, new Tuple<Vertex, Vertex>(fromVertex, toVertex)); componentGraph.AddEdge(new Edge(componentGraphVertices[i], componentGraphVertices[j], minDistance)); } if (distance < minDistance) { minDistance = distance; componentConnectingPathDictionary[fromComponent, toComponent] = new Tuple<Vertex, Vertex>(fromVertex, toVertex); componentGraph.GetEdgesForVertex(componentGraphVertices[i]) .Single(x => x.Other(componentGraphVertices[i]) == componentGraphVertices[j]) .Cost = minDistance; } } } } } componentGraph = Algorithms.Kruskal(componentGraph); foreach (var edge in componentGraph.Edges) { var v1 = edge.Either(); var v2 = edge.Other(v1); var vertices = componentConnectingPathDictionary[v1.VertexName, v2.VertexName]; var path = Algorithms.DijkstraPath(vertices.Item1, vertices.Item2, problemInstance); foreach (var pathEdge in path.Edges) workingSolution.AddEdge(pathEdge); } reconnectStopwatch.Stop(); }
/// <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 Dictionary<Vertex, Path> DijkstraPathToAll(Vertex from, Graph graph, bool onlyTerminals) { Dictionary<Vertex, Edge> comingFrom = new Dictionary<Vertex, Edge>(); HashSet<Vertex> visited = new HashSet<Vertex>(); Dictionary<Vertex, FibonacciHeap<int, Vertex>.Node> nodes = new Dictionary<Vertex, FibonacciHeap<int, Vertex>.Node>(); Dictionary<Vertex, Path> paths = new Dictionary<Vertex, Path>(); FibonacciHeap<int, Vertex> labels = new FibonacciHeap<int, Vertex>(); // Initialize labels. foreach (var vertex in graph.Vertices) { var n = labels.Add(vertex == from ? 0 : int.MaxValue, vertex); nodes.Add(vertex, n); } while (paths.Count < (onlyTerminals ? graph.Terminals.Count - 1 : graph.NumberOfVertices - 1)) { var currentNode = labels.ExtractMin(); var current = currentNode.Value; // 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 != from && (!onlyTerminals || graph.Terminals.Contains(current))) { // Travel back the path List<Edge> pathEdges = new List<Edge>(); Vertex pathVertex = current; while (pathVertex != from) { pathEdges.Add(comingFrom[pathVertex]); pathVertex = comingFrom[pathVertex].Other(pathVertex); } pathEdges.Reverse(); Path path = new Path(from); path.Edges.AddRange(pathEdges); paths[current] = path; } } return paths; }
private static bool ExistsPath(Vertex v1, Vertex v2, Graph graph, List<Vertex> visited) { foreach (var edge in graph.GetEdgesForVertex(v1)) { if (edge.Other(v1) == v2) { return true; } if (!visited.Contains(edge.Other(v1))) { var visited2 = visited.ToList(); visited2.Add(v1); if (ExistsPath(edge.Other(v1), v2, graph, visited2)) return true; } } return false; }
public static List<Path> NearestTerminals(Vertex from, Graph graph, int n) { List<Path> foundPaths = new List<Path>(); HashSet<Vertex> visited = new HashSet<Vertex>(); Dictionary<Vertex, FibonacciHeap<int, Vertex>.Node> nodes = new Dictionary<Vertex, FibonacciHeap<int, Vertex>.Node>(); FibonacciHeap<int, Vertex> labels = new FibonacciHeap<int, Vertex>(); Dictionary<Vertex, Edge> comingFrom = new Dictionary<Vertex, Edge>(); if (graph.Terminals.Contains(from)) foundPaths.Add(new Path(from)); // Initialize labels. foreach (var vertex in graph.Vertices) { var node = labels.Add(vertex == from ? 0 : int.MaxValue, vertex); nodes.Add(vertex, node); comingFrom.Add(vertex, null); } while (!labels.IsEmpty() && foundPaths.Count < n) { var currentNode = labels.ExtractMin(); var current = currentNode.Value; // 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 (graph.Terminals.Contains(current) && current != from) { // Now travel back, to find the actual path List<Edge> pathEdges = new List<Edge>(); Vertex pathVertex = current; while (pathVertex != from) { pathEdges.Add(comingFrom[pathVertex]); pathVertex = comingFrom[pathVertex].Other(pathVertex); } pathEdges.Reverse(); Path path = new Path(from); path.Edges.AddRange(pathEdges); foundPaths.Add(path); } } return foundPaths; }
private static Dictionary<int, double> CalculateComponentFunctionValues(Graph graph, Dictionary<Vertex, int> components) { Dictionary<int, double> fValues = new Dictionary<int, double>(); foreach (var componentNumber in components.Values.Distinct()) { //Get all edges in this component HashSet<Edge> edgesInComponent = new HashSet<Edge>(); var verticesInComponent = components.Where(x => x.Value == componentNumber).Select(x => x.Key); var nrOfTerminals = verticesInComponent.Count(x => graph.Terminals.Contains(x)); foreach (var v in verticesInComponent) { foreach (var e in graph.GetEdgesForVertex(v)) edgesInComponent.Add(e); } if (edgesInComponent.Count > 0) { double fVal = edgesInComponent.Sum(x => x.Cost)/Math.Pow(nrOfTerminals, 2); fValues.Add(componentNumber, fVal); } else fValues.Add(componentNumber, double.MaxValue); } return fValues; }
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; }