/// <summary> /// constructs a sub-tree /// </summary> /// <param name="graph"></param> /// <param name="visitedEdges"></param> /// <param name="startEdge"></param> /// <returns></returns> private MinimumSpanningTree <T> ConstructSubTree(FeatureGraph <T> graph, HashSet <int> visitedEdges, Edge <T> startEdge) { // Manages the tree being constructed. var tree = new MinimumSpanningTree <T>(); // Manages the list of candidate edges var tempEdges = new UniqueEdgeList <T>(); // Seed of the breadth first search (BFS) tempEdges.AddEdge(startEdge); // Start BFS while (tempEdges.Count > 0) { // Sort the edges based on distace. tempEdges.Sort(); Edge <T> shortestEdge = null; var edgesToRemove = new List <Edge <T> >(); // Find the shortest edge... foreach (var edge in tempEdges.Edges) { var edgeSeen = tree.HasEdgeBeenSeen(edge); var vertexSeen = tree.HasEdgeVerticesBeenSeen(edge); // Make sure that we havent seen this edge. if (edgeSeen) { continue; } if (vertexSeen) { visitedEdges.Add(edge.ID); edgesToRemove.Add(edge); continue; } shortestEdge = edge; tree.AddEdge(shortestEdge); break; } // Remove any edges that have been used up.. edgesToRemove.ForEach(x => tempEdges.RemoveEdge(x)); edgesToRemove.ForEach(x => graph.RemoveEdge(x)); // We didnt find an edge, so we have nothing else to connect... if (shortestEdge == null) { // Make sure that we assert that there are no edges left...should be the case here! System.Diagnostics.Debug.Assert(tempEdges.Count == 0); break; } visitedEdges.Add(shortestEdge.ID); // Removes the shortest edge from the graph... graph.RemoveEdge(shortestEdge); var adjacentEdges = graph.GetAdjacentEdgesFromEdgeVertices(shortestEdge); //adjacentEdges.Sort(); tempEdges.AddEdges(adjacentEdges.Edges); // Remove the shortest edge from the list of available edges left... tempEdges.RemoveEdge(shortestEdge); } return(tree); }
/// <summary> /// Creates clusters based on the MST's linear relationship made via construction. Cutoff is the score (length) per edge /// that is allowed. /// </summary> /// <param name="mst">Minimum Spanning Tree</param> /// <param name="cutoff">Cutoff score</param> /// <returns>List of clusters</returns> private List <U> CreateClusters(MinimumSpanningTree <T> mst, double cutoff) { var clusters = new List <U>(); if (mst.LinearRelationship.Count < 1) { return(clusters); } var currentCluster = new U(); var hashedFeatures = new HashSet <T>(); // Tracks the current feature // These are the features that dont ever get included into a cluster... // This can only happen if the MST building picked a bunch of low-life features that // dont ever construct a graph... var lowLifeFeatures = new List <T>(); for (var i = 0; i < mst.LinearRelationship.Count; i++) { // note this isnt O(n^2), this is just the search for a sub cluster // var currentEdge = mst.LinearRelationship[i]; var vertexA = currentEdge.VertexA; var vertexB = currentEdge.VertexB; var seenA = hashedFeatures.Contains(vertexA); var seenB = hashedFeatures.Contains(vertexB); if (currentEdge.Length < cutoff) { if (!seenA) { hashedFeatures.Add(vertexA); currentCluster.AddChildFeature(vertexA); } if (!seenB) { hashedFeatures.Add(vertexB); currentCluster.AddChildFeature(vertexB); } } else { if (currentCluster.Features.Count > 0) { clusters.Add(currentCluster); } currentCluster = new U(); if (!seenA && !seenB) { // I DONT KNOW WHAT TO DO WITH THESE ASSHOLES! lowLifeFeatures.Add(vertexA); lowLifeFeatures.Add(vertexB); // We dont hash these guys yet, because later we'll see if they hit the market // with their fake DVD's } else if (!seenA) { currentCluster.AddChildFeature(vertexA); hashedFeatures.Add(vertexA); } else { hashedFeatures.Add(vertexB); currentCluster.AddChildFeature(vertexB); } } } // Make sure we add the current cluster if it's not full yet... if (currentCluster.Features.Count > 0) { clusters.Add(currentCluster); } foreach (var lowLife in lowLifeFeatures) { if (!hashedFeatures.Contains(lowLife)) { var cluster = new U(); cluster.AddChildFeature(lowLife); clusters.Add(cluster); } } return(clusters); }