/// <summary>
        /// Generates a random individual.
        /// </summary>
        /// <param name="solver"></param>
        /// <returns></returns>
        public Individual <List <int>, GeneticProblem, Fitness> Generate(
            Solver <List <int>, GeneticProblem, Fitness> solver)
        {
            // create new genomes list.
            List <int> genome = new List <int>();

            // build cities to place (in a thread-safe way!)
            List <int> cities_to_place = new List <int>();

            lock (solver)
            {
                for (int idx = 0; idx < solver.Problem.Along.Count; idx++)
                {
                    cities_to_place.Add(solver.Problem.Along[idx]);
                }
            }

            BestPlacementHelper helper = BestPlacementHelper.Instance();

            helper.DoFast(
                solver.Problem,
                solver.FitnessCalculator as FitnessCalculator,
                genome,
                cities_to_place);

            Individual individual = new Individual(genome);

            individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
            return(individual);
        }
예제 #2
0
        /// <summary>
        /// Generates a random individual.
        /// </summary>
        /// <param name="solver"></param>
        /// <returns></returns>
        public Individual <List <int>, GeneticProblem, Fitness> Generate(
            Solver <List <int>, GeneticProblem, Fitness> solver)
        {
            List <int> genome       = new List <int>();
            List <int> node_indexes = new List <int>();

            for (int i = 0; i < solver.Problem.Along.Count; i++)
            {
                node_indexes.Add(i);
            }
            for (int i = 0; i < solver.Problem.Along.Count; i++)
            {
                // get the random idx.
                int idx = solver.Random.Next(node_indexes.Count);

                // get the node at the given idx.
                genome.Add(solver.Problem.Along[node_indexes[idx]]);
                node_indexes.RemoveAt(idx); // remove the idx.
            }

            Individual individual = new Individual(genome);

            individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
            return(individual);
        }
        /// <summary>
        /// Re-places all the cities again to their own best place.
        /// </summary>
        /// <param name="solver"></param>
        /// <param name="mutating"></param>
        /// <returns></returns>
        private Individual <List <int>, GeneticProblem, Fitness> MutateByRePlacement(
            Solver <List <int>, GeneticProblem, Fitness> solver,
            Individual <List <int>, GeneticProblem, Fitness> mutating)
        {
            List <int> nodes_to_re_place = mutating.Genomes.ToList <int>();
            List <int> current_placement = mutating.Genomes.ToList <int>();

            foreach (int node_to_place in nodes_to_re_place)
            {
                // take the node out.
                current_placement.Remove(node_to_place);

                // place the node back in.
                BestPlacementHelper helper = BestPlacementHelper.Instance();
                helper.Do(
                    solver.Problem,
                    solver.FitnessCalculator as FitnessCalculator,
                    current_placement,
                    node_to_place);
            }

            Individual individual = new Individual(current_placement);

            individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
            return(individual);
        }
예제 #4
0
        /// <summary>
        /// Places a city into an idividual.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="calculator"></param>
        /// <param name="round_idx"></param>
        /// <param name="individual"></param>
        /// <param name="city_to_place"></param>
        /// <returns></returns>
        internal static BestPlacementResult CalculateBestPlacementInIndividual(
            Problem problem,
            FitnessCalculator calculator,
            int round_idx,
            Individual <List <Genome>, Problem, Fitness> individual,
            int city_to_place)
        {
            // if the target round is empty best placement is impossible.
            Genome round = individual.Genomes[round_idx];

            // do best placement in the genome/round.
            BestPlacementResult result =
                BestPlacementHelper.CalculateBestPlacementInGenome(problem, calculator, round, city_to_place);

            // set the round index.
            result.RoundIdx = round_idx;
            if (!individual.FitnessCalculated)
            {
                individual.CalculateFitness(
                    problem, calculator);
            }
            result.Fitness = calculator.Adjust(
                problem,
                individual.Fitness,
                round_idx,
                result.Increase);

            // return the result.
            return(result);
        }
예제 #5
0
        /// <summary>
        /// Mutates a given individual.
        /// </summary>
        /// <param name="solver"></param>
        /// <param name="mutating"></param>
        /// <returns></returns>
        public Individual <List <int>, GeneticProblem, Fitness> Mutate(
            Solver <List <int>, GeneticProblem, Fitness> solver,
            Individual <List <int>, GeneticProblem, Fitness> mutating)
        {
            // take a random piece.
            int idx = solver.Random.Next(mutating.Genomes.Count);

            List <int> new_genome = new List <int>(mutating.Genomes);
            int        customer   = new_genome[idx];

            new_genome.RemoveAt(idx);

            // apply best placement algorithm to place the selected genomes.
            BestPlacementHelper helper = BestPlacementHelper.Instance();

            helper.Do(
                solver.Problem,
                solver.FitnessCalculator as FitnessCalculator,
                new_genome,
                customer);

            Individual individual = new Individual(new_genome);

            individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
            return(individual);
        }
예제 #6
0
        /// <summary>
        /// Generates a random individual.
        /// </summary>
        /// <param name="solver"></param>
        /// <returns></returns>
        public Individual<List<int>, GeneticProblem, Fitness> Generate(
            Solver<List<int>, GeneticProblem, Fitness> solver)
        {
            ISolver lk_solver = new HillClimbing3OptSolver(true, true);
            IRoute route = lk_solver.Solve(solver.Problem.BaseProblem);

            List<int> new_genome = new List<int>();
            bool first_found = false;
            foreach (int customer in route)
            {
                if (first_found)
                {
                    new_genome.Add(customer);
                }
                if (customer == 0)
                {
                    first_found = true;
                }
            }
            foreach (int customer in route)
            {
                if (customer == 0)
                {
                    break;
                }
                new_genome.Add(customer);
            }

            Individual individual = new Individual(new_genome);
            individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
            return individual;
        }
        public void Should_Return_Correct_Fitness(string target, string genes, double fitness)
        {
            var sut = new Individual(genes.ToCharArray(), Random);

            sut.CalculateFitness(target.ToCharArray());

            Assert.Equal(fitness, sut.Fitness);
        }
        /// <summary>
        /// Mutates an idividual.
        /// </summary>
        /// <param name="solver"></param>
        /// <param name="mutating"></param>
        /// <returns></returns>
        public Individual <List <int>, GeneticProblem, Fitness> Mutate(
            Solver <List <int>, GeneticProblem, Fitness> solver,
            Individual <List <int>, GeneticProblem, Fitness> mutating)
        {
            List <int> genome = new List <int>(mutating.Genomes);

            if (solver.Random.Next(2) > 0)
            {
                // switch two nodes.
                int idx1 = solver.Random.Next(genome.Count);
                int idx2 = solver.Random.Next(genome.Count);

                if (idx1 != idx2)
                {
                    int temp = genome[idx1];
                    genome[idx1] = genome[idx2];
                    genome[idx2] = temp;
                }
            }
            else
            {
                // switch two nodes.
                int idx1 = solver.Random.Next(genome.Count);
                int idx2 = solver.Random.Next(genome.Count);

                // make sure idx1 < idx2.
                if (idx1 > idx2)
                {
                    int idx_temp = idx2;
                    idx2 = idx1;
                    idx1 = idx_temp;
                }

                // switch order.
                if (idx1 != idx2)
                {
                    List <int> genomes_to_change = new List <int>();
                    for (int idx = idx1; idx <= idx2; idx++)
                    {
                        genomes_to_change.Add(genome[idx]);
                    }
                    genomes_to_change.Reverse();
                    int idx_list = 0;
                    for (int idx = idx1; idx <= idx2; idx++)
                    {
                        genome[idx] = genomes_to_change[idx_list];
                        idx_list++;
                    }
                }
            }

            Individual individual = new Individual(genome);

            individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
            return(individual);
        }
예제 #9
0
        /// <summary>
        /// Generates a random individual.
        /// </summary>
        /// <param name="solver"></param>
        /// <returns></returns>
        public Individual <List <int>, GeneticProblem, Fitness> Generate(
            Solver <List <int>, GeneticProblem, Fitness> solver)
        {
            ISolver lk_solver = new LinKernighanSolver();
            IRoute  route     = lk_solver.Solve(solver.Problem.BaseProblem);

            Individual individual = new Individual(new List <int>(route));

            individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
            return(individual);
        }
        public void Should_Calculate_Fitness()
        {
            const string targetString = "sample text";

            var sut = new Individual("sample other".ToCharArray(), Random);

            var oldFitness = sut.Fitness;

            sut.CalculateFitness(targetString.ToCharArray());

            Assert.NotEqual(sut.Fitness, oldFitness);
        }
        public void Should_Return_Correct_String_Representation()
        {
            const string s = "*****@*****.**";

            var sut = new Individual(s.ToCharArray(), Random);

            sut.CalculateFitness(s.ToCharArray());

            Assert.Equal(1d, sut.Fitness);

            Assert.Equal($"fitness: 100.00% - phrase: {s}", sut.ToString());
        }
        /// <summary>
        /// Take a piece of the genome and re-do best placement.
        /// </summary>
        /// <param name="solver"></param>
        /// <param name="mutating"></param>
        /// <returns></returns>
        private Individual <List <int>, GeneticProblem, Fitness> MutateByTakingPiece(
            Solver <List <int>, GeneticProblem, Fitness> solver,
            Individual <List <int>, GeneticProblem, Fitness> mutating)
        {
            // take a random piece.
            int idx1 = 0;
            int idx2 = 0;

            while (idx2 - idx1 == 0)
            {
                idx1 = solver.Random.Next(mutating.Genomes.Count - 1) + 1;
                idx2 = solver.Random.Next(mutating.Genomes.Count - 1) + 1;
                if (idx1 > idx2)
                {
                    int temp = idx1;
                    idx1 = idx2;
                    idx2 = temp;
                }
            }

            // if the genome range is big take it from the best individual.
            Individual <List <int>, GeneticProblem, Fitness> source =
                (mutating as Individual <List <int>, GeneticProblem, Fitness>);
            Individual <List <int>, GeneticProblem, Fitness> target =
                (mutating as Individual <List <int>, GeneticProblem, Fitness>);

            List <int> source_piece = source.Genomes.GetRange(idx1, idx2 - idx1);
            List <int> new_genome   = target.Genomes.GetRange(0, target.Genomes.Count);

            // insert the piece into the worst individual.
            // remove nodes in the source_piece.
            foreach (int source_node in source_piece)
            {
                new_genome.Remove(source_node);
            }

            // apply best placement algorithm to place the selected genomes.
            //List<int> genome = new List<int>();
            BestPlacementHelper helper = BestPlacementHelper.Instance();

            helper.DoFast(
                solver.Problem,
                solver.FitnessCalculator as FitnessCalculator,
                new_genome,
                source_piece);

            Individual individual = new Individual(new_genome);

            individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
            return(individual);
        }
예제 #13
0
        static string SimpleReplacement_Hack()
        {
            List <Individual> generation = GetFirstGeneration();
            Individual        best       = new Individual(generation[0]);
            Stopwatch         sw         = Stopwatch.StartNew();

            best.CalculateFitness();

            int i = 0;

            while (true)
            {
                Parallel.ForEach(generation, x => x.CalculateFitness());
                generation.Sort((x, y) => x.Fitness.CompareTo(y.Fitness));

                Console.WriteLine($"[Gen {++i,4}] {generation[0].Fitness}");
                if (generation[0].Fitness < best.Fitness)
                {
                    best = generation[0];
                }
                if (Math.Abs(SourseFitness - generation[0].Fitness) < FitnessDelta || i >= MaxGenerations)
                {
                    break;
                }

                generation = Crossover(generation);

                Parallel.ForEach(generation, x => x.CalculateFitness());
                generation.Sort((x, y) => x.Fitness.CompareTo(y.Fitness));

                Mutation(generation);
            }

            Console.WriteLine();
            Console.WriteLine($"[Total generations]   {i}");
            Console.WriteLine($"[Total time(sec)]     {sw.Elapsed.TotalSeconds}");
            Console.WriteLine($"[Average ms/gen]      {(double)sw.ElapsedMilliseconds / i}");
            Console.WriteLine($"[Best fitness]        {best.Fitness}");

            return(ByteArrToString(SimpleReplacement_Decode(best.Key)));
        }
예제 #14
0
        static List <Individual> GetFirstGeneration()
        {
            Random random = new Random(Guid.NewGuid().GetHashCode());

            Individual[] keys = new Individual[PopulationSize];

            Parallel.For(0, PopulationSize, i =>
            {
                byte[] arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 };

                Individual ind = new Individual(new List <byte>(arr).OrderBy(x => random.Next()).ToArray());
                ind.CalculateFitness();

                while (ind.Fitness > FirstPopulationMinFitness)
                {
                    ind = new Individual(new List <byte>(arr).OrderBy(x => random.Next()).ToArray());
                    ind.CalculateFitness();
                }

                keys[i] = ind;
            });

            return(keys.ToList());
        }
        /// <summary>
        /// Applies this operation.
        /// </summary>
        /// <param name="solver"></param>
        /// <param name="parent1"></param>
        /// <param name="parent2"></param>
        /// <returns></returns>
        public Individual <List <int>, GeneticProblem, Fitness> CrossOver(
            Solver <List <int>, GeneticProblem, Fitness> solver,
            Individual <List <int>, GeneticProblem, Fitness> parent1,
            Individual <List <int>, GeneticProblem, Fitness> parent2)
        {
            OsmSharp.Math.TSP.Problems.IProblem tsp_problem = solver.Problem.BaseProblem;

            // first create E_a
            int[] e_a = new int[parent1.Genomes.Count + 1];
            e_a[0] = parent1.Genomes[0];
            for (int idx = 0; idx < parent1.Genomes.Count - 1; idx++)
            {
                int from = parent1.Genomes[idx];
                int to   = parent1.Genomes[idx + 1];

                e_a[from] = to;
            }
            e_a[parent1.Genomes[parent1.Genomes.Count - 1]] = 0;

            // create E_b
            int[] e_b = new int[parent2.Genomes.Count + 1];
            e_b[0] = parent2.Genomes[0];
            for (int idx = 0; idx < parent2.Genomes.Count - 1; idx++)
            {
                int from = parent2.Genomes[idx];
                int to   = parent2.Genomes[idx + 1];

                e_b[from] = to;
            }
            e_b[parent2.Genomes[parent2.Genomes.Count - 1]] = 0;

            // create G_ab.
            Dictionary <int, int> g_a =
                new Dictionary <int, int>();
            Dictionary <int, int> g_b_opposite =
                new Dictionary <int, int>();

            for (int idx = 0; idx < e_b.Length; idx++)
            {
                if (e_a[idx] != e_b[idx])
                {
                    g_a.Add(idx, e_a[idx]);
                    g_b_opposite.Add(e_b[idx], idx);
                }
            }

            List <Dictionary <int, KeyValuePair <int, int> > > cycles =
                new List <Dictionary <int, KeyValuePair <int, int> > >();

            while (g_a.Count > 0)
            {
                int first = g_a.Keys.First <int>();
                KeyValuePair <int, int> next_pair;
                Dictionary <int, KeyValuePair <int, int> > cycle =
                    new Dictionary <int, KeyValuePair <int, int> >();
                while (!cycle.ContainsKey(first))
                {
                    next_pair = new KeyValuePair <int, int>(g_a[first], g_b_opposite[g_a[first]]);
                    // remove.
                    g_a.Remove(first);
                    g_b_opposite.Remove(next_pair.Key);


                    cycle.Add(first, next_pair);

                    // get all the nexts ones.
                    first = next_pair.Value;
                }
                cycles.Add(cycle);
            }

            int        generated = 0;
            Individual best      = null;

            while (generated < _max_offspring)
            {
                // select some random cycles.
                List <Dictionary <int, KeyValuePair <int, int> > > selected_cycles =
                    this.SelectCycles(cycles);

                // take e_a and remove all edges that are in the selected cycles and replace them by the eges
                // from e_b in the cycles.
                foreach (Dictionary <int, KeyValuePair <int, int> > cycle in selected_cycles)
                {
                    foreach (KeyValuePair <int, KeyValuePair <int, int> > pair in cycle)
                    {
                        e_a[pair.Value.Value] = pair.Value.Key;
                    }
                }

                // construct all subtours.
                List <Dictionary <int, KeyValuePair <int, double> > > subtours =
                    new List <Dictionary <int, KeyValuePair <int, double> > >();
                List <int> e_a_list  = new List <int>(e_a);
                int        start_idx = 0;
                while (start_idx < e_a_list.Count)
                {
                    Dictionary <int, KeyValuePair <int, double> > current_tour = new Dictionary <int, KeyValuePair <int, double> >();

                    int from = start_idx;
                    int to   = e_a_list[from];
                    while (to >= 0)
                    {
                        e_a_list[from] = -1;

                        current_tour.Add(from, new KeyValuePair <int, double>(to, tsp_problem.WeightMatrix[from][to]));

                        from = to;

                        to = e_a_list[from];
                    }

                    for (start_idx = start_idx + 1; start_idx < e_a_list.Count; start_idx++)
                    {
                        if (e_a_list[start_idx] >= 0)
                        {
                            break;
                        }
                    }
                    subtours.Add(current_tour);
                }
                while (subtours.Count > 1)
                {
                    int size = e_a.Length;
                    Dictionary <int, KeyValuePair <int, double> > current_tour = null;
                    foreach (Dictionary <int, KeyValuePair <int, double> > tour in subtours)
                    {
                        if (current_tour == null ||
                            tour.Count < current_tour.Count)
                        {
                            current_tour = tour;
                        }
                    }

                    // merge two tours.
                    Dictionary <int, KeyValuePair <int, double> > target_tour = null;
                    double weight = double.MaxValue;
                    KeyValuePair <int, KeyValuePair <int, double> > from = new KeyValuePair <int, KeyValuePair <int, double> >();
                    KeyValuePair <int, KeyValuePair <int, double> > to   = new KeyValuePair <int, KeyValuePair <int, double> >();

                    // first try nn approach.
                    if (_nn)
                    {
                        foreach (KeyValuePair <int, KeyValuePair <int, double> > from_pair in current_tour)
                        {
                            foreach (int nn in tsp_problem.Get10NearestNeighbours(from_pair.Key))
                            {
                                if (!current_tour.ContainsKey(nn))
                                {
                                    foreach (Dictionary <int, KeyValuePair <int, double> > target in subtours)
                                    {
                                        KeyValuePair <int, double> to_pair_value;
                                        if (target.TryGetValue(nn, out to_pair_value))
                                        {
                                            double merge_weight = (tsp_problem.WeightMatrix[from_pair.Key][to_pair_value.Key] +
                                                                   tsp_problem.WeightMatrix[nn][from_pair.Value.Key]) -
                                                                  (from_pair.Value.Value + to_pair_value.Value);
                                            if (merge_weight < weight)
                                            {
                                                weight      = merge_weight;
                                                from        = from_pair;
                                                to          = new KeyValuePair <int, KeyValuePair <int, double> >(nn, to_pair_value);
                                                target_tour = target;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    if (target_tour == null)
                    {
                        foreach (KeyValuePair <int, KeyValuePair <int, double> > from_pair in current_tour)
                        {
                            foreach (Dictionary <int, KeyValuePair <int, double> > target in subtours)
                            {
                                if (target != current_tour)
                                {
                                    foreach (KeyValuePair <int, KeyValuePair <int, double> > to_pair in target)
                                    {
                                        double merge_weight = (tsp_problem.WeightMatrix[from_pair.Key][to_pair.Value.Key] +
                                                               tsp_problem.WeightMatrix[to_pair.Key][from_pair.Value.Key]) -
                                                              (from_pair.Value.Value + to_pair.Value.Value);
                                        if (merge_weight < weight)
                                        {
                                            weight      = merge_weight;
                                            from        = from_pair;
                                            to          = to_pair;
                                            target_tour = target;
                                        }
                                    }
                                }
                            }
                        }
                    }

                    // merge the tours.
                    subtours.Remove(current_tour);
                    foreach (KeyValuePair <int, KeyValuePair <int, double> > for_target in current_tour)
                    {
                        target_tour.Add(for_target.Key, for_target.Value);
                    }
                    target_tour[from.Key] = new KeyValuePair <int, double>(to.Value.Key,
                                                                           tsp_problem.WeightMatrix[from.Key][to.Value.Key]);
                    target_tour[to.Key] = new KeyValuePair <int, double>(from.Value.Key,
                                                                         tsp_problem.WeightMatrix[to.Key][from.Value.Key]);
                }
                List <int> new_genome = new List <int>();
                int        next       = subtours[0][0].Key;
                do
                {
                    new_genome.Add(next);
                    next = subtours[0][next].Key;
                }while (next != 0);

                Individual individual = new Individual(new_genome);
                individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
                if (best == null ||
                    best.Fitness.CompareTo(individual.Fitness) > 0)
                {
                    best = individual;
                }

                generated++;
            }
            return(best);
        }
예제 #16
0
        /// <summary>
        /// Calculates/generates a next generation based on the given one.
        /// </summary>
        /// <param name="population"></param>
        /// <returns></returns>
        private Population <GenomeType, ProblemType, WeightType> NextGeneration(Population <GenomeType, ProblemType, WeightType> population)
        {
            Population <GenomeType, ProblemType, WeightType> next_population =
                new Population <GenomeType, ProblemType, WeightType>(true);

            // do elitims selection.
            int elitism_count = (int)(population.Count * (_settings.ElitismPercentage / 100f));

            next_population.AddRange(
                population.GetRange(
                    0,
                    elitism_count));

            // do selection/cross-over.
            //Tools.Core.Output.OutputTextStreamHost.Write(" C:");
            int cross_over_count = (int)(population.Count *
                                         (_settings.CrossOverPercentage / 100f)) + elitism_count;

            while (next_population.Count < cross_over_count &&
                   next_population.Count < population.Count)
            {
                // select two individuals.
                Individual <GenomeType, ProblemType, WeightType> individual1 = _selector.Select(
                    this,
                    population,
                    null);
                Individual <GenomeType, ProblemType, WeightType> individual2 = _selector.Select(
                    this,
                    population,
                    new HashSet <Individual <GenomeType, ProblemType, WeightType> >(
                        new Individual <GenomeType, ProblemType, WeightType>[] { individual1 }));

                // cross-over.
                Individual <GenomeType, ProblemType, WeightType> new_individual =
                    _crossOverOperation.CrossOver(
                        this,
                        individual1,
                        individual2);

                new_individual.CalculateFitness(_problem, _fitness_calculator);
                if (_accept_only_better_on_cross_over)
                {
                    if (new_individual.Fitness.CompareTo(individual1.Fitness) < 0 &&
                        new_individual.Fitness.CompareTo(individual2.Fitness) < 0)
                    {
                        // add to the new population.
                        next_population.Add(new_individual);
                    }
                    else
                    {
                        //next_population.Add(individual1);
                        if (individual2.Fitness.CompareTo(individual1.Fitness) < 0)
                        {
                            // add to the new population.
                            next_population.Add(individual2);
                        }
                        else
                        {
                            next_population.Add(individual1);
                        }
                    }
                }
                else
                {
                    // add to the new population.
                    next_population.Add(new_individual);
                }

                //this.ReportNew("Crossing over population!", next_population.Count, population.Count);
                //Tools.Core.Output.OutputTextStreamHost.Write(".");
            }

            // do mutation to generate the rest of the population.
            int mutation_count =
                (int)(population.Count * (_settings.MutationPercentage / 100f)) + cross_over_count;
            int mutation_count_max_tries = mutation_count * 2; // try mutation 10 times more.
            int mutation_idx_absolute    = 0;

            //Tools.Core.Output.OutputTextStreamHost.Write(" m:");
            while (next_population.Count < mutation_count &&
                   next_population.Count < population.Count)
            {
                // get random individual.
                int individual_to_mutate_idx = this.Random.Next(population.Count);
                Individual <GenomeType, ProblemType, WeightType> individual_to_mutate =
                    population[individual_to_mutate_idx];

                // mutate.
                Individual <GenomeType, ProblemType, WeightType> mutation = _mutation_operation.Mutate(
                    this,
                    individual_to_mutate);
                //if (!mutation.Equals(individual_to_mutate))
                //{ // do not add indentical ones.
                // add to population.
                if (_accept_only_better_on_mutation)
                {
                    mutation.CalculateFitness(_problem, _fitness_calculator);
                    if (mutation.Fitness.CompareTo(individual_to_mutate.Fitness) < 0)
                    {
                        next_population.Add(mutation);
                    }
                }
                else
                {
                    next_population.Add(mutation);
                }

                //    //Tools.Core.Output.OutputTextStreamHost.Write(".");
                //    this.ReportNew("Mutating population!", next_population.Count, population.Count);
                //}

                // increase the absolute count.
                mutation_idx_absolute++;
                if (mutation_idx_absolute > mutation_count_max_tries)
                { // stop trying to mutate not new individuals could be found.
                    break;
                }
            }


            while (next_population.Count < population.Count)
            {
                // get random individual.
                int individual_to_mutate_idx = this.Random.Next(population.Count);
                Individual <GenomeType, ProblemType, WeightType> individual =
                    population[individual_to_mutate_idx];

                // place in the new population.
                next_population.Add(individual);

                this.ReportNew("Filling population!", next_population.Count, population.Count);
            }

            return(next_population);
        }
        /// <summary>
        /// Crosses over the two indivduals using sequantial contructive crossover.
        /// </summary>
        /// <param name="solver"></param>
        /// <param name="parent1"></param>
        /// <param name="parent2"></param>
        /// <returns></returns>
        public Individual <List <int>, GeneticProblem, Fitness> CrossOver(
            Solver <List <int>, GeneticProblem, Fitness> solver,
            Individual <List <int>, GeneticProblem, Fitness> parent1,
            Individual <List <int>, GeneticProblem, Fitness> parent2)
        {
            List <int>    new_individual     = new List <int>();
            HashSet <int> selected_nodes     = new HashSet <int>();
            List <int>    non_selected_nodes = new List <int>(parent1.Genomes);

            // build the edge list.
            int edges = 1;

            if (solver.Problem.First != solver.Problem.Last)
            {
                edges = 2;
            }
            int[] edges_in_parent1 = new int[parent1.Genomes.Count + edges];
            int[] edges_in_parent2 = new int[parent1.Genomes.Count + edges];
            edges_in_parent1[solver.Problem.First] = -1;
            edges_in_parent1[solver.Problem.Last]  = -1;
            edges_in_parent2[solver.Problem.First] = -1;
            edges_in_parent2[solver.Problem.Last]  = -1;
            for (int idx = 0; idx < parent1.Genomes.Count - 1; idx++)
            {
                edges_in_parent1[parent1.Genomes[idx]] = parent1.Genomes[idx + 1];
                edges_in_parent2[parent2.Genomes[idx]] = parent2.Genomes[idx + 1];
            }
            edges_in_parent1[parent1.Genomes[parent1.Genomes.Count - 1]] = -1;
            edges_in_parent2[parent2.Genomes[parent2.Genomes.Count - 1]] = -1;

            // start with the first node.
            int selected_node = parent1.Genomes[0];

            new_individual.Add(selected_node);
            selected_nodes.Add(selected_node);
            non_selected_nodes.Remove(selected_node);

            // find the next legitimate node in both.
            double total_weight = solver.Problem.Weight(solver.Problem.First, selected_node);

            while (non_selected_nodes.Count > 0)
            {
                int  node_parent1       = edges_in_parent1[selected_node];
                bool node_parent1_found = false;
                int  node_parent2       = edges_in_parent2[selected_node];
                bool node_parent2_found = false;

                // find a node for parent1 if no legitimate one was found.
                if (node_parent1 >= 0)
                {
                    node_parent1_found = (!selected_nodes.Contains(node_parent1));
                    edges_in_parent1[selected_node] = -1;
                }

                // find a node for parent2 if no legitimate one was found.
                if (node_parent2 >= 0)
                {
                    node_parent2_found = (!selected_nodes.Contains(node_parent2));
                    edges_in_parent2[selected_node] = -1;
                }

                // find a node for parent1 if no legitimate one was found.
                if (!node_parent1_found)
                {
                    // Select the first node just like that!
                    node_parent1 = non_selected_nodes[0];
                }

                // find a node for parent2 if no legitimate one was found.
                if (!node_parent2_found)
                {
                    // Select the first node just like that!
                    node_parent2 = non_selected_nodes[0];
                }

                // select one of two
                if (node_parent1 == node_parent2)
                {
                    total_weight = total_weight + solver.Problem.Weight(selected_node, node_parent2);

                    selected_node = node_parent1;
                }
                else
                {
                    double weight1 = solver.Problem.Weight(selected_node, node_parent1);
                    double weight2 = solver.Problem.Weight(selected_node, node_parent2);
                    if (weight1 < weight2)
                    {
                        selected_node = node_parent1;

                        total_weight = total_weight + weight1;
                    }
                    else
                    {
                        selected_node = node_parent2;

                        total_weight = total_weight + weight2;
                    }
                }
                total_weight = total_weight + solver.Problem.Weight(selected_node, solver.Problem.Last);

                // update data structures.
                new_individual.Add(selected_node);
                selected_nodes.Add(selected_node);
                non_selected_nodes.Remove(selected_node);

                //if (non_selected_nodes.Count + selected_nodes.Count != parent1.Genomes.Count)
                //{
                //    Console.WriteLine("HELP");
                //}
            }

            Individual individual = new Individual(new_individual);

            //individual.CalculateFitness(total_weight);
            individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);

            //if (individual.Count > parent1.Genomes.Count)
            //{
            //    Console.WriteLine("HELP");
            //}
            return(individual);
        }
        /// <summary>
        /// Returns a solution found using best-placement.
        /// </summary>
        /// <returns></returns>
        protected override IRoute DoSolve(OsmSharp.Math.TSP.Problems.IProblem problem)
        {
            // create the settings.
            SolverSettings settings = new SolverSettings(
                -1,
                -1,
                1000000000,
                -1,
                -1,
                -1);

            Solver <List <int>, GeneticProblem, Fitness> solver =
                new Solver <List <int>, GeneticProblem, Fitness>(
                    new GeneticProblem(problem),
                    settings,
                    null,
                    null,
                    null,
                    _generation_operation,
                    new FitnessCalculator(),
                    true, false);

            Population <List <int>, GeneticProblem, Fitness> population =
                new Population <List <int>, GeneticProblem, Fitness>(true);

            while (population.Count < _population_size)
            {
                // generate new.
                Individual <List <int>, GeneticProblem, Fitness> new_individual =
                    _generation_operation.Generate(solver);

                // add to population.
                population.Add(new_individual);
            }

            // select each individual once.
            Population <List <int>, GeneticProblem, Fitness> new_population =
                new Population <List <int>, GeneticProblem, Fitness>(true);
            Individual <List <int>, GeneticProblem, Fitness> best = null;
            int stagnation = 0;

            while (stagnation < _stagnation)
            {
                while (new_population.Count < _population_size)
                {
                    // select an individual and the next one.
                    int idx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(population.Count);
                    Individual <List <int>, GeneticProblem, Fitness> individual1 = population[idx];
                    Individual <List <int>, GeneticProblem, Fitness> individual2 = null;
                    if (idx == population.Count - 1)
                    {
                        individual2 = population[0];
                    }
                    else
                    {
                        individual2 = population[idx + 1];
                    }
                    population.RemoveAt(idx);

                    Individual <List <int>, GeneticProblem, Fitness> new_individual = _cross_over_operation.CrossOver(solver,
                                                                                                                      individual1, individual2);

                    new_individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
                    if (new_individual.Fitness.CompareTo(
                            individual1.Fitness) < 0)
                    {
                        new_population.Add(new_individual);
                    }
                    else
                    {
                        new_population.Add(individual1);
                    }
                }

                population = new_population;
                population.Sort(solver, solver.FitnessCalculator);

                new_population = new Population <List <int>, GeneticProblem, Fitness>(true);

                if (best == null ||
                    best.Fitness.CompareTo(population[0].Fitness) > 0)
                {
                    stagnation = 0;
                    best       = population[0];
                }
                else
                {
                    stagnation++;
                }

                // report progress.
                OsmSharp.Logging.Log.TraceEvent("EdgeAssemblyCrossOverSolver", Logging.TraceEventType.Information,
                                                string.Format("Solving using EAX: Stagnation {0}.", stagnation));
            }

            var result = new List <int>(best.Genomes);

            result.Insert(0, 0);
            return(DynamicAsymmetricRoute.CreateFrom(result));
        }
        CrossOver(Solver <List <int>, GeneticProblem, Fitness> solver,
                  Individual <List <int>, GeneticProblem, Fitness> parent1,
                  Individual <List <int>, GeneticProblem, Fitness> parent2)
        {
            // take a random piece.
            int idx1 = 0;
            int idx2 = 0;

            while (idx2 - idx1 == 0)
            {
                idx1 = solver.Random.Next(parent1.Genomes.Count - 1) + 1;
                idx2 = solver.Random.Next(parent2.Genomes.Count - 1) + 1;
                if (idx1 > idx2)
                {
                    int temp = idx1;
                    idx1 = idx2;
                    idx2 = temp;
                }
            }

            // if the genome range is big take it from the best individual.
            Individual <List <int>, GeneticProblem, Fitness> source =
                (parent1 as Individual <List <int>, GeneticProblem, Fitness>);
            Individual <List <int>, GeneticProblem, Fitness> target =
                (parent2 as Individual <List <int>, GeneticProblem, Fitness>);

            if (idx2 - idx1 < parent1.Genomes.Count / 2)
            { // the range is small; take the worste genomes.
                if (source.Fitness.CompareTo(target.Fitness) > 0)
                {
                    Individual <List <int>, GeneticProblem, Fitness> temp = source;
                    source = target;
                    target = temp;
                }
                else
                {
                    // do nothing.
                }
            }
            else
            { // the range is big; take the good genomes.
                if (source.Fitness.CompareTo(target.Fitness) > 0)
                {
                    // do nothing.
                }
                else
                {
                    Individual <List <int>, GeneticProblem, Fitness> temp = source;
                    source = target;
                    target = temp;
                }
            }
            List <int> source_piece = source.Genomes.GetRange(idx1, idx2 - idx1);
            List <int> new_genome   = target.Genomes.GetRange(0, target.Genomes.Count);

            // insert the piece into the worst individual.
            // remove nodes in the source_piece.
            foreach (int source_node in source_piece)
            {
                new_genome.Remove(source_node);
            }

            // apply best placement algorithm to place the selected genomes.
            //List<int> genome = new List<int>();
            BestPlacementHelper helper = BestPlacementHelper.Instance();

            helper.DoFast(
                solver.Problem,
                solver.FitnessCalculator as FitnessCalculator,
                new_genome,
                source_piece);

            // return a new individual based on the new genome list.
            Individual individual = new Individual(new_genome);

            individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
            return(individual);
        }
예제 #20
0
        /// <summary>
        /// Applies this operation.
        /// </summary>
        /// <param name="solver"></param>
        /// <param name="parent1"></param>
        /// <param name="parent2"></param>
        /// <returns></returns>
        public Individual <List <int>, GeneticProblem, Fitness> CrossOver(
            Solver <List <int>, GeneticProblem, Fitness> solver,
            Individual <List <int>, GeneticProblem, Fitness> parent1,
            Individual <List <int>, GeneticProblem, Fitness> parent2)
        {
            // take a random piece.
            int idx1 = solver.Random.Next(parent1.Genomes.Count - 1) + 1;
            int idx2 = solver.Random.Next(parent1.Genomes.Count - 1) + 1;

            if (idx1 > idx2)
            {
                int temp = idx1;
                idx1 = idx2;
                idx2 = temp;
            }

            // if the genome range is big take it from the best individual.
            Individual <List <int>, GeneticProblem, Fitness> source =
                (parent1 as Individual <List <int>, GeneticProblem, Fitness>);
            Individual <List <int>, GeneticProblem, Fitness> target =
                (parent2 as Individual <List <int>, GeneticProblem, Fitness>);

            if (idx2 - idx1 < parent1.Genomes.Count / 2)
            { // the range is small; take the worste genomes.
                if (source.Fitness.CompareTo(target.Fitness) > 0)
                {
                    Individual <List <int>, GeneticProblem, Fitness> temp = source;
                    source = target;
                    target = temp;
                }
                else
                {
                    // do nothing.
                }
            }
            else
            { // the range is big; take the good genomes.
                if (source.Fitness.CompareTo(target.Fitness) > 0)
                {
                    // do nothing.
                }
                else
                {
                    Individual <List <int>, GeneticProblem, Fitness> temp = source;
                    source = target;
                    target = temp;
                }
            }
            List <int> source_piece = source.Genomes.GetRange(idx1, idx2 - idx1);
            List <int> new_genome   = target.Genomes.GetRange(0, target.Genomes.Count);

            // insert the piece into the worst individual.
            // remove nodes in the source_piece.
            foreach (int source_node in source_piece)
            {
                new_genome.Remove(source_node);
            }

            // insert the source_piece at index1
            new_genome.InsertRange(idx1, source_piece);

            Individual individual = new Individual(new List <int>(new_genome));

            individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
            return(individual);
        }
예제 #21
0
        /// <summary>
        /// Applies this crossover operation.
        /// </summary>
        /// <param name="solver"></param>
        /// <param name="parent1"></param>
        /// <param name="parent2"></param>
        /// <returns></returns>
        public Individual <List <int>, GeneticProblem, Fitness> CrossOver(
            Solver <List <int>, GeneticProblem, Fitness> solver,
            Individual <List <int>, GeneticProblem, Fitness> parent1,
            Individual <List <int>, GeneticProblem, Fitness> parent2)
        {
            OsmSharp.Math.TSP.Problems.IProblem tsp_problem = solver.Problem.BaseProblem;
            double[][] weights = tsp_problem.WeightMatrix;

            // first create E_a
            AsymmetricCycles e_a = new AsymmetricCycles(parent1.Genomes.Count + 1);

            e_a.AddEdge(0, parent1.Genomes[0]);
            for (int idx = 0; idx < parent1.Genomes.Count - 1; idx++)
            {
                int from = parent1.Genomes[idx];
                int to   = parent1.Genomes[idx + 1];

                e_a.AddEdge(from, to);
            }
            e_a.AddEdge(parent1.Genomes[parent1.Genomes.Count - 1], 0);

            // create E_b
            int[] e_b = new int[parent2.Genomes.Count + 1];
            e_b[parent2.Genomes[0]] = 0;
            for (int idx = 0; idx < parent2.Genomes.Count - 1; idx++)
            {
                int from = parent2.Genomes[idx];
                int to   = parent2.Genomes[idx + 1];

                e_b[to] = from;
            }
            e_b[0] = parent2.Genomes[parent2.Genomes.Count - 1];

            // create cycles.
            AsymmetricAlternatingCycles cycles = new AsymmetricAlternatingCycles(
                parent2.Genomes.Count + 1);

            for (int idx = 0; idx < e_b.Length; idx++)
            {
                int a = e_a[idx];
                int b = e_b[a];
                if (idx != b)
                {
                    cycles.AddEdge(idx, a, b);
                }
            }

            // the cycles that can be selected.
            List <int> selectable_cycles = new List <int>(cycles.Cycles.Keys);

            int        generated = 0;
            Individual best      = null;

            while (generated < _max_offspring &&
                   selectable_cycles.Count > 0)
            {
                // select some random cycles.
                List <int> cycle_starts = this.SelectCycles(selectable_cycles);

                // copy if needed.
                AsymmetricCycles a = null;
                if (_max_offspring > 1)
                {
                    a = e_a.Clone();
                }
                else
                {
                    a = e_a;
                }

                // take e_a and remove all edges that are in the selected cycles and replace them by the eges
                int[] next_array_a = a.NextArray;
                foreach (int start in cycle_starts)
                {
                    int current = start;
                    KeyValuePair <int, int> current_next = cycles.Next(current);
                    do
                    {
                        a.AddEdge(current_next.Value, current_next.Key);

                        current      = current_next.Value;
                        current_next = cycles.Next(current);
                    } while(current != start);
                }

                // connect all subtoures.
                int cycle_count = a.Cycles.Count;
                while (cycle_count > 1)
                {
                    // get the smallest tour.
                    KeyValuePair <int, int> current_tour =
                        new KeyValuePair <int, int>(-1, int.MaxValue);
                    foreach (KeyValuePair <int, int> tour in a.Cycles)
                    {
                        if (tour.Value < current_tour.Value)
                        {
                            current_tour = tour;
                        }
                    }

                    // first try nn approach.
                    double weight         = double.MaxValue;
                    int    selected_from1 = -1;
                    int    selected_from2 = -1;
                    int    selected_to1   = -1;
                    int    selected_to2   = -1;

                    bool[] ignore_list = new bool[a.Length];
                    int    from;
                    int    to;
                    from = current_tour.Key;
                    ignore_list[from] = true;
                    //ignore_list.Add(from);
                    to = next_array_a[from];
                    do
                    {
                        // step to the next ones.
                        from = to;
                        to   = next_array_a[from];

                        //ignore_list.Add(from);
                        ignore_list[from] = true;
                    } while (from != current_tour.Key);

                    if (_nn)
                    { // only try tours containing nn.
                        from = current_tour.Key;
                        to   = next_array_a[from];
                        double weight_from_to = weights[from][to];
                        do
                        {
                            // check the nearest neighbours of from
                            foreach (int nn in tsp_problem.Get10NearestNeighbours(from))
                            {
                                int nn_to = next_array_a[nn];

                                //if (!ignore_list.Contains(nn) &&
                                //    !ignore_list.Contains(nn_to))
                                if (!ignore_list[nn] &&
                                    !ignore_list[nn_to])
                                {
                                    double merge_weight =
                                        (weights[from][nn_to] + weights[nn][to]) -
                                        (weight_from_to + weights[nn][nn_to]);
                                    if (weight > merge_weight)
                                    {
                                        weight         = merge_weight;
                                        selected_from1 = from;
                                        selected_from2 = nn;
                                        selected_to1   = to;
                                        selected_to2   = nn_to;
                                    }
                                }
                            }

                            // step to the next ones.
                            from = to;
                            to   = next_array_a[from];
                        } while (from != current_tour.Key);
                    }
                    if (selected_from2 < 0)
                    {
                        // check the nearest neighbours of from
                        foreach (int customer in parent1.Genomes)
                        {
                            int customer_to = next_array_a[customer];

                            //if (!ignore_list.Contains(customer) &&
                            //    !ignore_list.Contains(customer_to))
                            if (!ignore_list[customer] &&
                                !ignore_list[customer_to])
                            {
                                double merge_weight =
                                    (weights[from][customer_to] + weights[customer][to]) -
                                    (weights[from][to] + weights[customer][customer_to]);
                                if (weight > merge_weight)
                                {
                                    weight         = merge_weight;
                                    selected_from1 = from;
                                    selected_from2 = customer;
                                    selected_to1   = to;
                                    selected_to2   = customer_to;
                                }
                            }
                        }
                    }

                    //if (selected_from1 >= 0)
                    //{
                    a.AddEdge(selected_from1, selected_to2);
                    a.AddEdge(selected_from2, selected_to1);
                    //}
                    //else
                    //{
                    //    throw new Exception();
                    //}
                    cycle_count--;
                }

                //if (a.Cycles.Values.First<int>() != a.Length)
                //{
                //    throw new Exception();
                //}
                List <int> new_genome = new List <int>(a.Length);
                int        next       = next_array_a[0];
                do
                {
                    new_genome.Add(next);
                    next = next_array_a[next];
                }while (next != 0);

                Individual individual = new Individual(new_genome);
                individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
                if (best == null ||
                    best.Fitness.CompareTo(individual.Fitness) > 0)
                {
                    best = individual;
                }

                generated++;
            }

            if (best == null)
            {
                List <int> new_genome = new List <int>();
                int        next       = e_a[0];
                do
                {
                    new_genome.Add(next);
                    next = e_a[next];
                }while (next != 0);

                Individual individual = new Individual(new_genome);
                individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
                if (best == null ||
                    best.Fitness.CompareTo(individual.Fitness) > 0)
                {
                    best = individual;
                }
            }
            return(best);
        }
예제 #22
0
        /// <summary>
        /// Places a city into an idividual.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="calculator"></param>
        /// <param name="round_idx"></param>
        /// <param name="individual"></param>
        /// <param name="city_to_place"></param>
        /// <returns></returns>
        internal static BestPlacementResult CalculateBestPlacementInIndividual(
            Problem problem,
            FitnessCalculator calculator,
            int round_idx,
            Individual<List<Genome>, Problem, Fitness> individual,
            int city_to_place)
        {
            // if the target round is empty best placement is impossible.
            Genome round = individual.Genomes[round_idx];

            // do best placement in the genome/round.
            BestPlacementResult result =
                BestPlacementHelper.CalculateBestPlacementInGenome(problem, calculator, round, city_to_place);

            // set the round index.
            result.RoundIdx = round_idx;
            if (!individual.FitnessCalculated)
            {
                individual.CalculateFitness(
                    problem, calculator);
            }
            result.Fitness = calculator.Adjust(
                problem,
                individual.Fitness,
                round_idx,
                result.Increase);

            // return the result.
            return result;
        }
예제 #23
0
        /// <summary>
        /// Applies this operation.
        /// </summary>
        /// <param name="solver"></param>
        /// <param name="parent1"></param>
        /// <param name="parent2"></param>
        /// <returns></returns>
        public Individual <List <int>, GeneticProblem, Fitness> CrossOver(
            Solver <List <int>, GeneticProblem, Fitness> solver,
            Individual <List <int>, GeneticProblem, Fitness> parent1,
            Individual <List <int>, GeneticProblem, Fitness> parent2)
        {
            List <int>    new_individual      = new List <int>();
            HashSet <int> selected_cities     = new HashSet <int>();
            List <int>    non_selected_cities = new List <int>(parent1.Genomes);

            // build the edge list.
            Dictionary <int, HashSet <int> > edges_in_parents = new Dictionary <int, HashSet <int> >();

            for (int idx = 0; idx < parent1.Genomes.Count; idx++)
            {
                int city = parent1.Genomes[idx];

                HashSet <int> city_edges = null;
                if (!edges_in_parents.TryGetValue(city, out city_edges))
                {
                    city_edges = new HashSet <int>();
                    edges_in_parents.Add(city, city_edges);
                }

                int next_idx = idx + 1;
                if (next_idx >= parent1.Genomes.Count)
                {
                    next_idx = 0;
                }
                city_edges.Add(parent1.Genomes[next_idx]);

                city = parent2.Genomes[idx];
                if (!edges_in_parents.TryGetValue(city, out city_edges))
                {
                    city_edges = new HashSet <int>();
                    edges_in_parents.Add(city, city_edges);
                }
                next_idx = idx + 1;
                if (next_idx >= parent2.Genomes.Count)
                {
                    next_idx = 0;
                }
                city_edges.Add(parent2.Genomes[next_idx]);
            }

            // select the initial city.
            int selected_city = parent1.Genomes[0];

            if (edges_in_parents[parent2.Genomes[0]].Count < edges_in_parents[parent1.Genomes[0]].Count)
            {
                selected_city = parent2.Genomes[0];
            }
            new_individual.Add(selected_city);
            selected_cities.Add(selected_city);
            non_selected_cities.Remove(selected_city);

            while (non_selected_cities.Count > 0)
            {
                // select the next city.
                HashSet <int> edges_of_current = edges_in_parents[selected_city];
                edges_in_parents.Remove(selected_city);
                if (edges_of_current.Count > 0)
                {
                    int        edge_count    = parent1.Genomes.Count;
                    List <int> minimum_edges = new List <int>();

                    // build a list of cities with the minimum neighbour count.
                    foreach (int edge_of_current in edges_of_current)
                    {
                        HashSet <int> edges_of_edge = null;
                        if (edges_in_parents.TryGetValue(edge_of_current, out edges_of_edge))
                        {
                            int count = 0;
                            foreach (int edge_of_edge in edges_of_edge)
                            {
                                if (!selected_cities.Contains(edge_of_edge))
                                {
                                    count++;
                                }
                            }

                            if (count < edge_count)
                            {
                                minimum_edges.Clear();
                                minimum_edges.Add(edge_of_current);

                                edge_count = count;
                            }
                            else if (count == edge_count)
                            {
                                minimum_edges.Add(edge_of_current);
                            }
                        }
                    }

                    // randomly select one.
                    if (minimum_edges.Count != 0)
                    {
                        selected_city = minimum_edges[Math.Random.StaticRandomGenerator.Get().Generate(minimum_edges.Count)];
                    }
                    else
                    {
                        selected_city = non_selected_cities[Math.Random.StaticRandomGenerator.Get().Generate(non_selected_cities.Count)];
                    }
                }
                else
                { // randomly select a city.
                    selected_city = non_selected_cities[Math.Random.StaticRandomGenerator.Get().Generate(non_selected_cities.Count)];
                }

                new_individual.Add(selected_city);
                selected_cities.Add(selected_city);
                non_selected_cities.Remove(selected_city);
            }

            Individual individual = new Individual(new_individual);

            individual.CalculateFitness(solver.Problem, solver.FitnessCalculator);
            return(individual);
        }