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 Location[] _Reproduce(Location[] parent) { var result = (Location[])parent.Clone(); if (!MustDoCrossovers) { // When we are not using cross-overs, we always apply mutations. RandomProvider.MutateRandomLocations(result); return result; } // if you want, you can ignore the next three lines of code and the next // if, keeping the call to RandomProvider.MutateRandomLocations(result); always // invoked and without crossovers. Doing that you will not promove evolution through // "sexual reproduction", yet the good result will probably be found. int otherIndex = RandomProvider.GetRandomValue(_populationWithDistances.Length/2); var other = _populationWithDistances[otherIndex].Key; RandomProvider._CrossOver(result, other, MustMutateFailedCrossovers); if (!MustMutateFailedCrossovers) if (RandomProvider.GetRandomValue(10) == 0) RandomProvider.MutateRandomLocations(result); return result; }