Пример #1
0
        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();
        }
Пример #2
0
        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);
            }
        }
Пример #3
0
        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;
        }
Пример #4
0
        /// <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;
        }
Пример #5
0
        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;
        }
Пример #6
0
        /// <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;
        }
Пример #7
0
        /// <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;
        }
Пример #8
0
 /// <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;
 }
Пример #9
0
        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;
        }