/// <summary>
        /// Places cities into an individual.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="calculator"></param>
        /// <param name="genomes"></param>
        /// <param name="cities_to_place"></param>
        /// <returns></returns>
        public static BestPlacementResult CalculateBestPlacementInGenomes(
            Problem problem,
            FitnessCalculator calculator,
            List <Genome> genomes,
            List <int> cities_to_place)
        {
            // initialize the best placement result.
            BestPlacementResult result = null;

            // place all the cities until there are no more left.
            // try to place every city in every round.
            for (int round_idx = 0; round_idx < genomes.Count; round_idx++)
            {
                Genome genome = genomes[round_idx];
                BestPlacementResult new_result =
                    BestPlacementHelper.CalculateBestPlacementInGenome(
                        problem,
                        calculator,
                        genome,
                        cities_to_place);
                if (result == null ||
                    new_result.Increase < result.Increase)
                {
                    result          = new_result;
                    result.RoundIdx = round_idx;
                }
            }

            // return the result.
            return(result);
        }
        /// <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);
        }
        /// <summary>
        /// Places cities into an individual.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="calculator"></param>
        /// <param name="individual"></param>
        /// <param name="cities_to_place"></param>
        /// <returns></returns>
        internal static BestPlacementResult CalculateBestPlacementInIndividual(
            Problem problem,
            FitnessCalculator calculator,
            Individual <List <Genome>, Problem, Fitness> individual,
            List <int> cities_to_place)
        {
            // initialize the best placement result.
            BestPlacementResult result = null;

            // place all the cities until there are no more left.
            // try to place every city in every round.
            foreach (int city_to_place in cities_to_place)
            {
                for (int round_idx = 0; round_idx < individual.Genomes.Count; round_idx++)
                {
                    BestPlacementResult new_result =
                        BestPlacementHelper.CalculateBestPlacementInIndividual(
                            problem,
                            calculator,
                            round_idx,
                            individual,
                            city_to_place);
                    if (result == null ||
                        new_result.Fitness < result.Fitness)
                    {
                        result = new_result;
                    }
                }
            }

            // return the result.
            return(result);
        }
        public static List <Genome> DoFast(
            Problem problem,
            FitnessCalculator calculator,
            List <Genome> genomes,
            List <int> cities_to_place)
        {
            // initialize the best placement result.
            BestPlacementResult result = null;

            // create the new individual.
            cities_to_place = new List <int>(cities_to_place);
            while (cities_to_place.Count > 0)
            {
                int city_to_place = cities_to_place[cities_to_place.Count - 1];
                cities_to_place.RemoveAt(cities_to_place.Count - 1);

                // calculates the next best position for placement.
                result = BestPlacementHelper.CalculateBestPlacementInGenomes(
                    problem,
                    calculator,
                    genomes,
                    city_to_place);

                // calculate the new individual using the result.
                List <int> round = genomes[result.RoundIdx];
                if (round.Count == result.CityIdx)
                {
                    round.Add(result.City);
                }
                else
                {
                    round.Insert(result.CityIdx, result.City);
                }

                // remove the placed city.
                cities_to_place.Remove(result.City);
            }

            // return the result.
            return(genomes);
        }
        internal static BestPlacementResult CalculateBestPlacementInGenome(
            Problem problem,
            FitnessCalculator calculator,
            Genome genome,
            List <int> cities_to_place)
        {
            // initialize the best placement result.
            BestPlacementResult result
                = new BestPlacementResult();

            result.RoundIdx = -1;

            // try and place all cities.
            for (int city_idx = 0; city_idx < cities_to_place.Count; city_idx++)
            {
                // try to place first city.
                int city = cities_to_place[city_idx];

                // place the city and check the result.
                BestPlacementResult current_result =
                    BestPlacementHelper.CalculateBestPlacementInGenome(
                        problem,
                        calculator,
                        genome,
                        city);

                // check current result
                //if (result.Increase == null ||
                //    current_result.Increase < result.Increase)
                if (current_result.Increase < result.Increase)
                {
                    result = current_result;
                }
            }

            return(result);
        }
        /// <summary>
        /// Calculates the best place to insert a city.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="calculator"></param>
        /// <param name="genome"></param>
        /// <param name="city_to_place"></param>
        /// <returns></returns>
        public static BestPlacementResult CalculateBestPlacementInGenome(
            Problem problem,
            FitnessCalculator calculator,
            Genome genome,
            int city_to_place)
        {
            // initialize the best placement result.
            BestPlacementResult result
                = new BestPlacementResult();
            result.RoundIdx = -1;
            result.City = city_to_place;

            // initialize the best increase.
            double increase = 0;

            if (genome.Count > 0)
            {
                if (genome.Count == 1)
                { // when there is only on city in the round, try placing after and calculate again.
                    // calculate the increase.
                    increase = problem.Weight(genome[0], city_to_place)
                        + (problem.Weight(city_to_place, genome[0]));

                    // set the result city.
                    result.CityIdx = 1;
                }
                else
                { // when there are multiple cities try to place in all position and keep the best.
                    for (int idx = 0; idx < genome.Count - 1; idx++)
                    {
                        // calculate the new weights.
                        double new_weights =
                            problem.Weight(genome[idx], city_to_place)
                                 + (problem.Weight(city_to_place, genome[idx + 1]));

                        // calculate the old weights.
                        double old_weight =
                            problem.Weight(genome[idx], genome[idx + 1]);

                        // calculate the difference to know the increase.
                        double new_increase =
                            new_weights - old_weight;
                        //if (increase == null || new_increase < increase)
                        if (new_increase < increase)
                        {
                            // set the new increase.
                            increase = new_increase;

                            // set the result city.
                            result.CityIdx = 1;
                        }
                    }
                }
            }
            else
            {
                throw new Exception("Cannot do best placement on an empty round!");
            }

            // calculate the fitness.
            result.Increase = increase;

            // return result.
            return result;
        }
        internal static BestPlacementResult CalculateBestPlacementInGenome(
            Problem problem,
            FitnessCalculator calculator,
            Genome genome,
            List<int> cities_to_place)
        {
            // initialize the best placement result.
            BestPlacementResult result
                = new BestPlacementResult();
            result.RoundIdx = -1;

            // try and place all cities.
            for (int city_idx = 0; city_idx < cities_to_place.Count; city_idx++)
            {
                // try to place first city.
                int city = cities_to_place[city_idx];

                // place the city and check the result.
                BestPlacementResult current_result =
                    BestPlacementHelper.CalculateBestPlacementInGenome(
                        problem,
                        calculator,
                        genome,
                        city);

                // check current result
                //if (result.Increase == null ||
                //    current_result.Increase < result.Increase)
                if (current_result.Increase < result.Increase)
                {
                    result = current_result;
                }
            }

            return result;
        }
        /// <summary>
        /// Calculates the best place to insert a city.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="calculator"></param>
        /// <param name="genome"></param>
        /// <param name="city_to_place"></param>
        /// <returns></returns>
        public static BestPlacementResult CalculateBestPlacementInGenome(
            Problem problem,
            FitnessCalculator calculator,
            Genome genome,
            int city_to_place)
        {
            // initialize the best placement result.
            BestPlacementResult result
                = new BestPlacementResult();

            result.RoundIdx = -1;
            result.City     = city_to_place;

            // initialize the best increase.
            double increase = 0;

            if (genome.Count > 0)
            {
                if (genome.Count == 1)
                { // when there is only on city in the round, try placing after and calculate again.
                    // calculate the increase.
                    increase = problem.Weight(genome[0], city_to_place)
                               + (problem.Weight(city_to_place, genome[0]));

                    // set the result city.
                    result.CityIdx = 1;
                }
                else
                { // when there are multiple cities try to place in all position and keep the best.
                    for (int idx = 0; idx < genome.Count - 1; idx++)
                    {
                        // calculate the new weights.
                        double new_weights =
                            problem.Weight(genome[idx], city_to_place)
                            + (problem.Weight(city_to_place, genome[idx + 1]));

                        // calculate the old weights.
                        double old_weight =
                            problem.Weight(genome[idx], genome[idx + 1]);

                        // calculate the difference to know the increase.
                        double new_increase =
                            new_weights - old_weight;
                        //if (increase == null || new_increase < increase)
                        if (new_increase < increase)
                        {
                            // set the new increase.
                            increase = new_increase;

                            // set the result city.
                            result.CityIdx = 1;
                        }
                    }
                }
            }
            else
            {
                throw new Exception("Cannot do best placement on an empty round!");
            }

            // calculate the fitness.
            result.Increase = increase;

            // return result.
            return(result);
        }