public IList <Cluster <TNode, double> > Solve([NotNull] IList <TNode> Nodes, [NotNull] CostAnalyzer <double> costanalyzer, double maxCostOfNearestNeighbor, int maxNodesPerCluster = -1) { var clusterFactory = new ClusterFactory(Nodes, costanalyzer); var transposedCostMatrix = CostMatrix <double> .CreateTransposed(costanalyzer.CostMatrix); var transposedCostanalyzer = new CostAnalyzer <double>(transposedCostMatrix); // While unhandled indexes available and the loop runs for at most a certain amount of times, continue the algorithm for (var counter = 0; counter < Nodes.Count * maxFactorOfLoopCount && clusterFactory.NodesAsIndexes.Count > 0; counter++) { // set the current pointer to a random node index among the nodes not yet classified in a cluster int currentPointer = clusterFactory.NodesAsIndexes[randomizer.Next(0, clusterFactory.NodesAsIndexes.Count - 1)]; var candidateCluster = CalculateCluster(clusterFactory.NodesAsIndexes, costanalyzer, transposedCostanalyzer, maxCostOfNearestNeighbor, maxNodesPerCluster); if (candidateCluster.Count > 1) { // loop over the cluster again maybe to cut the cluster in pieces. Clusters with one item are thrown back in the pool for (int indexInCluster = 0; indexInCluster < candidateCluster.Count - 1; indexInCluster++) { var maxCostInCluster = indexInCluster == 0 ? costanalyzer.AllNeighborsOrdered(candidateCluster[0])[candidateCluster[1]] : candidateCluster.Take(indexInCluster + 1).Tuples().Max(t => costanalyzer.AllNeighborsOrdered(t.Item1)[t.Item2]); var nodesOutsideClusterQuiteCloseToCluster = costanalyzer.AllNeighborsOrdered(candidateCluster[indexInCluster]) .Where(neighbor => !candidateCluster.Contains(neighbor.Key) && neighbor.Value <= maxCostInCluster); if (nodesOutsideClusterQuiteCloseToCluster.Count() > 1) // Split the cluster { var firstPart = candidateCluster.GetRange(0, indexInCluster + 1); clusterFactory.CreateCluster(firstPart); candidateCluster.RemoveRange(0, indexInCluster + 1); indexInCluster = -1; } } } clusterFactory.CreateCluster(candidateCluster); } // Here we add the singleton clusters from the remaining nodes clusterFactory.CreateSingletonClusters(); return(clusterFactory.ListOfClusters); }
public void CreateCluster(IList <int> clusterNodes) { if (clusterNodes.Count > 1) // don't add singleton clusters here { double costOfCluster = clusterNodes.Tuples().Sum(t => costanalyzer.AllNeighborsOrdered(t.Item1)[t.Item2]); double reverseCost = clusterNodes.Reverse().Tuples().Sum(n => costanalyzer.AllNeighborsOrdered(n.Item1)[n.Item2]); foreach (var j in clusterNodes) { NodesAsIndexes.Remove(j); // accepted as final member of the cluster } ListOfClusters.Add(new Cluster <TNode, double>(clusterNodes.Select(n => allNodes[n]), costOfCluster, reverseCost)); } }
private static void ExpandClusterFromStartPoint(int startIndex, List <int> constructingCluster, bool atTail, IList <int> nodesAsIndexes, CostAnalyzer <double> costanalyzer, double maxCostOfNearestNeighbor, int maxNodesPerCluster) { int currentPointer = startIndex; bool foundNextNodeInChain; if (maxNodesPerCluster < 0 || constructingCluster.Count < maxNodesPerCluster - 1) { do { foundNextNodeInChain = false; var myNeighborsNotAlreadyInConstructingCluster = costanalyzer.AllNeighborsOrdered(currentPointer).Where(neighbor => currentPointer != neighbor.Key && !constructingCluster.Contains(neighbor.Key)); if (myNeighborsNotAlreadyInConstructingCluster.Any()) { var nearestNeighbor = myNeighborsNotAlreadyInConstructingCluster.FirstOrDefault(); // The closest neighbor if (nearestNeighbor.Value <= maxCostOfNearestNeighbor && nodesAsIndexes.Contains(nearestNeighbor.Key)) // No overlapping with other clusters. We stop if the next one is in another cluster. { if (constructingCluster.Count == 0) { constructingCluster.Add(currentPointer); // If we start construct a cluster don't forget to add the beginning node. } if (atTail) { constructingCluster.Add(nearestNeighbor.Key); } else { constructingCluster.Insert(0, nearestNeighbor.Key); } currentPointer = nearestNeighbor.Key; // Move the pointer to the neighbor foundNextNodeInChain = true; } } }while (foundNextNodeInChain && (maxNodesPerCluster < 0 || constructingCluster.Count < maxNodesPerCluster)); } }