public static Graph RunSolver(Graph graph, Graph tmst) { HashSet<Edge> redundantEdges = new HashSet<Edge>(graph.Edges); foreach (var mstEdge in tmst.Edges) { var v1 = mstEdge.Either(); var v2 = mstEdge.Other(v1); var path = Algorithms.DijkstraPath(v1, v2, graph); foreach (var edge in path.Edges.Where(edge => redundantEdges.Contains(edge))) redundantEdges.Remove(edge); } var solutionEdge = graph.Clone(); foreach (var edge in redundantEdges) solutionEdge.RemoveEdge(edge); // Break cycles in the graph! // Solution: Take MST // Observation: mostly there are none solutionEdge = Algorithms.Kruskal(solutionEdge); var TMSTEremoveVertices = new HashSet<Vertex>(); foreach (var vertex in solutionEdge.Vertices) { if (solutionEdge.GetDegree(vertex) == 1 && !graph.Terminals.Contains(vertex)) TMSTEremoveVertices.Add(vertex); } foreach (var vertex in TMSTEremoveVertices) solutionEdge.RemoveVertex(vertex); return solutionEdge; }
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 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; }
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); } } } }
public static Graph RunTest(Graph graph) { var enumerator = AllTriangles(graph); Console.WriteLine("There are {0} triangles in this graph.", enumerator.Count()); return graph; }
public static Graph RunSolver(Graph graph, Graph tmst) { HashSet<Vertex> redundantVertices = new HashSet<Vertex>(graph.Vertices); foreach (var mstEdge in tmst.Edges) { var v1 = mstEdge.Either(); var v2 = mstEdge.Other(v1); var path = Algorithms.DijkstraPath(v1, v2, graph); foreach (var vertex in path.Vertices.Where(vertex => redundantVertices.Contains(vertex))) redundantVertices.Remove(vertex); } var solutionVertex = graph.Clone(); foreach (var vertex in redundantVertices) { solutionVertex.RemoveVertex(vertex); } solutionVertex = Algorithms.Kruskal(solutionVertex); var TMSTVremoveVertices = new HashSet<Vertex>(); foreach (var vertex in solutionVertex.Vertices) { if (solutionVertex.GetDegree(vertex) == 1 && !graph.Terminals.Contains(vertex)) TMSTVremoveVertices.Add(vertex); } foreach (var vertex in TMSTVremoveVertices) solutionVertex.RemoveVertex(vertex); return solutionVertex; }
public static IEnumerable<IEnumerable<Vertex>> BFS2(Graph graph, List<Vertex> visited) { List<Vertex> nodes = graph.GetNeighboursForVertex(visited.Last()); var visitedHash = new HashSet<Vertex>(visited); foreach (var node in nodes) { if (visitedHash.Contains(node)) continue; //if (node == end) { visited.Add(node); yield return visited; visited.RemoveAt(visited.Count - 1); //break; } } foreach (var node in nodes) { if (visitedHash.Contains(node)) continue; visited.Add(node); foreach (var bfs in BFS2(graph, visited)) yield return bfs; visited.RemoveAt(visited.Count - 1); } }
public Reducer(Graph instance) { _instance = instance.Clone(); _solutionUpperBound = Int32.MaxValue; _reductionUpperBound = 0; _running = false; Status = "Not running."; }
public Solver(Graph instance) { _instance = instance.Clone(); _running = false; _bls = new BLS(); _edgesToRemove = new ConcurrentQueue<Edge>(); _verticesToRemove = new ConcurrentQueue<Vertex>(); }
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; }
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 Graph RemoveVertexAndReconnect(Graph currentSolution, Graph problemInstance, Vertex remove) { var workingSolution = currentSolution.Clone(); foreach (var vertex in problemInstance.Vertices) if (!workingSolution.ContainsVertex(vertex)) workingSolution.AddVertex(vertex); foreach (var edge in workingSolution.GetEdgesForVertex(remove).ToList()) workingSolution.RemoveEdge(edge); IEnumerable<Vertex> degreeOne; while ((degreeOne = workingSolution.Vertices.Except(problemInstance.Terminals) .Where(x => workingSolution.GetDegree(x) == 1)).Any()) { foreach (var degreeZeroSteiner in degreeOne.ToList()) foreach (var edge in workingSolution.GetEdgesForVertex(degreeZeroSteiner).ToList()) workingSolution.RemoveEdge(edge, false); } ReconnectTerminals(workingSolution, problemInstance); return workingSolution; }
/// <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> /// 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; }
/// <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 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> /// 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; }
/// <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; }
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; }
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> /// Method to remove a vertex from this graph. /// Also removes all the edges that this vertex was connected to. /// </summary> /// <param name="vertex">The vertex to remove.</param> public void RemoveVertex(Vertex vertex) { if (!_vertices.Contains(vertex)) return; _vertices.Remove(vertex); Vertices.Remove(vertex); foreach (var edge in _adjacencies[vertex].ToList()) RemoveEdge(edge); _terminalDistance = null; _adjacencies.Remove(vertex); }
/// <summary> /// Method to remove an edge from the graph. /// </summary> /// <param name="edge">The edge to be removed.</param> /// <param name="removeDegreeZero">Indicates whether when a vertex becomes of degree zero, it should be removed. Default: True.</param> public void RemoveEdge(Edge edge, bool removeDegreeZero = true) { var v1 = edge.Either(); var v2 = edge.Other(v1); _adjacencies[v1].Remove(edge); _adjacencies[v2].Remove(edge); if (removeDegreeZero) { if (GetDegree(v1) == 0) RemoveVertex(v1); if (GetDegree(v2) == 0) RemoveVertex(v2); } _edgesUpToDate = false; _terminalDistance = null; _voronoiRegions.Clear(); }
public void AddEdge(Edge edge) { var from = edge.Either(); var to = edge.Other(from); if (!_adjacencies.ContainsKey(from) || !_adjacencies.ContainsKey(to)) throw new ArgumentException("This edge can not be added as it connects vertices that are not in the graph."); _adjacencies[from].Add(edge); _adjacencies[to].Add(edge); _edgesUpToDate = false; _terminalDistance = null; }
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; }
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> /// 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; }
public void AddVertex(Vertex vertex) { if (_vertices.Contains(vertex)) return; Vertices.Add(vertex); _vertices.Add(vertex); _adjacencies.Add(vertex, new List<Edge>()); _terminalDistance = null; }