예제 #1
0
        protected override int ExecuteTest()
        {
            if (NodeStates.FixedTargetNodeCount <= 1 || NodeStates.VariableTargetNodeCount > 0)
            {
                return(0);
            }

            var removedNodes = 0;

            var mst = new MinimalSpanningTree(NodeStates.FixedTargetNodeIndices.ToList(), DistanceLookup);

            mst.Span(StartNodeIndex);
            var maxEdgeDistance = mst.SpanningEdges.Max(e => e.Priority);

            for (var i = 0; i < SearchSpaceSize; i++)
            {
                if (NodeStates.IsTarget(i) || NodeStates.IsRemoved(i))
                {
                    continue;
                }

                // Theoretically, this can be sped up by using Voronoi partitions. The Voronoi base of i is the
                // terminal with the smallest distance to i by definition, so only the distance to that terminal
                // has to be checked.
                if (NodeStates.FixedTargetNodeIndices.All(t => DistanceLookup[i, t] >= maxEdgeDistance))
                {
                    EdgeSet.EdgesOf(i).ForEach(EdgeSet.Remove);
                    NodeStates.MarkNodeAsRemoved(i);
                    removedNodes++;
                }
            }

            return(removedNodes);
        }
예제 #2
0
        protected override int ExecuteTest()
        {
            // The test only makes sense with at least 2 terminals.
            if (NodeStates.FixedTargetNodeCount <= 1)
            {
                return(0);
            }

            var removedNodes = 0;
            var untested     = new HashSet <int>(NodeStates.FixedTargetNodeIndices);

            // For each terminal z with degree of at least 2
            while (untested.Any())
            {
                var z = untested.First();
                untested.Remove(z);

                var neighbors = EdgeSet.NeighborsOf(z);
                if (neighbors.Count < 2)
                {
                    continue;
                }

                // Determine the shortest and second shortest edge incident to z.
                // For the second shortest, only the weight is of interest.
                var tuple                = ShortestTwoEdgesOf(EdgeSet.EdgesOf(z));
                var shortest             = tuple.Item1;
                var secondShortestWeight = tuple.Item2;
                // v is the node which is connected to z via the shortest edge.
                var v = shortest.N1 == z ? shortest.N2 : shortest.N1;

                // The shortest edge belongs to at least one Steiner minimal tree, if
                // secondShortestWeight >= shortest.Weight + distance(v, y) for any terminal y, y != z
                var canBeContracted = NodeStates.FixedTargetNodeIndices
                                      .Where(y => z != y)
                                      .Any(y => secondShortestWeight >= shortest.Weight + DistanceLookup[v, y]);
                // If such a y exists, we can merge v into z.
                if (canBeContracted)
                {
                    // z was changed and can be tested again.
                    untested.Add(z);
                    // v no longer exists and as such must not be tested.
                    untested.Remove(v);
                    MergeInto(v, z);
                    removedNodes++;
                }
            }
            return(removedNodes);
        }