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(); }
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); } }
private static Graph ParseSteinLibBenchmark(string path) { Graph g = null; using (StreamReader sr = new StreamReader(File.Open(path, FileMode.Open))) { string line; int nodes; int edges; while ((line = sr.ReadLine()) != null) { if (line.Equals("SECTION Graph", StringComparison.InvariantCultureIgnoreCase)) { nodes = int.Parse(sr.ReadLine().Split(' ')[1]); edges = int.Parse(sr.ReadLine().Split(' ')[1]); List<Vertex> vertices = new List<Vertex>(); for (int i = 0; i < nodes; i++) vertices.Add(new Vertex(i+1)); g = new Graph(vertices); for (int i = 0; i < edges; i++) { string gline = sr.ReadLine(); if (gline == null || gline.Trim().Length == 0) continue; string[] edgeData = gline.Split(' '); int from = int.Parse(edgeData[1]); int to = int.Parse(edgeData[2]); int cost = int.Parse(edgeData[3]); g.AddEdge(vertices[from-1], vertices[to-1], cost); } } else if (line.Equals("SECTION Terminals", StringComparison.InvariantCultureIgnoreCase)) { int terminals = int.Parse(sr.ReadLine().Split(' ')[1]); for (int i = 0; i < terminals; i++) { int terminalNumber = int.Parse(sr.ReadLine().Split(' ')[1]); var t = g.Vertices.Single(x => x.VertexName == terminalNumber); g.Terminals.Add(t); } } } } return g; }
/// <summary> /// Creates a distance graph for this graph. /// Subtle note: the terminals used for this graph are the terminals for the problem, /// and the nodes that are considered required Steiner nodes. /// </summary> /// <returns></returns> private Graph CreateTerminalDistanceGraph() { var terminals = this.Required.ToList(); var n = terminals.Count; var edgesCalculated = 0; var edgesToCalculate = (n * (n - 1)) / 2; int beforeUpdate = (edgesToCalculate / 200) + 1; Graph distanceGraph = new Graph(terminals); for (int from = 0; from < n; from++) { var vFrom = terminals[from]; var distanceToAll = Algorithms.DijkstraToAll(vFrom, this); foreach (var dist in distanceToAll) { var vTo = dist.Key; if (vTo.VertexName > vFrom.VertexName || !terminals.Contains(vTo)) continue; distanceGraph.AddEdge(vFrom, vTo, dist.Value); edgesCalculated++; } } return distanceGraph; }
private static Graph ParseORBenchmark(string path) { Graph g; using (StreamReader sr = new StreamReader(File.Open(path, FileMode.Open))) { // Read the number of edges and vertices string metadata = sr.ReadLine().RemoveWhitespace(); int nbEdges = int.Parse(metadata.Split(' ')[1]); int nbVertices = int.Parse(metadata.Split(' ')[0]); g = new Graph(nbVertices); // Read all edges and add them to the graph for (int i = 0; i < nbEdges; i++) { string rawline = sr.ReadLine().RemoveWhitespace(); int start = int.Parse(rawline.Split(' ')[0]); int end = int.Parse(rawline.Split(' ')[1]); int cost = int.Parse(rawline.Split(' ')[2]); g.AddEdge(g.Vertices.Single(x => x.VertexName == start), g.Vertices.Single(x => x.VertexName == end), cost); } // Read the Steiner nodes and save them int numberOfRequiredNodes = int.Parse(sr.ReadLine().RemoveWhitespace()); IEnumerable<Vertex> requiredNodes = sr.ReadLine().RemoveWhitespace().Split(' ').Where(x => x.Length > 0).Select(x => g.Vertices.Single(v => v.VertexName == int.Parse(x))); g.Terminals.AddRange(requiredNodes); } return g; }
/// <summary> /// Method to create and return the distance graph of this graph. /// </summary> /// <returns>The distance graph of the current instance of the graph.</returns> public Graph CreateDistanceGraph() { var n = this.NumberOfVertices; Graph distanceGraph = new Graph(Vertices); for (int from = 0; from < n; from++) { var vFrom = Vertices[from]; var distanceToAll = Algorithms.DijkstraToAll(vFrom, this); foreach (var dist in distanceToAll) { var vTo = dist.Key; if (vTo.VertexName > vFrom.VertexName) continue; distanceGraph.AddEdge(vFrom, vTo, dist.Value); } } return distanceGraph; }
/// <summary> /// Creates an exact copy of this graph. /// </summary> /// <returns></returns> public Graph Clone() { Graph clone = new Graph(Vertices); foreach (var edge in GetAllEdges()) clone.AddEdge(edge); foreach (var terminal in Terminals) clone.Terminals.Add(terminal); foreach (var requiredSteinerNode in RequiredSteinerNodes) clone.RequiredSteinerNodes.Add(requiredSteinerNode); clone._terminalDistance = _terminalDistance; return clone; }
/// <summary> /// Method to create and return a complete graph (like a distance graph), but /// each edge has cost int.MaxValue. Those costs are later changed to be the /// special distances between vertices. /// </summary> /// <param name="graph">The graph to calculate the initial special distance graph for.</param> /// <returns>The initial special distance graph, containing all int.MaxValue special distances.</returns> private static Graph CreateInitialSpecialDistanceGraph(Graph graph) { var n = graph.NumberOfVertices; Graph specialGraph = new Graph(graph.Vertices); for (int from = 0; from < n; from++) { for (int to = from + 1; to < n; to++) { var vFrom = graph.Vertices[from]; var vTo = graph.Vertices[to]; specialGraph.AddEdge(vFrom, vTo, int.MaxValue); } } return specialGraph; }
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; }