public List <List <TLayout> > GetClusters(List <TLayout> layouts, GetDistanceDelegate <TLayout> getDistance, double stopDistance) { var layoutToIntMapping = layouts.CreateIntMapping(); var layoutDistanceMatrix = GetLayoutDistanceMatrix(layoutToIntMapping, getDistance); var clusters = GetInitialClusters(layoutToIntMapping); var clusterDistanceMatrix = layoutDistanceMatrix.Select(x => x.ToArray()).ToArray(); // Copy layoutDistanceMatrix array // Compute clusters while (clusters.Count > 10) { var minDistance = double.MaxValue; var minCluster1 = -1; var minCluster2 = -1; foreach (var cluster1 in clusters.Keys) { foreach (var cluster2 in clusters.Keys) { if (cluster1 != cluster2) { var distance = clusterDistanceMatrix[cluster1][cluster2]; if (distance < minDistance) { minDistance = distance; minCluster1 = cluster1; minCluster2 = cluster2; } } } } if (minDistance > stopDistance) { break; } MergeClusters(minCluster1, minCluster2, clusters, clusterDistanceMatrix, layoutDistanceMatrix); } // Prepare output var output = clusters .Values .OrderByDescending(x => x.Count) .Select(x => x.Select(y => layoutToIntMapping.GetByValue(y)).ToList()) .ToList(); return(output); }
private double[][] GetLayoutDistanceMatrix(TwoWayDictionary <TLayout, int> layouts, GetDistanceDelegate <TLayout> getDistance) { var distanceMatrix = new double[layouts.Count][]; for (int i = 0; i < layouts.Count; i++) { distanceMatrix[i] = new double[layouts.Count]; } for (int i = 0; i < layouts.Count - 1; i++) { for (int j = i + 1; j < layouts.Count; j++) { var distance = getDistance(layouts.GetByValue(i), layouts.GetByValue(j)); distanceMatrix[i][j] = distance; distanceMatrix[j][i] = distance; } } return(distanceMatrix); }
protected override void CalculateDistancesFromAPlayer(GameState gameState, PlayerType player, HashSet <CellState> reachableCells) { int nextDistance = 0; int numberOfCellsReachable = 0; int totalDegreesOfCellsReachable = 0; HashSet <CellState> cellsToExpand = new HashSet <CellState>(); DijkstraStatus dijkstraStatus = DijkstraStatus.NotCalculated; bool isPartiallyCalculated = false; int upToDateDijkstraDistance = 0; CellState playersCell; CompartmentStatus compartmentStatus; GetDistanceDelegate getDistance = null; SetDistanceDelegate setDistance = null; switch (player) { case PlayerType.You: compartmentStatus = CompartmentStatus.InYourCompartment; getDistance = GetDistanceFromYou; setDistance = SetDistanceFromYou; dijkstraStatus = gameState.YourDijkstraStatus; upToDateDijkstraDistance = gameState.YourUpToDateDijkstraDistance; playersCell = gameState.YourCell; break; case PlayerType.Opponent: compartmentStatus = CompartmentStatus.InOpponentsCompartment; getDistance = GetDistanceFromOpponent; setDistance = SetDistanceFromOpponent; dijkstraStatus = gameState.OpponentsDijkstraStatus; upToDateDijkstraDistance = gameState.OpponentsUpToDateDijkstraDistance; playersCell = gameState.OpponentsCell; break; default: throw new ApplicationException("The player must be specified when calculating distances"); } if (dijkstraStatus != DijkstraStatus.FullyCalculated) { if (player == PlayerType.You) { gameState.OpponentIsInSameCompartment = false; } isPartiallyCalculated = (dijkstraStatus == DijkstraStatus.PartiallyCalculated && upToDateDijkstraDistance > 0); if (isPartiallyCalculated) { nextDistance = upToDateDijkstraDistance; foreach (CellState cellState in gameState.GetAllCellStates()) { int distance = getDistance(cellState); if ((cellState.OccupationStatus == OccupationStatus.Clear) && (cellState.CompartmentStatus == compartmentStatus || cellState.CompartmentStatus == CompartmentStatus.InSharedCompartment) && (distance <= upToDateDijkstraDistance)) { if (reachableCells != null) { reachableCells.Add(cellState); } numberOfCellsReachable++; totalDegreesOfCellsReachable += cellState.DegreeOfVertex; if (distance == upToDateDijkstraDistance) { cellsToExpand.Add(cellState); } } else { cellState.ClearDijkstraStateForPlayer(player); } } } else { gameState.ClearDijkstraPropertiesForPlayer(player); cellsToExpand.Add(playersCell); } while (cellsToExpand.Any()) { nextDistance++; HashSet <CellState> nextLevelOfCells = new HashSet <CellState>(); foreach (CellState sourceCell in cellsToExpand) { CellState[] adjacentCells = sourceCell.GetAdjacentCellStates(); foreach (CellState adjacentCell in adjacentCells) { switch (adjacentCell.OccupationStatus) { case OccupationStatus.Opponent: if (player == PlayerType.You) { gameState.OpponentIsInSameCompartment = true; } break; case OccupationStatus.Clear: adjacentCell.CompartmentStatus |= compartmentStatus; int existingDistance = getDistance(adjacentCell); if (nextDistance < existingDistance) { setDistance(adjacentCell, nextDistance); // HashSets automatically filter out duplicates, so no need to check: nextLevelOfCells.Add(adjacentCell); if (reachableCells != null) { reachableCells.Add(adjacentCell); } } break; } } numberOfCellsReachable++; totalDegreesOfCellsReachable += sourceCell.DegreeOfVertex; } cellsToExpand = nextLevelOfCells; } switch (player) { case PlayerType.You: gameState.NumberOfCellsReachableByYou = numberOfCellsReachable; gameState.TotalDegreesOfCellsReachableByYou = totalDegreesOfCellsReachable; break; case PlayerType.Opponent: gameState.NumberOfCellsReachableByOpponent = numberOfCellsReachable; gameState.TotalDegreesOfCellsReachableByOpponent = totalDegreesOfCellsReachable; break; } switch (player) { case PlayerType.You: gameState.YourDijkstraStatus = DijkstraStatus.FullyCalculated; gameState.YourUpToDateDijkstraDistance = int.MaxValue; break; case PlayerType.Opponent: gameState.OpponentsDijkstraStatus = DijkstraStatus.FullyCalculated; gameState.OpponentsUpToDateDijkstraDistance = int.MaxValue; break; } } else { // Fix ClosestPlayer: foreach (CellState cellState in gameState.GetAllCellStates()) { if (cellState.ClosestPlayer == PlayerType.Unknown) { switch (cellState.CompartmentStatus) { case CompartmentStatus.InYourCompartment: cellState.ClosestPlayer = PlayerType.You; break; case CompartmentStatus.InOpponentsCompartment: cellState.ClosestPlayer = PlayerType.Opponent; break; case CompartmentStatus.InSharedCompartment: if (cellState.DistanceFromYou > cellState.DistanceFromOpponent) { cellState.ClosestPlayer = PlayerType.You; } else if (cellState.DistanceFromOpponent > cellState.DistanceFromYou) { cellState.ClosestPlayer = PlayerType.Opponent; } else { cellState.ClosestPlayer = gameState.PlayerToMoveNext; } break; } } } gameState.YourCell.ClosestPlayer = PlayerType.You; gameState.OpponentsCell.ClosestPlayer = PlayerType.Opponent; } }
public static string KNN <T>( List <T> trainFeatures, List <string> trainLabels, T testFeature, GetDistanceDelegate <T> getDistance, int K = 4) { Dictionary <string, double> classSize = new Dictionary <string, double>(); foreach (var label in trainLabels) { if (classSize.ContainsKey(label)) { classSize[label]++; } else { classSize[label] = 0.0; } } string predictLabel = ""; List <Tuple <double, int> > distAndIndexes = new List <Tuple <double, int> >(); for (int i = 0; i < trainFeatures.Count; i++) { distAndIndexes.Add(null); } Parallel.For(0, trainFeatures.Count, (i) => { distAndIndexes[i] = Tuple.Create(getDistance(trainFeatures[i], testFeature), i); }); distAndIndexes.Sort(); Dictionary <string, int> dict = new Dictionary <string, int>(); for (int i = 0; i < K; i++) { string label = trainLabels[distAndIndexes[i].Item2]; if (dict.ContainsKey(label)) { dict[label]++; } else { dict[label] = 1; } } double max = -1; foreach (var item in dict) { string label = item.Key; int num = item.Value; double ratio = num / classSize[label]; if (ratio > max) { predictLabel = label; max = ratio; } } return(predictLabel); }