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); }
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); }