Пример #1
0
            public static void ReverseRange(LocationGA[] locations, int startIndex, int endIndex)
            {
                if (locations == null)
                {
                    throw new ArgumentNullException("locations");
                }

                if (startIndex < 0 || startIndex >= locations.Length)
                {
                    throw new ArgumentOutOfRangeException("startIndex");
                }

                if (endIndex < 0 || endIndex >= locations.Length)
                {
                    throw new ArgumentOutOfRangeException("endIndex");
                }

                if (endIndex < startIndex)
                {
                    int temp = endIndex;
                    endIndex   = startIndex;
                    startIndex = temp;
                }

                while (startIndex < endIndex)
                {
                    LocationGA temp = locations[endIndex];
                    locations[endIndex]   = locations[startIndex];
                    locations[startIndex] = temp;

                    startIndex++;
                    endIndex--;
                }
            }
Пример #2
0
        private void GoGeneticAlgorithm(LocationGA startLocation, LocationGA[] destinations)
        {
            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   = (LocationGA[])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 LocationGA".
            // This is rarely the shortest path, yet it is already a "somewhat good" path.
            //destinations = _GetFakeShortest(destinations);

            _populationWithDistances = new KeyValuePair <LocationGA[], double> [_populationCount];

            // Create initial population.
            for (int solutionIndex = 0; solutionIndex < _populationCount; solutionIndex++)
            {
                var newPossibleDestinations = (LocationGA[])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 = LocationGA.GetTotalDistance(startLocation, newPossibleDestinations);
                var pair     = new KeyValuePair <LocationGA[], double>(newPossibleDestinations, distance);

                _populationWithDistances[solutionIndex] = pair;
            }

            Array.Sort(_populationWithDistances, _sortDelegate);
        }
Пример #3
0
        public Location[] Solution(Cities cities)
        {
            LocationGA[] _randomLocations = new LocationGA[cities.NumCities];
            _randomLocations = cities.GetLocations().Select(x => new LocationGA(x)).ToArray();
            GoGeneticAlgorithm((LocationGA)_randomLocations[0], _randomLocations);

            int i = _maxTime;

            Location[] _bestSolutionSoFar = GetBestSolutionSoFar().ToArray();

            bool _mutateFailedCrossovers = false;
            bool _mutateDuplicates       = false;
            bool _mustDoCrossovers       = true;

            while (i-- > 0)
            {
                MustMutateFailedCrossovers = _mutateFailedCrossovers;
                MustDoCrossovers           = _mustDoCrossovers;
                Reproduce();

                if (_mutateDuplicates)
                {
                    MutateDuplicates();
                }

                var newSolution = GetBestSolutionSoFar().ToArray();
                if (!newSolution.SequenceEqual(_bestSolutionSoFar))
                {
                    _bestSolutionSoFar = newSolution;
                }
            }
            _totalDistance = LocationGA.GetTotalDistance((LocationGA)_randomLocations[0], _bestSolutionSoFar.Select(x => new LocationGA(x)).ToArray());
            return(_bestSolutionSoFar);
        }
Пример #4
0
        private LocationGA[] _GetFakeShortest(LocationGA[] destinations)
        {
            LocationGA[] result = new LocationGA[destinations.Length];

            var currentLocation = _startLocation;

            for (int fillingIndex = 0; fillingIndex < destinations.Length; fillingIndex++)
            {
                int    bestIndex    = -1;
                double bestDistance = double.MaxValue;

                for (int evaluatingIndex = 0; evaluatingIndex < destinations.Length; evaluatingIndex++)
                {
                    var evaluatingItem = destinations[evaluatingIndex];
                    if (evaluatingItem == null)
                    {
                        continue;
                    }

                    double distance = currentLocation.GetDistance(evaluatingItem);
                    if (distance < bestDistance)
                    {
                        bestDistance = distance;
                        bestIndex    = evaluatingIndex;
                    }
                }

                result[fillingIndex]    = destinations[bestIndex];
                currentLocation         = destinations[bestIndex];
                destinations[bestIndex] = null;
            }

            return(result);
        }
Пример #5
0
            public static double GetTotalDistance(LocationGA startLocation, LocationGA[] locations)
            {
                if (startLocation == null)
                {
                    throw new ArgumentNullException("startLocation");
                }

                if (locations == null)
                {
                    throw new ArgumentNullException("locations");
                }

                if (locations.Length == 0)
                {
                    throw new ArgumentException("The locations array must have at least one element.", "locations");
                }

                foreach (var location in locations)
                {
                    if (location == null)
                    {
                        throw new ArgumentException("The locations array can't contain null values.");
                    }
                }

                double result     = startLocation.GetDistance(locations[0]);
                int    countLess1 = locations.Length - 1;

                for (int i = 0; i < countLess1; i++)
                {
                    var actual = locations[i];
                    var next   = locations[i + 1];

                    var distance = actual.GetDistance(next);
                    result += distance;
                }

                result += locations[locations.Length - 1].GetDistance(startLocation);

                return(result);
            }
Пример #6
0
            public static void FullyRandomizeLocations(LocationGA[] locations)
            {
                if (locations == null)
                {
                    throw new ArgumentNullException("locations");
                }

                // This code does a full randomization of the destination locations without creating a new array.
                // If we have 3 items, for example, it will first determine which one of the 3 will be in the last
                // place, swapping items if needed. Then, it will chose which one of the first 2 items is put at the
                // second place. And, as everything works by swaps, the item in the first position is obviously the
                // only one that remains, that's why the i>0 is used instead of i>=0.
                int count = locations.Length;

                for (int i = count - 1; i > 0; i--)
                {
                    int value = GetRandomValue(i + 1);
                    if (value != i)
                    {
                        LocationGA.SwapLocations(locations, i, value);
                    }
                }
            }
Пример #7
0
        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 <LocationGA[], double>(child1, LocationGA.GetTotalDistance(_startLocation, child1));
                var pair2 = new KeyValuePair <LocationGA[], double>(child2, LocationGA.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);
        }
Пример #8
0
            public static void MutateRandomLocations(LocationGA[] locations)
            {
                if (locations == null)
                {
                    throw new ArgumentNullException("locations");
                }

                if (locations.Length < 2)
                {
                    throw new ArgumentException("The locations array must have at least two items.", "locations");
                }

                // I opted to give up to 10% of the chromosome size in number of mutations.
                // Maybe I should find a better number of make this configurable.
                int mutationCount = GetRandomValue(locations.Length / 10) + 1;

                for (int mutationIndex = 0; mutationIndex < mutationCount; mutationIndex++)
                {
                    int index1 = GetRandomValue(locations.Length);
                    int index2 = GetRandomValue(locations.Length - 1);
                    if (index2 >= index1)
                    {
                        index2++;
                    }

                    switch (GetRandomValue(3))
                    {
                    case 0: LocationGA.SwapLocations(locations, index1, index2); break;

                    case 1: LocationGA.MoveLocations(locations, index1, index2); break;

                    case 2: LocationGA.ReverseRange(locations, index1, index2); break;

                    default: throw new InvalidOperationException();
                    }
                }
            }
Пример #9
0
        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 <LocationGA[], double>(current.Key, LocationGA.GetTotalDistance(_startLocation, current.Key));
            }

            if (needToSortAgain)
            {
                Array.Sort(_populationWithDistances, _sortDelegate);
            }
        }