Beispiel #1
0
        /// <summary>
        /// Returns a solution found using best-placement.
        /// </summary>
        /// <returns></returns>
        protected override IRoute DoSolve(IProblem problem)
        {
            // build the customer list to place.
            List <int> customers = null;

            if (_customers != null)
            { // copy the list of the given customers and keep this order.
                customers = new List <int>(_customers);
            }
            else
            { // generate some random route.
                customers = new List <int>();
                List <int> customers_to_place = new List <int>();
                for (int customer = 0; customer < problem.Size; customer++)
                {
                    customers_to_place.Add(customer);
                }
                while (customers_to_place.Count > 0)
                {
                    int idx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(customers_to_place.Count);
                    customers.Add(customers_to_place[idx]);
                    customers_to_place.RemoveAt(idx);
                }
            }

            // initialize the route based on the problem definition.
            IRoute route  = null;
            double weight = double.MaxValue;

            if (problem.Symmetric)
            {     // create a symmetric route that is dynamic and can accept new customers.
                if (problem.First.HasValue && problem.Last.HasValue && problem.First == problem.Last)
                { // route is a round.
                    route = new DynamicSymmetricRoute(problem.First.Value);
                }
                else
                { // not a round.
                    throw new NotImplementedException("No symmetric routes implemented that are not rounds!");
                }
            }
            else
            {     // create a asymmetric route that is dynamic and can accept new customers.
                if (problem.First.HasValue)
                { // the first customer is set.
                    // test if the last customer is the same.
                    if (!problem.Last.HasValue ||
                        problem.Last == problem.First)
                    { // the route is a round.
                        route = new DynamicAsymmetricRoute(customers.Count, problem.First.Value, true);

                        // remove the first customer.
                        customers.Remove(problem.First.Value);
                    }
                    else
                    { // the route is not a round.
                        route = new DynamicAsymmetricRoute(customers.Count, problem.First.Value, false);
                        route.InsertAfter(problem.First.Value, problem.Last.Value);

                        // remove the first customer.
                        customers.Remove(problem.First.Value);
                        customers.Remove(problem.Last.Value);
                    }
                }
                else
                { // the first and last customer can be choosen randomly.
                    // find two customers close together.
                    int from = -1;
                    int to   = -1;
                    for (int x = 0; x < customers.Count; x++)
                    {
                        for (int y = 0; y < customers.Count; y++)
                        {
                            if (x != y)
                            { // only different customers.
                                double current_weight = problem.WeightMatrix[x][y];
                                if (current_weight < weight)
                                { // the current weight is better.
                                    from   = x;
                                    to     = y;
                                    weight = current_weight;

                                    if (weight == 0)
                                    { // no edge with less weight is going to be found.
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    route = new DynamicAsymmetricRoute(customers.Count, from, false);
                    route.InsertAfter(from, to);

                    // remove the first customer.
                    customers.Remove(from);
                    customers.Remove(to);
                }
            }

            // insert the rest of the customers.
            while (customers.Count > 0 && !_stopped)
            { // keep placing customer 0 until all customers are placed.
                // calculate placement.
                CheapestInsertionResult result =
                    CheapestInsertionHelper.CalculateBestPlacement(problem, route, customers);

                // place the customer.
                if (result.CustomerAfter >= 0 && result.CustomerBefore >= 0)
                {
                    //route.InsertAfterAndRemove(result.CustomerBefore, result.Customer, result.CustomerAfter);
                    route.InsertAfter(result.CustomerBefore, result.Customer);
                    customers.Remove(result.Customer);
                }
            }

            return(route);
        }
Beispiel #2
0
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            MaxTimeCalculator calculator = new MaxTimeCalculator(problem);

            // get the seed customers.
            ICollection <int> seeds = _seed_selector.SelectSeeds(
                problem, _k);

            double[] weights = new double[seeds.Count];

            // start the seed routes.
            List <int>      selectable_customers = problem.Customers;
            MaxTimeSolution routes = new MaxTimeSolution(
                problem.Size, true);

            foreach (int seed in seeds)
            {
                routes.Add(seed);
                selectable_customers.Remove(seed);
            }

            if (!routes.IsValid())
            {
                throw new Exception();
            }

            // keep a list of cheapest insertions.
            IInsertionCosts costs = new BinaryHeapInsertionCosts();

            // keep looping until all customers have been placed.
            while (selectable_customers.Count > 0)
            {
                // try and place into every route.
                CheapestInsertionResult best_result = new CheapestInsertionResult();
                best_result.Increase = float.MaxValue;
                int best_route_idx = -1;

                CheapestInsertionResult best_result_above_max = new CheapestInsertionResult();
                best_result_above_max.Increase = float.MaxValue;
                int best_route_above_max_idx = -1;

                for (int route_idx = 0; route_idx < routes.Count; route_idx++)
                {
                    IRoute current_route = routes.Route(route_idx);

                    // choose the next customer.
                    CheapestInsertionResult result =
                        CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, selectable_customers, costs);
                    if (result.Customer == result.CustomerAfter)
                    {
                        throw new Exception();
                    }
                    // get the current weight
                    double weight = weights[route_idx];
                    if (result.Increase < best_result.Increase)
                    {
                        if (weight + result.Increase + calculator.DeliveryTime < problem.Max.Value)
                        { // route will still be inside bounds.
                            best_result    = result;
                            best_route_idx = route_idx;
                        }
                        else
                        { // route will become above max.
                            if (result.Increase < best_result_above_max.Increase)
                            {
                                best_result_above_max    = result;
                                best_route_above_max_idx = route_idx;
                            }
                        }
                    }
                }

                // do the placement if a placement is found without max violation.
                // else do the placement in the above max route.
                CheapestInsertionResult placement_result = new CheapestInsertionResult();
                placement_result.Increase = double.MaxValue;
                int placement_result_idx = -1;
                if (best_route_idx >= 0)
                { // best placement found.
                    placement_result     = best_result;
                    placement_result_idx = best_route_idx;
                }
                else
                { // best placement found but only above max.
                    placement_result     = best_result_above_max;
                    placement_result_idx = best_route_above_max_idx;
                }

                // do the actual placement.
                weights[placement_result_idx] = calculator.CalculateOneRouteIncrease(
                    weights[placement_result_idx], placement_result.Increase);
                selectable_customers.Remove(placement_result.Customer);
                //routes.Route(placement_result_idx).InsertAfterAndRemove(
                //    placement_result.CustomerBefore, placement_result.Customer, placement_result.CustomerAfter);
                routes.Route(placement_result_idx).InsertAfter(
                    placement_result.CustomerBefore, placement_result.Customer);

                if (!routes.IsValid())
                {
                    throw new Exception();
                }
            }

            return(routes);
        }
        private void FillRoutes(MaxTimeCalculator calculator, MaxTimeSolution route1, MaxTimeSolution solution,
                                MaxTimeProblem problem)
        {
            double[] weights = new double[solution.Count];

            // insert all non-placed customers in the order of the first route.
            HashSet <int> unplaced = new HashSet <int>();

            for (int route_idx = 0; route_idx < route1.Count; route_idx++)
            {
                IRoute route1_route = route1.Route(route_idx);
                foreach (int customer in route1_route)
                {
                    if (!solution.Contains(customer))
                    {
                        unplaced.Add(customer);
                    }
                }
            }

            for (int idx = 0; idx < solution.Count; idx++)
            {
                IRoute route = solution.Route(idx);
                weights[idx] = calculator.CalculateOneRoute(route);
            }

            // insert all non-placed customers in the order of the first route.
            //for (int route_idx = 0; route_idx < route1.Count; route_idx++)
            //{
            //    IRoute route1_route = route1.Route(route_idx);
            //    foreach (int customer in route1_route)
            //    {
            //        if (!solution.Contains(customer))
            //        {
            while (unplaced.Count > 0)
            {
                int customer = unplaced.First <int>();

                // try reinsertion.
                CheapestInsertionResult result = new CheapestInsertionResult();
                result.Increase = double.MaxValue;
                int target_idx = -1;

                CheapestInsertionResult unlimited_result = new CheapestInsertionResult();
                unlimited_result.Increase = double.MaxValue;
                int unlimited_target_idx = -1;
                for (int idx = 0; idx < solution.Count; idx++)
                {
                    IRoute route = solution.Route(idx);

                    CheapestInsertionResult current_result =
                        CheapestInsertionHelper.CalculateBestPlacement(problem.Weights, route, customer);
                    if (current_result.Increase < result.Increase)
                    {
                        if (weights[idx] + current_result.Increase < problem.Max.Value)
                        {
                            target_idx = idx;
                            result     = current_result;

                            if (result.Increase <= 0)
                            {
                                break;
                            }
                        }
                    }
                    if (current_result.Increase < unlimited_result.Increase)
                    {
                        unlimited_target_idx = idx;
                        unlimited_result     = current_result;
                    }
                }

                if (target_idx < 0)
                {
                    result     = unlimited_result;
                    target_idx = unlimited_target_idx;
                }

                // get the target route and insert.
                IRoute target_route = solution.Route(target_idx);
                weights[target_idx] = weights[target_idx] + result.Increase;
                //target_route.InsertAfterAndRemove(result.CustomerBefore, result.Customer, result.CustomerAfter);
                target_route.InsertAfter(result.CustomerBefore, result.Customer);
                unplaced.Remove(result.Customer);

                ////solution.ToString();
                //if (!solution.IsValid())
                //{
                //    throw new Exception();
                //}
            }
            //    }
            //}
        }
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            // create the calculator.
            MaxTimeCalculator calculator = new MaxTimeCalculator(problem);

            // create the solution.
            MaxTimeSolution solution = new MaxTimeSolution(problem.Size, true);

            // keep placing customer until none are left.
            List <int> customers = new List <int>(problem.Customers);

            while (customers.Count > 0)
            {
                // select a customer using some heuristic.
                int customer_idx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(customers.Count);
                int customer     = customers[customer_idx];
                customers.Remove(customer);

                // start a route r.
                double current_route_weight = 0;
                IRoute current_route        = solution.Add(customer);
                //Console.WriteLine("Starting new route with {0}", customer);
                while (customers.Count > 0)
                {
                    // calculate the best placement.
                    CheapestInsertionResult result =
                        CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers);

                    // calculate the new weight.
                    double potential_weight = calculator.CalculateOneRouteIncrease(current_route_weight, result.Increase);
                    // cram as many customers into one route as possible.
                    if (potential_weight < problem.Max.Value)
                    {
                        // insert the customer, it is
                        customers.Remove(result.Customer);
                        //current_route.InsertAfterAndRemove(result.CustomerBefore, result.Customer, result.CustomerAfter);
                        current_route.InsertAfter(result.CustomerBefore, result.Customer);
                        current_route_weight = potential_weight;

                        //// improve if needed.
                        ////if (improvement_probalitity > OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(1))
                        //if (((problem.Size - customers.Count) % _k) == 0)
                        //{ // an improvement is descided.
                        //    current_route_weight = this.ImproveIntraRoute(problem,
                        //        current_route, current_route_weight);
                        //}
                    }
                    else
                    {// ok we are done!
                        //// apply the intra-route heuristics.
                        //for (int route_idx = 0; route_idx < solution.Count - 1; route_idx++)
                        //{ // apply the intra-route heurstic between the new and all existing routes.
                        //    this.ImproveInterRoute(problem, solution.Route(route_idx), current_route);
                        //}

                        //// apply the inter-route heuristics.
                        //for (int route_idx = 0; route_idx < solution.Count; route_idx++)
                        //{ // apply heurstic for each route.
                        //    IRoute route = solution.Route(route_idx);
                        //    this.ImproveIntraRoute(problem, current_route, current_route_weight);
                        //}

                        // break the route.
                        break;
                    }
                }
            }

            return(solution);
        }
Beispiel #5
0
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            // create the solution.
            MaxTimeSolution solution = new MaxTimeSolution(problem.Size, true);

            // keep placing customer until none are left.
            List <int> customers = new List <int>(problem.Customers);

            double max = problem.Max.Value - (problem.Max.Value * _delta_percentage);

            // keep a list of cheapest insertions.
            IInsertionCosts costs      = new BinaryHeapInsertionCosts();
            double          percentage = _threshold_percentage;

            while (customers.Count > 0)
            {
                // try and distribute the remaining customers if there are only a few left.
                if (customers.Count < problem.Size * percentage)
                {
                    bool succes = true;
                    while (succes && customers.Count > 0)
                    {
                        succes = false;
                        CheapestInsertionResult best = new CheapestInsertionResult();
                        best.Increase = float.MaxValue;
                        int best_idx = -1;
                        for (int route_idx = 0; route_idx < solution.Count; route_idx++)
                        {
                            IRoute route = solution.Route(route_idx);
                            CheapestInsertionResult result =
                                CheapestInsertionHelper.CalculateBestPlacement(problem, route, customers);
                            if (best.Increase > result.Increase)
                            {
                                best     = result;
                                best_idx = route_idx;
                            }
                        }

                        IRoute best_route = solution.Route(best_idx);
                        double route_time = problem.Time(best_route);
                        if (route_time + best.Increase < max)
                        { // insert the customer.
                            best_route.InsertAfter(best.CustomerBefore, best.Customer);
                            customers.Remove(best.Customer);

                            this.Improve(problem, solution, max, best_idx);

                            succes = true;
                        }
                    }
                }

                // select a customer using some heuristic.
                if (customers.Count > 0)
                {
                    // select a customer using some heuristic.
                    int customer = -1;
                    if (_use_seed)
                    { // use a seeding heuristic.
                        customer = this.SelectSeed(problem, problem.MaxTimeCalculator, solution, customers);
                    }
                    else
                    { // just select a random customer.
                        customer = customers[Math.Random.StaticRandomGenerator.Get().Generate(customers.Count)];
                    }
                    customers.Remove(customer);

                    // start a route r.
                    IRoute current_route = solution.Add(customer);
                    solution[solution.Count - 1] = 0;

                    while (customers.Count > 0)
                    {
                        //OsmSharp.IO.Output.OutputStreamHost.WriteLine("{0}/{1} placed!",
                        //    customers.Count, problem.Size);

                        // calculate the best placement.
                        CheapestInsertionResult result;
                        if (_use_seed_cost)
                        { // use the seed cost; the cost to the seed customer.
                            result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers,
                                                                                    customer, _lambda);

                            // calculate the 'real' increase.
                            result.Increase = (problem.WeightMatrix[result.CustomerBefore][result.Customer] +
                                               problem.WeightMatrix[result.Customer][result.CustomerAfter]) -
                                              problem.WeightMatrix[result.CustomerBefore][result.CustomerAfter];
                        }
                        else
                        { // just use cheapest insertion.
                            result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers, costs);
                        }

                        // calculate the new weight.
                        solution[solution.Count - 1] = problem.Time(solution.Route(solution.Count - 1));
                        double potential_weight = problem.MaxTimeCalculator.CalculateOneRouteIncrease(solution[solution.Count - 1],
                                                                                                      result.Increase);
                        // cram as many customers into one route as possible.
                        if (potential_weight < max)
                        {
                            // insert the customer, it is
                            customers.Remove(result.Customer);
                            current_route.InsertAfter(result.CustomerBefore, result.Customer);

                            // free some memory in the costs list.
                            costs.Remove(result.CustomerBefore, result.CustomerAfter);

                            // update the cost of the route.
                            solution[solution.Count - 1] = potential_weight;

                            // improve if needed.
                            if (((problem.Size - customers.Count) % _k) == 0)
                            { // an improvement is descided.
                                // apply the inter-route improvements.
                                int count_before = solution.Route(solution.Count - 1).Count;

                                solution[solution.Count - 1] = this.ImproveIntraRoute(problem,
                                                                                      current_route, solution[solution.Count - 1]);
                                if (!solution.IsValid())
                                {
                                    throw new Exception();
                                }
                                int count_after = solution.Route(solution.Count - 1).Count;

                                // also to the inter-improvements.
                                current_route = this.Improve(problem, solution, max, solution.Count - 1);
                            }
                        }
                        else
                        {// ok we are done!
                            this.Improve(problem, solution, max, solution.Count - 1);

                            // break the route.
                            break;
                        }
                    }
                }
            }

            // remove empty routes.
            for (int route_idx = solution.Count - 1; route_idx >= 0; route_idx--)
            {
                if (solution.Route(route_idx).IsEmpty)
                {
                    solution.Remove(route_idx);
                }
            }

            return(solution);
        }
        /// <summary>
        /// Tries to relocate customers using the source the same as the CrossExchange but places customers using cheapest insertion.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="solution"></param>
        /// <param name="route1_idx"></param>
        /// <param name="route2_idx"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public bool Improve(MaxTimeProblem problem, MaxTimeSolution solution,
                            int route1_idx, int route2_idx, double max)
        {
            int max_window = 5;

            IRoute route1 = solution.Route(route1_idx);
            IRoute route2 = solution.Route(route2_idx);

            double total_before = problem.Time(solution.Route(route1_idx)) +
                                  problem.Time(solution.Route(route2_idx));

            int route1_customers = route1.Count;
            int route2_customers = route2.Count;

            double[] route1_cumul = problem.TimeCumul(route1);
            double[] route2_cumul = problem.TimeCumul(route2);

            // build all edge weights.
            List <Edge> route1_edges = new List <Edge>(route1.Edges());
            List <Edge> route2_edges = new List <Edge>(route2.Edges());

            double[] route1_weights = new double[route1_edges.Count];
            for (int idx = 0; idx < route1_edges.Count; idx++)
            {
                Edge edge = route1_edges[idx];
                route1_weights[idx] = problem.WeightMatrix[edge.From][edge.To];
            }
            double[] route2_weights = new double[route2_edges.Count];
            for (int idx = 0; idx < route2_edges.Count; idx++)
            {
                Edge edge = route2_edges[idx];
                route2_weights[idx] = problem.WeightMatrix[edge.From][edge.To];
            }

            List <EdgePair> route2_pairs = new List <EdgePair>();

            for (int i_idx = 0; i_idx < route2_edges.Count - 2; i_idx++)
            {
                Edge   i               = route2_edges[i_idx];
                double i_weight        = route2_weights[i_idx];
                double weight_before_i = route2_cumul[i_idx];

                int k_idx_max = route2_edges.Count;
                if (k_idx_max > i_idx + 2 + max_window)
                {
                    k_idx_max = i_idx + 2 + max_window;
                }
                for (int k_idx = i_idx + 2; k_idx < k_idx_max; k_idx++)
                {
                    Edge   k                    = route2_edges[k_idx];
                    double k_weight             = route2_weights[k_idx];
                    double weight_after_k       = route2_cumul[route2_cumul.Length - 1] - route2_cumul[k_idx + 1];
                    double weight_between_route = route2_cumul[k_idx] - route2_cumul[i_idx + 1];

                    route2_pairs.Add(new EdgePair()
                    {
                        First            = i,
                        FirstWeight      = i_weight,
                        Second           = k,
                        SecondWeight     = k_weight,
                        Between          = new List <int>(route2.Between(i.To, k.From)),
                        WeightTotal      = i_weight + k_weight,
                        WeightAfter      = weight_after_k,
                        WeightBefore     = weight_before_i,
                        WeightBetween    = weight_between_route,
                        CustomersBetween = k_idx - i_idx
                    });
                }
            }

            // try to relocate all and find best pair.
            double   route1_weight = route1_cumul[route1_cumul.Length - 1];
            EdgePair best          = null;
            CheapestInsertionResult best_result = new CheapestInsertionResult();
            double best_extra = double.MaxValue;

            foreach (EdgePair pair2 in route2_pairs)
            {
                // calculate cheapest insertion.
                CheapestInsertionResult result =
                    CheapestInsertionHelper.CalculateBestPlacement(problem, route1,
                                                                   pair2.First.To, pair2.Second.From);

                double extra_route2 = problem.WeightMatrix[pair2.First.From][pair2.Second.To];

                // check if the result has a net-decrease.
                if (result.Increase + extra_route2 < pair2.WeightTotal - 0.01)
                { // there is a net decrease.
                    // calculate the real increase.
                    double new_weight = problem.Time(route1_weight + result.Increase + pair2.WeightBetween, route1_customers +
                                                     pair2.CustomersBetween);

                    // check the max.
                    if (new_weight < max && new_weight < best_extra)
                    { // the route is smaller than max.
                        best_extra  = new_weight;
                        best_result = result;
                        best        = pair2;
                    }
                }
            }

            if (best != null)
            {
                if (route2.Last == best.Second.To)
                {
                    //throw new Exception();
                }
                route2.ReplaceEdgeFrom(best.First.From, best.Second.To);

                int previous = best_result.CustomerBefore;
                foreach (int customer in best.Between)
                {
                    route1.ReplaceEdgeFrom(previous, customer);

                    previous = customer;
                }
                route1.ReplaceEdgeFrom(previous, best_result.CustomerAfter);

                // check validity.
                if (!route2.IsValid())
                {
                    throw new Exception();
                }
                if (!route1.IsValid())
                {
                    throw new Exception();
                }

                if (route1.Count + route2.Count != route1_customers + route2_customers)
                {
                    throw new Exception();
                }

                double total_after = problem.Time(solution.Route(route1_idx)) +
                                     problem.Time(solution.Route(route2_idx));
                if (total_after >= total_before)
                {
                    throw new Exception("this is not an improvement!");
                }

                return(true);
            }
            return(false);
        }
        public Individual <List <Genome>, Problem, Fitness> CrossOver(
            Solver <List <Genome>, Problem, Fitness> solver,
            Individual <List <Genome>, Problem, Fitness> parent1,
            Individual <List <Genome>, Problem, Fitness> parent2)
        {
            Genome route1 = parent1.Genomes[0];
            Genome route2 = parent2.Genomes[0];

            // get the minimum size of both routes.
            int size = route1.Sizes.Length;

            if (route2.Sizes.Length < size)
            {
                size = route2.Sizes.Length;
            }

            // select a random number of routes.
            HashSet <int> selected_first  = new HashSet <int>();
            HashSet <int> selected_second = new HashSet <int>();
            List <IRoute> selected_routes = new List <IRoute>();
            bool          first           = true;

            while (selected_routes.Count < size)
            {
                // select route.
                int selected_route = -1;
                if (first)
                {
                    selected_route = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(route1.Sizes.Length);
                    while (selected_first.Contains(selected_route))
                    {
                        selected_route = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(route1.Sizes.Length);
                    }

                    selected_first.Add(selected_route);
                    selected_routes.Add(route1.Route(selected_route));
                }
                else
                {
                    selected_route = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(route2.Sizes.Length);
                    while (selected_second.Contains(selected_route))
                    {
                        selected_route = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(route2.Sizes.Length);
                    }

                    selected_second.Add(selected_route);
                    selected_routes.Add(route2.Route(selected_route));
                }

                first = !first;
            }

            // generate the new customer genome.
            HashSet <int> selected_customers = new HashSet <int>();
            List <int>    customers          = new List <int>();
            List <int>    sizes = new List <int>();

            foreach (IRoute route in selected_routes)
            {
                int current_size = 0;
                foreach (int customer in route)
                {
                    if (!selected_customers.Contains(customer))
                    {
                        customers.Add(customer);
                        current_size++;
                        selected_customers.Add(customer);
                    }
                }
                sizes.Add(current_size);
            }
            while (sizes.Remove(0))
            {
            }

            Genome genome = new Genome();

            genome.Sizes     = sizes.ToArray();
            genome.Customers = customers.ToArray();

            // insert all non-placed customers in the order of the first route.
            foreach (int customer in route1.Customers)
            {
                if (!selected_customers.Contains(customer))
                {
                    // try reinsertion.
                    CheapestInsertionResult result = new CheapestInsertionResult();
                    result.Increase = float.MaxValue;

                    int target_idx = -1;
                    for (int idx = 0; idx < genome.Sizes.Length; idx++)
                    {
                        IRoute route = genome.Route(idx);

                        if (genome.Sizes[idx] > 0)
                        {
                            CheapestInsertionResult current_result =
                                CheapestInsertionHelper.CalculateBestPlacement(solver.Problem.Weights, route, customer);
                            if (current_result.Increase < result.Increase)
                            {
                                target_idx = idx;
                                result     = current_result;

                                if (result.Increase <= 0)
                                {
                                    break;
                                }
                            }
                        }
                    }

                    // insert the customer.
                    for (int idx = 0; idx < customers.Count; idx++)
                    {
                        if (customers[idx] == result.CustomerBefore)
                        {
                            if (customers.Count - 1 == idx)
                            {
                                customers.Add(customer);
                            }
                            else
                            {
                                customers.Insert(idx + 1, customer);
                            }
                            break;
                        }
                    }

                    // set the mutated.
                    genome.Sizes[target_idx] = genome.Sizes[target_idx] + 1;
                    genome.Customers         = customers.ToArray();
                }
            }

            if (!genome.IsValid())
            {
                throw new Exception();
            }
            List <Genome> genomes = new List <Genome>();

            genomes.Add(genome);
            Individual <List <Genome>, Problem, Fitness> individual = new Individual <List <Genome>, Problem, Fitness>(genomes);

            //individual.Initialize();
            return(individual);
        }
        /// <summary>
        /// Does the mutation.
        /// </summary>
        /// <param name="solver"></param>
        /// <param name="mutating"></param>
        /// <returns></returns>
        public Individual <MaxTimeSolution, MaxTimeProblem, Fitness> Mutate(
            Solver <MaxTimeSolution, MaxTimeProblem, Fitness> solver,
            Individual <MaxTimeSolution, MaxTimeProblem, Fitness> mutating)
        {
            // get the route information.
            MaxTimeSolution multi_route = mutating.Genomes.Clone() as MaxTimeSolution;

            if (multi_route.Count > 1)
            { // TODO: Maybe add some extra code for the the route-count is very low and chances of collisions are big.
                // TODO: investigate what is more expensive, and extra random generation or creating a list and remove items.
                // http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
                // select a route.
                int source_route_idx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(multi_route.Count);
                int target_route_idx = -1;
                do
                {
                    target_route_idx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(multi_route.Count);
                } while (source_route_idx == target_route_idx);
                int source_count = multi_route.Sizes[source_route_idx];
                int target_count = multi_route.Sizes[target_route_idx];
                if (target_count > 0 && source_count > 3)
                {
                    // take a part out of the orginal.
                    int size            = (int)OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(source_count);
                    int source_location = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(source_count);

                    int first = source_location - (size / 2);
                    if (first < 0)
                    {
                        first = 0;
                    }
                    //first = multi_route.StartOf(source_route_idx) + first;
                    int last = source_location + (size / 2);
                    if (last > source_count - 1)
                    {
                        last = source_count - 1;
                    }
                    //last = multi_route.StartOf(source_route_idx) + last;
                    int        idx             = -1;
                    IRoute     source          = multi_route.Route(source_route_idx);
                    List <int> part_of_orginal = new List <int>();
                    foreach (int customer in source)
                    {
                        idx++;
                        if (idx >= first && idx <= last)
                        {
                            part_of_orginal.Add(customer);
                        }
                    }

                    // remove from the source.
                    foreach (int customer in part_of_orginal)
                    {
                        multi_route.RemoveCustomer(customer);
                    }

                    // place it somewhere in the target.
                    if (part_of_orginal.Count > 0)
                    {
                        IRoute target = multi_route.Route(target_route_idx);

                        CheapestInsertionResult route_placement = CheapestInsertionHelper.CalculateBestPlacement(
                            solver.Problem, target, part_of_orginal[0], part_of_orginal[part_of_orginal.Count - 1]);

                        int from = route_placement.CustomerBefore;
                        foreach (int customer in part_of_orginal)
                        {
                            target.InsertAfter(from, customer);
                            //target.InsertAfterAndRemove(from, customer, -1);
                            from = customer;
                        }
                    }
                }
            }

            return(new Individual <MaxTimeSolution, MaxTimeProblem, Fitness>(multi_route));
        }
        /// <summary>
        /// Executes the RAI.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="solver"></param>
        /// <param name="initial_route"></param>
        /// <returns></returns>
        private static IRoute DoSolve(RandomizedArbitraryInsertionSolver solver, IProblem problem, IRoute initial_route)
        {
            // initialize a route using best-placement.
            DynamicAsymmetricRoute route = null;

            if (initial_route == null)
            {
                OsmSharp.Math.TSP.ArbitraryInsertion.ArbitraryInsertionSolver ai_solver =
                    new OsmSharp.Math.TSP.ArbitraryInsertion.ArbitraryInsertionSolver();
                initial_route = ai_solver.Solve(problem);
            }

            // get/create the dynamic route.
            if (initial_route is DynamicAsymmetricRoute)
            { // initial route is already the correct type.
                route = initial_route as DynamicAsymmetricRoute;
            }
            else
            { // convert the initial route to a route of the correct type.
                route = DynamicAsymmetricRoute.CreateFrom(initial_route);
            }

            // do the Arbitrary Insertion.
            double weight = route.CalculateWeight(problem);

            int try_count = 0;

            while (try_count < (route.Count * route.Count))
            { // keep trying for a given number of times.
                int factor = 2;

                // cut out a part.
                int i = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate((route.Count / factor) - 1) + 1;
                int j = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate((route.Count / factor) - 1) + 1;

                while (i == j)
                {
                    j = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate((route.Count / factor) - 1) + 1;
                }

                if (i > j)
                {
                    int k = j;
                    j = i;
                    i = k;
                }

                // cut out the i->j part.
                int length = j - i;
                if (length > 0)
                {
                    // cut and remove.
                    DynamicAsymmetricRoute.CutResult cut_result = route.CutAndRemove(
                        problem, weight, i, length);

                    // calculate the weight that was removed.
                    double                 new_weight = cut_result.Weight;
                    List <int>             cut_part   = cut_result.CutPart;
                    DynamicAsymmetricRoute cut_route  = cut_result.Route;

                    // use best placement to re-insert.
                    int c = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(cut_part.Count);
                    while (cut_part.Count > 0)
                    { // loop until it's empty.
                        int customer = cut_part[c];
                        cut_part.RemoveAt(c);

                        // calculate the best placement.
                        CheapestInsertionResult result = CheapestInsertionHelper.CalculateBestPlacement(
                            problem, cut_route, customer);
                        //cut_route.InsertAfterAndRemove(result.CustomerBefore, result.Customer, result.CustomerAfter);
                        cut_route.InsertAfter(result.CustomerBefore, result.Customer);
                        new_weight = new_weight + result.Increase;

                        // choose next random customer.
                        c = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(cut_part.Count);
                    }

                    // descide to keep new route or not.
                    if (weight > new_weight)
                    {
                        route  = cut_route;
                        weight = new_weight;

                        //if (this.CanRaiseIntermidiateResult())
                        //{
                        //    this.RaiseIntermidiateResult(route.ToArray<int>(), weight);
                        //}
                    }
                }

                // increase the try count.
                try_count++;
            }

            if (solver != null && solver.CanRaiseIntermidiateResult())
            {
                solver.RaiseIntermidiateResult(route.ToArray <int>());
            }

            return(route);
        }
        /// <summary>
        /// Generates individuals based on a random first customer for each route.
        /// </summary>
        /// <param name="solver"></param>
        /// <returns></returns>
        public Individual <List <Genome>, Problem, Fitness> Generate(
            Solver <List <Genome>, Problem, Fitness> solver)
        {
            Problem problem = solver.Problem;

            DynamicAsymmetricMultiRoute multi_route = new DynamicAsymmetricMultiRoute(problem.Size, true);

            // create the problem for the genetic algorithm.
            List <int> customers = new List <int>();

            for (int customer = problem.Depots.Count; customer < problem.Size; customer++)
            {
                customers.Add(customer);
            }
//            CheapestInsertionHelper helper = new CheapestInsertionHelper();

            List <double> weights = new List <double>();

            for (int i = 0; i < problem.Depots.Count; i++)
            {
                multi_route.Add(i);
                weights.Add(0);
            }
            int k = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(problem.Depots.Count);

            // keep placing customer until none are left.
            while (customers.Count > 0)
            {
                k = (k + 1) % problem.Depots.Count;

                // use best placement to generate a route.
                IRoute current_route = multi_route.Route(k);


                //Console.WriteLine("Starting new route with {0}", customer);
                while (customers.Count > 0)
                {
                    // calculate the best placement.
                    CheapestInsertionResult result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers);

                    if (result.CustomerAfter == -1 || result.CustomerBefore == -1)
                    {
                        customers.Remove(result.Customer);
                        continue;
                    }
                    // calculate the new weight.
                    customers.Remove(result.Customer);
                    //current_route.InsertAfterAndRemove(result.CustomerBefore, result.Customer, result.CustomerAfter);
                    current_route.InsertAfter(result.CustomerBefore, result.Customer);
                    weights[k] += result.Increase + 15 * 60;

                    if (weights[k] == weights.Max())
                    {
                        break;
                    }
                }
            }

            for (int i = 0; i < problem.Depots.Count; i++)
            {
                multi_route.RemoveCustomer(i);
            }


            List <Genome> genomes = new List <Genome>();

            genomes.Add(Genome.CreateFrom(multi_route));
            Individual <List <Genome>, Problem, Fitness> individual = new Individual <List <Genome>, Problem, Fitness>(genomes);

            //individual.Initialize();
            return(individual);
        }