public void DoClusters(out CostMatrix CostMatrix, out List<CityNodeData> CityData, out List<CityCluster> CityClusters, out Dictionary<int, CityCluster> CityToClusterItsIn, out Dictionary<int, int> SizeClusterToNumberOfThatSize) { CostMatrix = new CostMatrix(Cities); _costMatrix = CostMatrix; Stopwatch clusterWatch = new Stopwatch(); clusterWatch.Start(); CityData = new List<CityNodeData>(); _cityNodes = CityData; for (int i = 0; i < CostMatrix.Size; i++) { CityData.Add(new CityNodeData(i, CostMatrix, Cities)); } //Clustering double threshold = CostMatrix.DistanceRange * _clusterPercent; _threshold = (float)threshold; List<CityNodeData> citiesSortedByNumberUnderThreshold = new List<CityNodeData>(CityData); citiesSortedByNumberUnderThreshold.Sort((a, b) => (a.AverageWorstDistanceOfBelowThreshold(threshold).CompareTo( b.AverageWorstDistanceOfBelowThreshold(threshold)))); List<List<CityNodeData>> finalClusters = new List<List<CityNodeData>>(); List<CityNodeData> visited = new List<CityNodeData>(CityData); Dictionary<CityNodeData, int> clusterAssignment = new Dictionary<CityNodeData, int>(); foreach (CityNodeData c in visited) { clusterAssignment.Add(c, -1); } while (citiesSortedByNumberUnderThreshold.Count > 0) { List<CityNodeData> curCluster = new List<CityNodeData>(); CityNodeData cur = citiesSortedByNumberUnderThreshold[0]; clusterAssignment[cur] = finalClusters.Count; citiesSortedByNumberUnderThreshold.RemoveAt(0); visited.Remove(cur); curCluster.Add(cur); for (int i = 0; i < cur.SortedWorstDistance.Count; i++) { bool canAdd = true; CityNodeData curCloseCheck = CityData[cur.SortedWorstDistance[i].CityId]; if (!visited.Contains(curCloseCheck)) { continue; } foreach (CityNodeData inCluster in curCluster) { double worstDistance = CostMatrix.WorstDistanceBetween(inCluster.CityId, curCloseCheck.CityId); if (worstDistance > threshold) { canAdd = false; break; } } if (canAdd) { curCluster.Add(curCloseCheck); visited.Remove(curCloseCheck); citiesSortedByNumberUnderThreshold.Remove(curCloseCheck); } } finalClusters.Add(curCluster); } clusterWatch.Stop(); Console.WriteLine("SAVED: " + (CostMatrix.Size - finalClusters.Count)); _storedClusters = finalClusters; CityClusters = new List<CityCluster>(); CityToClusterItsIn = new Dictionary<int, CityCluster>(); SizeClusterToNumberOfThatSize = new Dictionary<int, int>(); foreach (List<CityNodeData> clust in finalClusters) { CityCluster actualCluster = new CityCluster(clust, CityData, CostMatrix); CityClusters.Add(actualCluster); foreach (int city in actualCluster.ContainedCityIds) { CityToClusterItsIn.Add(city, actualCluster); } if (!SizeClusterToNumberOfThatSize.ContainsKey(clust.Count)) { SizeClusterToNumberOfThatSize.Add(clust.Count, 0); } SizeClusterToNumberOfThatSize[clust.Count] = SizeClusterToNumberOfThatSize[clust.Count] + 1; } }
public static int ShortedValidEdgeBetweenClusters(CityCluster from, CityCluster to) { foreach (int edgeId in from._outgoingEdgesSortedByDistance) { KeyValuePair<int, int> coords = from._costMatrix.EdgeCoords(edgeId); if (from._cityEntryPoint != coords.Key || from._containedCities.Count == 1) { //If valid to leave from here if (to.ContainedCityIds.Contains(coords.Value)) { //If target has this city if (to._cityExitPoint != coords.Value || to._containedCities.Count == 1) { //If target city is valid from.OutgoingOnEdge(edgeId); to.IncomingFromEdge(edgeId); return edgeId; } } } } return -1; }