public TravellingSalesmanAlgorithm(Location startLocation, Location[] destinations, int populationCount) { if (startLocation == null) { throw new ArgumentNullException("startLocation"); } if (destinations == null) { throw new ArgumentNullException("destinations"); } if (populationCount < 2) { throw new ArgumentOutOfRangeException("populationCount"); } if (populationCount % 2 != 0) { throw new ArgumentException("The populationCount parameter must be an even value.", "populationCount"); } _startLocation = startLocation; destinations = (Location[])destinations.Clone(); foreach (var destination in destinations) { if (destination == null) { throw new ArgumentException("The destinations array can't contain null values.", "destinations"); } } // This commented method uses a search of the kind "look for the nearest non visited location". // This is rarely the shortest path, yet it is already a "somewhat good" path. destinations = _GetFakeShortest(destinations); _populationWithDistances = new KeyValuePair <Location[], double> [populationCount]; // Create initial population. for (int solutionIndex = 0; solutionIndex < populationCount; solutionIndex++) { var newPossibleDestinations = (Location[])destinations.Clone(); // Try commenting the next 2 lines of code while keeping the _GetFakeShortest active. // If you avoid the algorithm from running and press reset, you will see that it always // start with a path that seems "good" but is not the best. //for(int randomIndex=0; randomIndex<newPossibleDestinations.Length; randomIndex++) //RandomProvider.FullyRandomizeLocations(newPossibleDestinations); var distance = Location.GetTotalDistance(startLocation, newPossibleDestinations); var pair = new KeyValuePair <Location[], double>(newPossibleDestinations, distance); _populationWithDistances[solutionIndex] = pair; } Array.Sort(_populationWithDistances, _sortDelegate); }
private void generateLines() { Location[] bestSolutionSoFar = _bestSolutionSoFar; Location.GetTotalDistance(_startLocation, bestSolutionSoFar); _tspSegments.Clear(); if (bestSolutionSoFar.Length > 0) { var actualLocation = _startLocation; int index = 0; int dropCount = 0; foreach (var destination in _AddEndLocation(bestSolutionSoFar)) { var line = new TSPSegment() { start = new Vector2(actualLocation.X, actualLocation.Y), end = new Vector2(destination.X, destination.Y) }; if (line.LineLength() > kJumpThreshold) { line.type = TSPSegment.LineType.Jump; } else { line.type = TSPSegment.LineType.Draw; } _tspSegments.Add(line); actualLocation = destination; index++; } Debug.WriteLine("Total long jumps: " + dropCount); Debug.WriteLine("Segments added: " + _tspSegments.Count); } }
public void Reproduce() { var bestSoFar = _populationWithDistances[0]; int halfCount = _populationWithDistances.Length / 2; for (int i = 0; i < halfCount; i++) { var parent = _populationWithDistances[i].Key; var child1 = _Reproduce(parent); var child2 = _Reproduce(parent); var pair1 = new KeyValuePair <Location[], double>(child1, Location.GetTotalDistance(_startLocation, child1)); var pair2 = new KeyValuePair <Location[], double>(child2, Location.GetTotalDistance(_startLocation, child2)); _populationWithDistances[i * 2] = pair1; _populationWithDistances[i * 2 + 1] = pair2; } // We keep the best alive from one generation to the other. _populationWithDistances[_populationWithDistances.Length - 1] = bestSoFar; Array.Sort(_populationWithDistances, _sortDelegate); }
public void MutateDuplicates() { bool needToSortAgain = false; int countDuplicates = 0; var previous = _populationWithDistances[0]; for (int i = 1; i < _populationWithDistances.Length; i++) { var current = _populationWithDistances[i]; if (!previous.Key.SequenceEqual(current.Key)) { previous = current; continue; } countDuplicates++; needToSortAgain = true; RandomProvider.MutateRandomLocations(current.Key); _populationWithDistances[i] = new KeyValuePair <Location[], double>(current.Key, Location.GetTotalDistance(_startLocation, current.Key)); } if (needToSortAgain) { Array.Sort(_populationWithDistances, _sortDelegate); } }