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