/// <summary> /// Merges the node x into the fixed target node into. /// /// Edges between these nodes, edges to x and related distance information is updated. /// /// x is marked as to be removed from the search space. If x was the start node, into /// will now be the start node. /// </summary> /// <returns>All neighbors of x before merging. These are the nodes that had their adjacency /// information changed.</returns> protected IEnumerable <int> MergeInto(int x, int into) { if (!NodeStates.IsFixedTarget(into)) { throw new ArgumentException("Nodes can only be merged into fixed target nodes", "into"); } _data.DistanceLookup.IndexToNode(into).MergeWith(_data.DistanceLookup.IndexToNode(x), _data.DistanceLookup.GetShortestPath(x, into)); _data.DistanceLookup.MergeInto(x, into); EdgeSet.Remove(x, into); var intoNeighbors = EdgeSet.NeighborsOf(into); var xNeighbors = EdgeSet.NeighborsOf(x); var neighbors = intoNeighbors.Union(xNeighbors); foreach (var neighbor in xNeighbors) { EdgeSet.Remove(x, neighbor); } foreach (var neighbor in neighbors) { EdgeSet.Add(into, neighbor, _data.DistanceLookup[into, neighbor]); } if (StartNodeIndex == x) { _data.StartNodeIndex = into; } NodeStates.MarkNodeAsRemoved(x); return(xNeighbors); }
public override bool DeleteEdge(T v1, T v2) { if (v1 is null) { throw new ArgumentNullException(nameof(v1)); } if (v2 is null) { throw new ArgumentNullException(nameof(v2)); } IPairValue <T> pair_1 = new PairValueI <T>(v1, v2); IPairValue <T> pair_2 = new PairValueI <T>(v2, v1); if (EdgeSet.Contains(pair_1) || EdgeSet.Contains(pair_2)) { EdgeSet.Remove(pair_1); Weights.Remove(pair_1); EdgeSet.Remove(pair_2); Weights.Remove(pair_2); return(true); } return(false); }
public override bool DeleteEdge(TV v1, TV v2) { if (v1 == null || v2 == null) { throw new ArgumentNullException(); } IPairValue <TV> pair = new PairValue <TV>(v1, v2); if (EdgeSet.Contains(pair)) { EdgeSet.Remove(pair); Weigths.Remove(pair); return(true); } return(false); }
public override bool DeleteEdge(T v1Key, T v2Key) { if (v1Key == null || v2Key == null) { throw new ArgumentNullException(); } IPairValue <T> pair = new PairValue <T>(v1Key, v2Key); if (EdgeSet.Contains(pair)) { EdgeSet.Remove(pair); Weights.Remove(pair); return(true); } return(false); }
private void RemoveNode(int index) { if (NodeStates.IsTarget(index)) { throw new ArgumentException("Target nodes can't be removed", "index"); } var neighbors = EdgeSet.NeighborsOf(index); switch (neighbors.Count) { case 0: break; case 1: EdgeSet.Remove(index, neighbors[0]); break; case 2: // Merge the two incident edges. var left = neighbors[0]; var right = neighbors[1]; var newWeight = EdgeSet[index, left].Weight + EdgeSet[index, right].Weight; EdgeSet.Remove(index, left); EdgeSet.Remove(index, right); if (newWeight <= DistanceLookup[left, right]) { EdgeSet.Add(left, right, newWeight); } break; default: throw new ArgumentException("Removing nodes with more than 2 neighbors is not supported", "index"); } NodeStates.MarkNodeAsRemoved(index); }
protected override int ExecuteTest() { var edges = new GraphEdge[SearchSpaceSize]; var removedNodes = 0; for (var i = 0; i < SearchSpaceSize; i++) { // This test only checks non-terminals. if (NodeStates.IsTarget(i)) { continue; } // Nodes with less than 3 neighbors are covered by DegreeTest // Nodes are limited to 7 neighbors because this test is exponential in the neighbor count. var neighbors = EdgeSet.NeighborsOf(i); if (neighbors.Count < 3 || neighbors.Count > 7) { continue; } // Cache the edges. They might be removed from EdgeSet when we need them. foreach (var neighbor in neighbors) { edges[neighbor] = EdgeSet[i, neighbor]; } // Check whether each subset satisfies the condition. var canBeRemoved = true; foreach (var subset in GetAllSubsets(neighbors)) { // Only subsets of at least size 3 are relevant. if (subset.Count < 3) { continue; } // Sum up the weights of all edges between the nodes of the subsets and i. var edgeSum = subset.Sum(j => edges[j].Weight); // Build the MST of the fully connected graph of the nodes in the subset with the bottleneck // Steiner distances as edge weights. var mst = new MinimalSpanningTree(subset, SMatrix); mst.Span(subset[0]); // Sum up the edge weights of the MST. var mstSum = mst.SpanningEdges.Sum(e => e.Priority); // The condition is only satisfied if edgeSum >= mstSum. if (edgeSum < mstSum) { canBeRemoved = false; break; } } if (!canBeRemoved) { continue; } // Remove i and replace its edges. foreach (var neighbor in neighbors) { // Remove the old edges between i and its neighbors. var edge = edges[neighbor]; EdgeSet.Remove(edge); // For each pair of neighbors create a new edge. foreach (var neighbor2 in neighbors) { if (neighbor >= neighbor2) { continue; } // The weight of the new edge between the two neighbors is the sum of their edge weights to i. var edge2 = edges[neighbor2]; var newEdgeWeight = edge.Weight + edge2.Weight; // Only add this edge if it wouldn't be removed by the Paths with many terminals test. if (newEdgeWeight <= SMatrix[neighbor, neighbor2]) { EdgeSet.Add(neighbor, neighbor2, newEdgeWeight); } } } NodeStates.MarkNodeAsRemoved(i); removedNodes++; } return(removedNodes); }